初始化项目

This commit is contained in:
Xu Chang 2024-04-21 17:49:59 +08:00
commit 855a0467c2
65 changed files with 1550 additions and 0 deletions

69
.gitignore vendored Normal file
View File

@ -0,0 +1,69 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
# typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.idea/
.vscode
build
package-lock.json
scripts/local
*tsbuildinfo
src/oak-app-domain

212
package.json Normal file
View File

@ -0,0 +1,212 @@
{
"name": "oak_template",
"version": "1.0.0",
"description": "",
"scripts": {
"make:domain": "cross-env COMPLING_AS_LIB=yes oak-cli make:domain",
"make:locale": "oak-cli make:locale -m",
"make:dep": "oak-cli make:dependency",
"clean:cache": "rimraf node_modules/.cache",
"copy-config-json": "copyfiles -u 1 src/config/*.json lib/",
"start:mp": "oak-cli start --target mp --mode development",
"start:mp:prod": "oak-cli start --target mp --mode development --prod",
"build:mp:staging": "oak-cli build --target mp --mode staging",
"build-analyze:mp:staging": "oak-cli build --target mp --mode staging --analyze",
"build:mp": "oak-cli build --target mp --mode production",
"build-analyze:mp": "oak-cli build --target mp --mode production --analyze",
"start:web": "oak-cli start --target web --mode development",
"start:web:prod": "oak-cli start --target web --mode development --prod",
"start:native": "oak-cli start --target rn --mode development",
"start:native:prod": "oak-cli start --target rn --mode development --prod",
"build:web:staging": "oak-cli build --target web --mode staging",
"build-analyze:web:staging": "oak-cli build --target web --mode staging --analyze",
"build:web": "oak-cli build --target web --mode production",
"build-analyze:web": "oak-cli build --target web --mode production --analyze",
"build-sourcemap-analyze:web": "oak-cli build --target web --mode production --sourcemap --analyze",
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && npm run copy-config-json",
"prebuild": "npm run make:locale",
"run:ios": "oak-cli run -p ios",
"run:android": "oak-cli run -p android",
"server:init": "cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node scripts/initServer.js",
"server:start": "cross-env NODE_ENV=development cross-env OAK_PLATFORM=server node scripts/startServer.js",
"postinstall": "npm run make:dep"
},
"keywords": [],
"author": "",
"license": "",
"typings": "typings/index.d.ts",
"dependencies": {
"@ant-design/cssinjs": "^1.16.2",
"@ant-design/icons": "^5.2.6",
"@react-native-async-storage/async-storage": "^1.19.8",
"@react-native-masked-view/masked-view": "^0.3.0",
"@react-navigation/bottom-tabs": "^6.5.11",
"@react-navigation/native": "^6.1.9",
"@react-navigation/stack": "^6.3.20",
"@wangeditor/basic-modules": "^1.1.3",
"@wangeditor/editor": "^5.1.14",
"@wangeditor/editor-for-react": "^1.0.4",
"antd": "^5.8.3",
"antd-mobile": "^5.32.0",
"antd-mobile-icons": "^0.3.0",
"classnames": "^2.3.1",
"crypto-browserify": "^3.12.0",
"crypto-js": "^4.1.1",
"dayjs": "^1.11.5",
"echarts": "^5.3.0",
"echarts-for-react": "^3.0.2",
"history": "^5.3.0",
"hmacsha1": "^1.0.0",
"js-base64": "^3.7.2",
"lodash": "^4.17.21",
"nprogress": "^0.2.0",
"oak-backend-base": "file:../oak-backend-base",
"oak-common-aspect": "file:../oak-common-aspect",
"oak-db": "file:../oak-db",
"oak-domain": "file:../oak-domain",
"oak-external-sdk": "file:../oak-external-sdk",
"oak-frontend-base": "file:../oak-frontend-base",
"oak-memory-tree-store": "file:../oak-memory-tree-store",
"oak-general-business": "file:../oak-general-business",
"react": "^18.2.0",
"react-dom": "^18.1.0",
"react-image-gallery": "^1.2.11",
"react-native": "0.72.7",
"react-native-exception-handler": "^2.10.10",
"react-native-gesture-handler": "^2.14.0",
"react-native-localize": "^3.0.4",
"react-native-quick-base64": "^2.0.7",
"react-native-quick-crypto": "^0.6.1",
"react-native-reanimated": "^3.5.4",
"react-native-safe-area-context": "^4.7.4",
"react-native-screens": "^3.27.0",
"react-native-url-polyfill": "^2.0.0",
"react-responsive": "^9.0.0-beta.10",
"react-router-dom": "^6.4.0",
"react-slick": "^0.29.0",
"rmc-pull-to-refresh": "^1.0.13",
"slick-carousel": "^1.8.1",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/cli": "^7.12.13",
"@babel/core": "^7.12.13",
"@babel/plugin-proposal-class-properties": "^7.12.13",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@babel/preset-env": "^7.12.13",
"@babel/preset-typescript": "^7.12.13",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
"@react-native/metro-config": "^0.72.11",
"@svgr/webpack": "^5.5.0",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@tsconfig/react-native": "^3.0.0",
"@types/assert": "^1.5.6",
"@types/crypto-js": "^4.1.1",
"@types/fs-extra": "^9.0.13",
"@types/isomorphic-fetch": "^0.0.36",
"@types/jest": "^27.5.2",
"@types/lodash": "^4.14.179",
"@types/luxon": "^2.3.2",
"@types/mocha": "^8.2.0",
"@types/node": "^20.10.2",
"@types/nprogress": "^0.2.0",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
"@types/react-image-gallery": "^1.2.0",
"@types/shelljs": "^0.8.11",
"@types/urlsafe-base64": "^1.0.28",
"@types/uuid": "^8.3.0",
"@types/wechat-miniprogram": "^3.4.0",
"@xuchangzju/oak-cli": "file:../oak-cli",
"assert": "^2.0.0",
"babel-jest": "^27.4.2",
"babel-loader": "^8.2.3",
"babel-plugin-named-asset-import": "^0.3.8",
"babel-plugin-module-resolver": "^5.0.0",
"babel-preset-react-app": "^10.0.1",
"bfj": "^7.0.2",
"browserify-zlib": "^0.2.0",
"browserslist": "^4.18.1",
"camelcase": "^6.2.1",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
"chalk": "^4.1.2",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^10.2.4",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"css-loader": "^6.6.0",
"css-minimizer-webpack-plugin": "^3.2.0",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"dotenv-webpack": "^7.1.0",
"ensure-posix-path": "^1.1.1",
"eslint": "^8.3.0",
"eslint-config-react-app": "^7.0.1",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.2.0",
"fs-extra": "^10.0.0",
"globby": "^11.1.0",
"html-webpack-plugin": "^5.5.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^27.4.3",
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"metro-react-native-babel-preset": "0.76.8",
"mini-css-extract-plugin": "^2.5.3",
"miniprogram-api-typings": "^3.4.5",
"mocha": "^8.2.1",
"postcss": "^8.4.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-less": "^6.0.0",
"postcss-loader": "^6.2.1",
"postcss-normalize": "^10.0.1",
"postcss-preset-env": "^7.0.1",
"progress": "^2.0.3",
"progress-bar-webpack-plugin": "^2.1.0",
"prompts": "^2.4.2",
"react-app-polyfill": "^3.0.0",
"react-dev-utils": "^12.0.1",
"react-refresh": "^0.11.0",
"required-path": "^1.0.1",
"resolve": "^1.20.0",
"resolve-url-loader": "^4.0.0",
"sass-loader": "^12.3.0",
"semver": "^7.3.5",
"shelljs": "^0.8.5",
"source-map-loader": "^3.0.0",
"style-loader": "^3.3.1",
"stylelint": "^14.4.0",
"stylelint-config-standard": "^25.0.0",
"stylelint-webpack-plugin": "^3.1.1",
"tailwindcss": "^3.0.2",
"terser-webpack-plugin": "^5.2.5",
"ts-loader": "^9.3.0",
"ts-node": "^10.9.1",
"tsc-alias": "^1.8.2",
"tslib": "^2.4.0",
"typescript": "^5.2.2",
"ui-extract-webpack-plugin": "^1.0.0",
"web-vitals": "^2.1.4",
"webpack": "^5.86.0",
"webpack-dev-server": "^4.15.1",
"webpack-manifest-plugin": "^4.0.2",
"workbox-webpack-plugin": "^6.4.1"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"copyWebpack": []
}

View File

@ -0,0 +1,6 @@
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
import { EntityDict } from '@oak-app-domain';
export type AspectDict = {
test: (params: string, context: BackendRuntimeContext) => Promise<any>;
};

12
src/aspects/index.ts Normal file
View File

@ -0,0 +1,12 @@
import { AspectDict } from './AspectDict';
import { test } from './sample';
const aspectDict = {
test,
} as AspectDict;
export default aspectDict;
export {
AspectDict,
};

6
src/aspects/sample.ts Normal file
View File

@ -0,0 +1,6 @@
import { EntityDict } from '@oak-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
export async function test(params: string, context: BackendRuntimeContext) {
return 'hello world';
}

9
src/checkers/index.ts Normal file
View File

@ -0,0 +1,9 @@
import { EntityDict } from '@oak-app-domain';
import { Checker } from 'oak-domain/lib/types';
import { RuntimeCxt } from '../types/RuntimeCxt';
const checkers = [
] as Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
export default checkers;

33
src/checkers/store.ts Normal file
View File

@ -0,0 +1,33 @@
import { EntityDict } from '@oak-app-domain';
import { Checker } from 'oak-domain/lib/types';
import { RuntimeCxt } from '../types/RuntimeCxt';
import { checkAttributesNotNull } from 'oak-domain/lib/utils/validator';
import { CreateOperationData as CreateStoreData } from '@oak-app-domain/Store/Schema';
export const checkers: Checker<EntityDict, 'store', RuntimeCxt>[] = [
{
type: 'data',
action: 'create',
entity: 'store',
checker: (data, context) => {
if (data instanceof Array) {
data.forEach((ele) => {
checkAttributesNotNull('store', data, [
'coordinate',
'name',
'addrDetail',
'areaId',
]);
});
} else {
checkAttributesNotNull('store', data, [
'coordinate',
'name',
'addrDetail',
'areaId',
]);
}
return 0;
},
},
];

View File

@ -0,0 +1,45 @@
/**
* EntityDict的重新声明
* by Xc 20230807
*/
import { EntityDict } from '@project/oak-app-domain';
import { TableProps, PaginationProps } from 'antd';
import { ReactComponentProps, ColumnProps, RowWithActions, OakExtraActionProps,
OakAbsAttrDef, onActionFnDef, ListButtonProps, OakAbsAttrUpsertDef, ColumnMapType } from 'oak-frontend-base';
import AbsFilterPanel from 'oak-frontend-base/es/components/filterPanel';
import AbsList from 'oak-frontend-base/es/components/list';
import AbsListPro from 'oak-frontend-base/es/components/listPro';
import AbsDetail from 'oak-frontend-base/es/components/detail';
import AbsUpsert from 'oak-frontend-base/es/components/upsert';
const FilterPanel = AbsFilterPanel as <T extends keyof EntityDict>(
...props: Parameters<typeof AbsFilterPanel<EntityDict, T>>
) => React.ReactElement;
const List = AbsList as <T extends keyof EntityDict>(
...props: Parameters<typeof AbsList<EntityDict, T>>
) => React.ReactElement;
const ListPro = AbsListPro as <T extends keyof EntityDict>(
...props: Parameters<typeof AbsListPro<EntityDict, T>>
) => React.ReactElement;
const Detail = AbsDetail as <T extends keyof EntityDict>(
...props: Parameters<typeof AbsDetail<EntityDict, T>>
) => React.ReactElement;
const Upsert = AbsUpsert as <T extends keyof EntityDict>(
...props: Parameters<typeof AbsUpsert<EntityDict, T>>
) => React.ReactElement;
export {
FilterPanel,
List,
ListPro,
Detail,
Upsert,
ReactComponentProps, ColumnProps, RowWithActions, OakExtraActionProps, OakAbsAttrDef, onActionFnDef,
}

9
src/config/connector.ts Normal file
View File

@ -0,0 +1,9 @@
import SimpleConnector from 'oak-domain/lib/utils/SimpleConnector';
import accessConfiguration from '@project/configuration/access';
import { makeException } from '@project/types/Exception';
import { EntityDict } from '@project/oak-app-domain';
import FrontendRuntimeContext from '@project/context/FrontendRuntimeContext';
const connector = new SimpleConnector<EntityDict, FrontendRuntimeContext>(accessConfiguration, makeException);
export default connector;

1
src/config/constants.ts Normal file
View File

@ -0,0 +1 @@
export const DATA_SUBSCRIBER_KEYS = {};

1
src/config/message.ts Normal file
View File

@ -0,0 +1 @@
export const MessageTypes = {};

View File

@ -0,0 +1,2 @@
//小程序使用
@import "oak-frontend-base/es/config/styles/mp/index.less";

View File

@ -0,0 +1,7 @@
// 解决全屏幕机型底部适配问题
.safe-area-inset-bottom() {
padding-bottom: constant(safe-area-inset-bottom) !important;
/* 兼容 iOS < 11.2 */
padding-bottom: env(safe-area-inset-bottom) !important;
/* 兼容 iOS >= 11.2 */
}

View File

@ -0,0 +1 @@
@import 'oak-frontend-base/es/config/styles/web/index.less'; // 少量公共样式

View File

@ -0,0 +1,10 @@
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
const accessConfiguration: AccessConfiguration = {
http: {
hostname: 'localhost',
port: 3001,
},
};
export default accessConfiguration;

View File

@ -0,0 +1,11 @@
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
import devConfiguration from './access.dev';
const accessConfiguration: AccessConfiguration = {
http: {
hostname: 'www.oak-framework.test',
ssl: true,
path: 'oak-api', // 配置在nginx中的映射
},
};
export default process.env.NODE_ENV === 'development' ? devConfiguration : accessConfiguration;

View File

@ -0,0 +1,3 @@
import accessConfiguration from './access.dev';
export default accessConfiguration;
console.log('不应该跑到这里');

View File

@ -0,0 +1,15 @@
import { AttrUpdateMatrix } from 'oak-domain/lib/types/EntityDesc';
import { EntityDict } from '@project/oak-app-domain';
const attrUpdateMatrix: AttrUpdateMatrix<EntityDict> = {
store: {
name: {
filter: {
iState: 'offline',
},
},
},
}
export default attrUpdateMatrix;

View File

@ -0,0 +1,4 @@
import { EntityDict } from '@project/oak-app-domain';
const cacheSavedEntities: (keyof EntityDict)[] = [];
export default cacheSavedEntities;

View File

@ -0,0 +1,3 @@
import { DependencyConfiguration } from 'oak-domain/lib/types/Configuration';
const dependencyConfiguration: DependencyConfiguration = ["oak-general-business"];
export default dependencyConfiguration;

View File

@ -0,0 +1,19 @@
/**
* index中汇总了前端启动需要的引用配置
*/
import attrUpdateMatrix from './attrUpdateMatrix';
import { CommonConfiguration } from 'oak-domain/lib/types/Configuration';
import { actionDefDict } from '@project/oak-app-domain/ActionDefDict';
import { selectFreeEntities, authDeduceRelationMap, updateFreeDict } from './relation';
import cacheSavedEntities from './cache';
import { EntityDict } from '@project/oak-app-domain';
export default {
attrUpdateMatrix,
actionDefDict,
authDeduceRelationMap,
selectFreeEntities,
updateFreeDict,
cacheSavedEntities,
// cacheKeepFreshPeriod: 600 * 1000, // cache默认对缓存对象的刷新间隔时长(在这个间隔内不刷新)
} as CommonConfiguration<EntityDict>;

View File

@ -0,0 +1,19 @@
import { AuthDeduceRelationMap, SelectFreeEntities, UpdateFreeDict } from 'oak-domain/lib/types/Entity';
import { EntityDict } from '@project/oak-app-domain';
// 此对象所标识的entity的权限由其外键指向的父对象判定
export const authDeduceRelationMap: AuthDeduceRelationMap<EntityDict> = {
};
export const selectFreeEntities = [
'payChannel',
];
export const updateFreeDict: UpdateFreeDict<EntityDict> = {
};
export default {
authDeduceRelationMap,
selectFreeEntities,
updateFreeDict,
};

View File

@ -0,0 +1,7 @@
import { RenderConfiguration } from 'oak-domain/lib/types/Configuration';
import { styleDict } from '@project/oak-app-domain/StyleDict';
import { EntityDict } from '@project/oak-app-domain';
export default {
styleDict,
} as RenderConfiguration<EntityDict>;

View File

@ -0,0 +1,13 @@
import { ServerConfiguration } from 'oak-domain/lib/types/Configuration';
import { EntityDict } from '@project/oak-app-domain';
import { BackendRuntimeContext } from '@project/context/BackendRuntimeContext';
import { join } from 'path';
const serverConfiguration: ServerConfiguration<EntityDict, BackendRuntimeContext> = {
database: require('../../configuration/mysql.json'),
workDir: {
path: join(__dirname, '..', '..'),
},
};
export default serverConfiguration;

View File

@ -0,0 +1,12 @@
import { EntityDict } from '@project/oak-app-domain';
import { RuntimeContext } from './RuntimeContext';
import { BackendRuntimeContext as DependentBackendRuntimeContext } from './DependentContext';
export class BackendRuntimeContext extends DependentBackendRuntimeContext<EntityDict> implements RuntimeContext {
async toString() {
const data = await this.getSerializedData();
return JSON.stringify(data);
}
};
export default BackendRuntimeContext;

View File

@ -0,0 +1 @@
export { BackendRuntimeContext, FrontendRuntimeContext } from "oak-general-business";

View File

@ -0,0 +1,17 @@
import { EntityDict } from '@project/oak-app-domain';
import {
FrontendRuntimeContext as DependentFrontendRuntimeContext,
} from './DependentContext';
import { RuntimeContext } from './RuntimeContext';
export class FrontendRuntimeContext
extends DependentFrontendRuntimeContext<EntityDict>
implements RuntimeContext
{
async toString() {
const data = await this.getSerializedData();
return JSON.stringify(data);
}
}
export default FrontendRuntimeContext;

View File

@ -0,0 +1,5 @@
/**
*
*/
export interface RuntimeContext {}

8
src/data/actionAuth.ts Normal file
View File

@ -0,0 +1,8 @@
import { CreateOperationData as ActionAuth } from '@oak-app-domain/ActionAuth/Schema';
const actionAuths: ActionAuth[] = [
];
export default actionAuths;

5
src/data/i18n.ts Normal file
View File

@ -0,0 +1,5 @@
// 本文件为自动编译产生,请勿直接修改
import { CreateOperationData as I18n } from "../oak-app-domain/I18n/Schema";
const i18ns: I18n[] = [];
export default i18ns;

13
src/data/index.ts Normal file
View File

@ -0,0 +1,13 @@
import { relations } from '@project/oak-app-domain/Relation';
import actionAuth from './actionAuth';
import relationAuth from './relationAuth';
import path from './path';
import i18n from './i18n';
export default {
relation: relations,
actionAuth,
relationAuth,
path,
i18n,
};

5
src/data/path.ts Normal file
View File

@ -0,0 +1,5 @@
import { CreateOperationData as Path } from '@oak-app-domain/Path/Schema';
const paths: Path[] = [];
export default paths;

8
src/data/relationAuth.ts Normal file
View File

@ -0,0 +1,8 @@
import { CreateOperationData as RelationAuth } from '@oak-app-domain/RelationAuth/Schema';
const relationAuths: RelationAuth[] = [
]
export default relationAuths;

121
src/entities/Order.ts Normal file
View File

@ -0,0 +1,121 @@
import {
String,
Text,
Price,
Boolean,
Datetime,
} from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { EntityDesc, ActionDef } from 'oak-domain/lib/types';
export interface Schema extends EntityShape {
price: Price;
paid: Price;
refunded: Price;
title: String<32>;
desc: String<64>;
timeoutAt: Datetime;
};
type IAction = 'startPaying' | 'payAll' | 'payPartially' | 'payNone' | 'timeout' | 'cancel' | 'startRefunding' | 'refundAll' | 'refundPartially' | 'refundNone';
type IState = 'paid' | 'unPaid' | 'timeout' | 'cancelled' | 'paying' | 'partiallyPaid' | 'paid' | 'refunding' | 'partiallyRefunded' | 'refunded';
export const IActionDef: ActionDef<IAction, IState> = {
stm: {
startPaying: ['unPaid', 'paying'],
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
payNone: ['paying', 'unPaid'],
timeout: ['unPaid', 'timeout'],
cancel: ['unPaid', 'cancelled'],
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
refundNone: ['refunding', 'paid'],
},
is: 'unPaid',
};
type Action = IAction;
export const entityDesc: EntityDesc<Schema, Action, '', {
iState: IState,
}> = {
indexes: [
//索引
{
name: 'index_iState',
attributes: [
{
name: 'iState',
},
],
},
],
locales: {
zh_CN: {
name: '订单',
attr: {
price: '订单金额',
paid: '已支付金额',
refunded: '已退款金额',
iState: '订单状态',
title: '订单标题',
desc: "订单描述",
timeoutAt: '过期时间'
},
action: {
startPaying: '开始支付',
payAll: '全部支付',
payPartially: '部分支付',
payNone: '支付失败',
timeout: '过期',
cancel: '放弃',
startRefunding: '开始退款',
refundAll: '完全退款',
refundNone: '退款失败',
refundPartially: '部分退款',
},
v: {
iState: {
paid: '已付款',
partiallyPaid: '部分支付',
paying: '支付中',
unPaid: '待付款',
timeout: '已超时',
cancelled: '已取消',
refunded: '已退款',
partiallyRefunded: '已部分退款',
refunding: '退款中',
},
}
},
},
style: {
icon: {
startPaying: '',
payAll: '',
payPartially: '',
payNone: '',
timeout: '',
cancel: '',
startRefunding: '',
refundAll: '',
refundNone: '',
refundPartially: '',
},
color: {
iState: {
unPaid: '#52BE80',
partiallyPaid: '#5DADE2',
cancelled: '#D6DBDF',
paid: '#2E86C1',
paying: '#D2B4DE',
timeout: '#2C3E50',
refunded: '#BA4A00',
partiallyRefunded: '#EDBB99',
refunding: '#FBEEE6'
},
}
}
};

125
src/entities/Pay.ts Normal file
View File

@ -0,0 +1,125 @@
import {
String,
Text,
Price,
Boolean,
Datetime,
} from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { EntityDesc, ActionDef } from 'oak-domain/lib/types';
import { Schema as Order } from './Order';
import { Schema as PayChannel } from './PayChannel';
export interface Schema extends EntityShape {
price: Price;
paid: Price;
refunded: Price;
order: Order;
channel: PayChannel;
timeoutAt: Datetime;
forbidRefundAt?: Datetime;
};
type IAction = 'startPaying' | 'payAll' | 'payPartially' | 'payNone' | 'timeout' | 'cancel' | 'startRefunding' | 'refundAll' | 'refundPartially' | 'refundNone';
type IState = 'paid' | 'unPaid' | 'timeout' | 'cancelled' | 'paying' | 'partiallyPaid' | 'paid' | 'refunding' | 'partiallyRefunded' | 'refunded';
export const IActionDef: ActionDef<IAction, IState> = {
stm: {
startPaying: ['unPaid', 'paying'],
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
payNone: ['paying', 'unPaid'],
timeout: ['unPaid', 'timeout'],
cancel: ['unPaid', 'cancelled'],
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
refundNone: ['refunding', 'paid'],
},
is: 'unPaid',
};
type Action = IAction;
export const entityDesc: EntityDesc<Schema, Action, '', {
iState: IState,
}> = {
indexes: [
//索引
{
name: 'index_iState',
attributes: [
{
name: 'iState',
},
],
},
],
locales: {
zh_CN: {
name: '订单',
attr: {
price: '订单金额',
paid: '已支付金额',
refunded: '已退款金额',
iState: '支付状态',
channel: '支付渠道',
order: '所属订单',
timeoutAt: '过期时间',
forbidRefundAt: '停止退款时间',
},
action: {
startPaying: '开始支付',
payAll: '全部支付',
payPartially: '部分支付',
payNone: '支付失败',
timeout: '过期',
cancel: '放弃',
startRefunding: '开始退款',
refundAll: '完全退款',
refundNone: '退款失败',
refundPartially: '部分退款',
},
v: {
iState: {
paid: '已付款',
partiallyPaid: '部分支付',
paying: '支付中',
unPaid: '待付款',
timeout: '已超时',
cancelled: '已取消',
refunded: '已退款',
partiallyRefunded: '已部分退款',
refunding: '退款中',
},
}
},
},
style: {
icon: {
startPaying: '',
payAll: '',
payPartially: '',
payNone: '',
timeout: '',
cancel: '',
startRefunding: '',
refundAll: '',
refundNone: '',
refundPartially: '',
},
color: {
iState: {
unPaid: '#52BE80',
partiallyPaid: '#5DADE2',
cancelled: '#D6DBDF',
paid: '#2E86C1',
paying: '#D2B4DE',
timeout: '#2C3E50',
refunded: '#BA4A00',
partiallyRefunded: '#EDBB99',
refunding: '#FBEEE6'
},
}
}
};

View File

@ -0,0 +1,41 @@
import {
String,
Text,
Price,
Boolean,
Datetime,
} from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { EntityDesc, ActionDef } from 'oak-domain/lib/types';
export interface Schema extends EntityShape {
name: String<16>;
code: String<16>;
svg: Text;
};
export const entityDesc: EntityDesc<Schema> = {
locales: {
zh_CN: {
name: '支付通道',
attr: {
name: '名称',
code: '代号',
svg: 'svg',
}
},
},
indexes: [
{
name: 'code_uniqe',
attributes: [
{
name: 'code',
}
],
config: {
unique: true,
},
},
],
};

59
src/exceptionHandler.ts Normal file
View File

@ -0,0 +1,59 @@
import {
OakException,
OakUnloggedInException,
OakUserUnpermittedException,
OakAttrNotNullException,
OakInputIllegalException,
} from 'oak-domain/lib/types/Exception';
import {
ExampleException,
} from '@project/types/Exception';
import { FeatureDict } from '@project/features';
import { AFD } from '@project/types/RuntimeCxt';
/**
* backUrl
* @param location
* @param encode
* @returns
*/
export const handler = async (reason: any, features: AFD) => {
if (reason instanceof OakException) {
if (reason instanceof OakUnloggedInException) {
// await features.token.logout();
features.navigator.navigateTo(
{
url: '/login',
},
{ isGoBack: true },
true
);
} else if (reason instanceof OakInputIllegalException) {
features.message.setMessage({
content: reason.message,
type: 'error',
});
} else if (reason instanceof OakAttrNotNullException) {
features.message.setMessage({
content: reason.message,
type: 'error',
});
} else if (reason instanceof ExampleException) {
console.log('在此处理ExampleException');
} else {
console.warn(reason);
features.message.setMessage({
content: reason.message,
type: 'error',
});
}
return true;
}
console.error(reason);
features.message.setMessage({
content: reason.message,
type: 'error',
});
return false;
};

26
src/features/Console.ts Normal file
View File

@ -0,0 +1,26 @@
import { EntityDict } from '@project/oak-app-domain';
import { Feature } from 'oak-frontend-base';
import { Cache } from 'oak-frontend-base/es/features/cache';
type IMode = 'systemProvider' | 'store'; // 控制台的访问模式,一般是业务的顶层结点对象
export default class Console extends Feature {
private cache: Cache<EntityDict>;
constructor(cache: Cache<EntityDict>) {
super();
this.cache = cache;
}
getMode(allowUninitialized?: boolean): IMode {
return 'systemProvider';
}
async initialize() {
}
async destroy() {
}
}

99
src/features/Menu.ts Normal file
View File

@ -0,0 +1,99 @@
import { EntityDict } from '@project/oak-app-domain';
import { Feature } from 'oak-frontend-base';
import { ContextMenuFactory } from 'oak-frontend-base/es/features/contextMenuFactory';
import Console from './Console';
type GroupName = 'System';
type Groups = {
icon: string;
name: GroupName;
}[];
interface IMenu<T extends keyof EntityDict> {
name: string;
icon: string;
url: string;
entity?: T;
paths?: string[];
action?: EntityDict[T]['Action'];
parent?: GroupName;
};
export interface OMenu {
name: GroupName | string;
icon: string;
url?: string;
children?: Array<OMenu>;
};
const groups: Groups = [
{
name: 'System', // 系统级别配置
icon: 'setup_fill',
},
];
const menus: IMenu<keyof EntityDict>[] = [
{
name: 'Dashboard',
icon: 'document',
url: '',
},
{
name: 'relationManage',
icon: 'share',
url: '/relation/entityList',
parent: 'System',
entity: 'relation',
action: 'create',
paths: [],
},
];
export default class Menu extends Feature {
private contextMenuFactory: ContextMenuFactory<EntityDict>;
private console: Console;
private menus?: OMenu[];
constructor(
contextMenuFactory: ContextMenuFactory<EntityDict>,
console: Console
) {
super();
this.contextMenuFactory = contextMenuFactory;
this.contextMenuFactory.setMenus(menus);
this.console = console;
this.console.subscribe(
() => {
this.refreshMenus();
}
);
}
refreshMenus() {
/* const roomId = this.console.getRoomId();
const menus = this.contextMenuFactory.getMenusByContext<IMenu<keyof EntityDict>>('room', roomId);
const menuGroup = groupBy(menus, 'parent');
this.menus = (menus as any[]).filter(ele => !ele.parent).concat(
groups.map((ele) => {
const { name, icon } = ele;
const children = menuGroup[name];
return {
name,
icon,
children,
};
}).filter((ele) => !!ele.children)
);
this.publish(); */
}
getMenus() {
if (!this.menus) {
this.refreshMenus();
}
return this.menus;
}
}

26
src/features/Sample.ts Normal file
View File

@ -0,0 +1,26 @@
import { EntityDict } from '@oak-app-domain';
import { BasicFeatures, Feature } from 'oak-frontend-base';
type DoSthAcion = {
type: 'doSth';
payload: {
args: string;
};
};
export default class Sample extends Feature {
get(params: any) {
throw new Error('Method not implemented.');
}
action(action: DoSthAcion) {
throw new Error('Method not implemented.');
}
cache: BasicFeatures<EntityDict>['cache'];
constructor(
cache: BasicFeatures<EntityDict>['cache']
) {
super();
this.cache = cache;
}
}

20
src/features/index.ts Normal file
View File

@ -0,0 +1,20 @@
import { EntityDict } from '@project/oak-app-domain';
import { BasicFeatures } from 'oak-frontend-base';
import Sample from './Sample';
import Console from './Console';
import Menu from './Menu';
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business";
export function create(features: BasicFeatures<EntityDict> & Ogb0FeatureDict<EntityDict>) {
const { cache, contextMenuFactory, } = features;
const sample = new Sample(cache);
const console = new Console(cache);
const menu = new Menu(contextMenuFactory, console);
return {
sample,
console,
menu,
};
}
export type FeatureDict = ReturnType<typeof create>;
export async function initialize<ED extends EntityDict>(features: FeatureDict<ED> & BasicFeatures<ED> & Ogb0FeatureDict<ED>) {
}

9
src/hooks/useFeatures.ts Normal file
View File

@ -0,0 +1,9 @@
import { useFeatures as useCommonFeatures } from 'oak-frontend-base/es/platforms/web';
import { AFD } from '@project/types/RuntimeCxt';
// react 独有
// 这里因为开发时要引用src而AFD定义中引用lib所以有编译的warning. by Xc
export default function useFeatures() {
// @ts-ignore
return useCommonFeatures<AFD>()
};

4
src/initialize.ts Normal file
View File

@ -0,0 +1,4 @@
import initialize from './initialize.dev';
export default initialize;
console.log('不应该走到这里');

View File

@ -0,0 +1,49 @@
{
"ptrActivate": "松开刷新",
"ptrDeactivate": "下拉刷新",
"ptrRelease": "正在刷新...",
"ptrFinish": "刷新完成",
"noData": "暂无数据",
"areYouSure": "请确认",
"action": {
"create": "创建",
"update": "更新",
"delete": "删除",
"remove": "删除",
"cancel": "取消",
"grant": "授权",
"revoke": "回收",
"tip": "提示",
"detail": "详情",
"editor": "编辑",
"newAdd": "新增",
"add": "添加",
"commit": "提交",
"save": "保存",
"upload": "上传",
"import": "导入"
},
"confirm": "确定",
"submit": "提交",
"reset": "重置",
"select": "查询",
"expand": "展开",
"shrink": "收起",
"back": "返回",
"$$createAt$$": "创建时间",
"$$updateAt$$": "更新时间",
"$$deleteAt$$": "删除时间",
"$$seq$$": "序号",
"message": "消息",
"more": "更多",
"view": "查看",
"scan": "扫一扫",
"bind": "绑定",
"true": "是",
"false": "否",
"open": "开",
"close": "关",
"enter": "请输入",
"change": "修改",
"finish": "完成"
}

1
src/page.mp.ts Normal file
View File

@ -0,0 +1 @@
export { createComponent } from 'oak-frontend-base/es/page.mp';

1
src/page.native.ts Normal file
View File

@ -0,0 +1 @@
export { createComponent } from 'oak-frontend-base/es/page.native';

2
src/page.ts Normal file
View File

@ -0,0 +1,2 @@
// for 编译
export { createComponent } from 'oak-frontend-base/es/page.web';

1
src/page.web.ts Normal file
View File

@ -0,0 +1 @@
export { createComponent } from 'oak-frontend-base/es/page.web';

15
src/ports/index.ts Normal file
View File

@ -0,0 +1,15 @@
import { Importation, Exportation } from "oak-domain/lib/types/Port";
import { EntityDict } from "@oak-app-domain";
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
export const importations: Importation<
EntityDict,
keyof EntityDict,
any,
BackendRuntimeContext
>[] = [];
export const exportations = [
] as Exportation<EntityDict, keyof EntityDict, any, BackendRuntimeContext>[];

28
src/routines/start.ts Normal file
View File

@ -0,0 +1,28 @@
import { Routine } from 'oak-domain/lib/types/Timer';
import { EntityDict } from '@oak-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
const startRoutines: Array<Routine<EntityDict, keyof EntityDict, BackendRuntimeContext>> = [
{
name: '示例性routine',
entity: 'extraFile',
filter: {
uploadState: 'uploading',
},
projection: {
id: 1,
uploadMeta: 1,
uploadState: 1,
entity: 1,
entityId: 1,
objectId: 1,
},
fn: async (context, data) => {
console.log('示例性routine执行请在src/routine/start.ts中关闭');
return context.opResult;
},
},
];
export default startRoutines;

30
src/timers/index.ts Normal file
View File

@ -0,0 +1,30 @@
import { Timer } from 'oak-domain/lib/types/Timer';
import { EntityDict } from '@oak-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
const timers: Array<Timer<EntityDict, keyof EntityDict, BackendRuntimeContext>> = [
{
name: '示例timer',
cron: '30 * * * * *',
entity: 'extraFile',
filter: {
uploadState: 'uploading',
},
projection: {
id: 1,
uploadMeta: 1,
uploadState: 1,
entity: 1,
entityId: 1,
objectId: 1,
},
fn: async (context, data) => {
console.log(
'这是示例timer程序每30秒执行一次请在src/timer/index中关闭'
);
return context.opResult;
},
},
];
export default timers;

10
src/triggers/index.ts Normal file
View File

@ -0,0 +1,10 @@
import { EntityDict } from '@oak-app-domain';
import { Trigger } from 'oak-domain/lib/types';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
const triggers = [
] as Trigger<EntityDict, keyof EntityDict, BackendRuntimeContext>[];
export default triggers;

View File

@ -0,0 +1,13 @@
import { EntityDict } from '@project/oak-app-domain';
import { SelectOpResult } from 'oak-domain/lib/types/Entity';
import { makeException as makeDomainException } from 'oak-domain/lib/types/Exception';
import { makeException as makeOgb0Exception } from "oak-general-business";
export default function makeException(data: {
name: string;
message?: string;
opRecords: SelectOpResult<EntityDict>;
[A: string]: any;
}) {
const e = makeDomainException<EntityDict>(data) || makeOgb0Exception<EntityDict>(data);
return e;
}

30
src/types/Exception.ts Normal file
View File

@ -0,0 +1,30 @@
import { OakException, OakUserException } from 'oak-domain/lib/types';
import { EntityDict } from '@oak-app-domain';
import makeDepedentException from './DependentExceptions';
export class ExampleException extends OakException<EntityDict> {};
export class ConsoleModeIllegalException extends OakException<EntityDict> {};
export class ConsoleLoadingDataException extends OakException<EntityDict> {};
export class ExistsNewBidException extends OakUserException<EntityDict> {};
export function makeException(msg: string | object) {
const data = typeof msg === 'string' ? JSON.parse(msg) : msg;
const exception = makeDepedentException(data);
if (exception) {
return exception;
}
const { name, message } = data;
switch (name) {
case 'ExampleException': {
return new ExampleException(message);
}
default: {
throw new OakException(`不可解读的exception信息「${msg}`);
}
}
}

12
src/types/RuntimeCxt.ts Normal file
View File

@ -0,0 +1,12 @@
import { AspectDict } from "@project/aspects/AspectDict";
import { FeatureDict } from "@project/features";
import { EntityDict } from "@project/oak-app-domain";
import { BasicFeatures } from "oak-frontend-base";
import { BackendRuntimeContext } from "@project/context/BackendRuntimeContext";
import { FrontendRuntimeContext } from "@project/context/FrontendRuntimeContext";
import { FeatureDict as Ogb0FeatureDict, AspectDict as Ogb0AspectDict } from "oak-general-business";
type BRC = BackendRuntimeContext;
type FRC = FrontendRuntimeContext;
export type RuntimeCxt = FRC | BRC;
export type AAD = AspectDict & Ogb0AspectDict<EntityDict>;
export type AFD = FeatureDict & BasicFeatures<EntityDict> & Ogb0FeatureDict<EntityDict>;

11
src/watchers/index.ts Normal file
View File

@ -0,0 +1,11 @@
import { Watcher } from 'oak-domain/lib/types';
import { EntityDict } from '@oak-app-domain';
import { BackendRuntimeContext } from '../context/BackendRuntimeContext';
const watchers = [] as Watcher<
EntityDict,
keyof EntityDict,
BackendRuntimeContext
>[];
export default watchers;

37
tsconfig.build.json Normal file
View File

@ -0,0 +1,37 @@
{
"extends": "./tsconfig.build.paths.json",
"compilerOptions": {
"jsx": "react-jsx",
"module": "commonjs",
"target": "esnext",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"strict": true,
"importHelpers": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"outDir": "lib", /* Redirect output structure to the directory. */
"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "types": [
// "node",
// "wechat-miniprogram"
// ],
"resolveJsonModule": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"test",
"src/pages/**/*",
"src/components/**/*"
]
}

17
tsconfig.build.paths.json Normal file
View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@project/*": [
"src/*"
],
"@oak-app-domain": [
"src/oak-app-domain/index"
],
"@oak-app-domain/*": [
"src/oak-app-domain/*"
],
},
"typeRoots": ["./typings"]
}
}

44
tsconfig.json Normal file
View File

@ -0,0 +1,44 @@
{
"extends": "./tsconfig.paths.json",
"compilerOptions": {
"jsx": "react-jsx",
"module": "commonjs",
"target": "es5",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"strict": true,
"importHelpers": true,
"lib": [
"dom",
"dom.iterable",
"esnext"
],
//"outDir": "lib", /* Redirect output structure to the directory. */
//"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"types": [
"node",
"wechat-miniprogram"
],
"resolveJsonModule": true
},
"include": [
"./src/**/*.js",
"./src/**/*.ts",
"./src/**/*.tsx",
"./web/src/**/*.ts",
"./web/src/**/*.tsx",
"./wechatMp/src/**/*.js",
"./wechatMp/src/**/*.ts",
"./typings/*.d.ts"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"test",
"scripts",
"lib"
]
}

45
tsconfig.mp.json Normal file
View File

@ -0,0 +1,45 @@
{
"extends": "./tsconfig.paths.json",
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"strict": true,
"downlevelIteration": true,
"importHelpers": true,
"moduleResolution": "Node",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
// "outDir": "lib", /* Redirect output structure to the directory. */
// "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"types": [
"node",
"wechat-miniprogram"
],
"resolveJsonModule": true,
"jsx": "react"
},
"include": [
"./src/**/*.js",
"./src/**/*.ts",
"./wechatMp/src/**/*.js",
"./wechatMp/src/**/*.ts",
"./typings/*.d.ts"
],
"exclude": [
"node_modules",
"scripts",
"test",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.test.tsx",
"./web",
"./native"
]
}

17
tsconfig.paths.json Normal file
View File

@ -0,0 +1,17 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@project/*": [
"src/*"
],
"@oak-app-domain": [
"src/oak-app-domain/index"
],
"@oak-app-domain/*": [
"src/oak-app-domain/*"
],
},
"typeRoots": ["./typings"]
}
}

47
tsconfig.web.json Normal file
View File

@ -0,0 +1,47 @@
{
"extends": "./tsconfig.paths.json",
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"importHelpers": true,
"strict": true,
"moduleResolution": "Node",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
// "outDir": "lib", /* Redirect output structure to the directory. */
// "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"types": [
"node",
"wechat-miniprogram",
"react"
],
"resolveJsonModule": true,
"jsx": "react"
},
"include": [
"./src/**/*.js",
"./src/**/*.ts",
"./src/**/*.tsx",
"./web/src/**/*.js",
"./web/src/**/*.ts",
"./web/src/**/*.tsx",
"./typings/*.d.ts"
],
"exclude": [
"node_modules",
"scripts",
"test",
"**/*.spec.ts",
"**/*.test.ts",
"**/*.test.tsx",
"./wechatMp",
"./native"
]
}

5
typings/index.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/// <reference path="../../templateFiles/polyfill.d.ts" />
declare global {
}

13
typings/polyfill.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
import { MakeOakComponent } from 'oak-frontend-base';
import { EntityDict } from '@oak-app-domain';
import { AspectDict } from '@project/aspects/AspectDict';
import { FeatureDict } from '@project/features';
import { BackendRuntimeContext } from '@project/context/BackendRuntimeContext';
import { FrontendRuntimeContext } from '@project/context/FrontendRuntimeContext';
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business/es/features";
import { AspectDict as Ogb0AspectDict } from "oak-general-business/es/aspects";
declare global {
const OakComponent: MakeOakComponent<EntityDict, BackendRuntimeContext, FrontendRuntimeContext, AspectDict & Ogb0AspectDict<EntityDict>, FeatureDict & Ogb0FeatureDict<EntityDict, BackendRuntimeContext>>;
const features: FeatureDict & Ogb0FeatureDict<EntityDict, BackendRuntimeContext>;
}
export {};

1
typings/react-app-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference path="../node_modules/oak-frontend-base/typings/react.d.ts" />