大量逻辑代码

This commit is contained in:
Xu Chang 2024-04-25 20:07:31 +08:00
parent 9734af84e0
commit 288426babb
1166 changed files with 39785 additions and 508 deletions

4
es/aspects/AspectDict.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
import { BRC } from '../types/RuntimeCxt';
export type AspectDict = {
test: (params: string, context: BRC) => Promise<any>;
};

1
es/aspects/AspectDict.js Normal file
View File

@ -0,0 +1 @@
export {};

4
es/aspects/index.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
import { AspectDict } from './AspectDict';
declare const aspectDict: AspectDict;
export default aspectDict;
export { AspectDict, };

5
es/aspects/index.js Normal file
View File

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

2
es/aspects/sample.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
import { BRC } from '../types/RuntimeCxt';
export declare function test(params: string, context: BRC): Promise<string>;

3
es/aspects/sample.js Normal file
View File

@ -0,0 +1,3 @@
export async function test(params, context) {
return 'hello world';
}

5
es/checkers/account.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { Checker } from 'oak-domain/lib/types/Auth';
import { EntityDict } from '../oak-app-domain';
import { RuntimeCxt } from '../types/RuntimeCxt';
declare const checkers: Checker<EntityDict, 'account', RuntimeCxt>[];
export default checkers;

2
es/checkers/account.js Normal file
View File

@ -0,0 +1,2 @@
const checkers = [];
export default checkers;

5
es/checkers/accountOper.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { Checker } from 'oak-domain/lib/types/Auth';
import { EntityDict } from '../oak-app-domain';
import { RuntimeCxt } from '../types/RuntimeCxt';
declare const checkers: Checker<EntityDict, 'accountOper', RuntimeCxt>[];
export default checkers;

View File

@ -0,0 +1,73 @@
import assert from 'assert';
import { OakInputIllegalException } from 'oak-domain/lib/types';
const checkers = [
{
entity: 'accountOper',
action: 'create',
type: 'row',
filter: {
account: {
ableState: 'enabled',
},
},
errMsg: 'account.update.accountDisabled',
},
{
entity: 'accountOper',
action: 'create',
type: 'data',
checker(data, context) {
assert(!(data instanceof Array));
const { type, totalPlus, availPlus } = data;
if (typeof totalPlus !== 'number') {
throw new OakInputIllegalException('accountOper', ['totalPlus'], 'accountOper中的totalPlus不是数字');
}
if (typeof availPlus !== 'number') {
throw new OakInputIllegalException('accountOper', ['availPlus'], 'accountOper中的availPlus不是数字');
}
switch (type) {
case 'consume': {
if (totalPlus >= 0 || availPlus > 0 || totalPlus > availPlus) {
throw new OakInputIllegalException('accountOper', ['availPlus'], 'accountOper为consume时其totalPlus/availPlus必须为0或负数且totalPlus的绝对值要更大');
}
break;
}
case 'deposit': {
if (totalPlus < 0 || availPlus < 0 || totalPlus !== availPlus) {
throw new OakInputIllegalException('accountOper', ['availPlus'], 'accountOper为deposit时其totalPlus/availPlus必须为正数且相等');
}
break;
}
case 'loan': {
if (totalPlus !== 0 || availPlus >= 0) {
throw new OakInputIllegalException('accountOper', ['availPlus'], 'accountOper为loan时其totalPlus必须为0且availPlus必须为负数');
}
break;
}
case 'repay': {
if (totalPlus !== 0 || availPlus <= 0) {
throw new OakInputIllegalException('accountOper', ['availPlus'], 'accountOper为repay时其totalPlus必须为0且availPlus必须为正数');
}
break;
}
case 'withdraw': {
if (totalPlus >= 0 || availPlus >= 0 || totalPlus !== availPlus) {
throw new OakInputIllegalException('accountOper', ['availPlus'], 'accountOper为withdraw时其totalPlus和availPlus必须为不相等的负数');
}
break;
}
case 'withdrawBack': {
if (totalPlus <= 0 || availPlus <= 0 || totalPlus !== availPlus) {
throw new OakInputIllegalException('accountOper', ['availPlus'], 'accountOper为withdraw时其totalPlus和availPlus必须为不相等的正数');
}
break;
}
default: {
assert(false);
break;
}
}
}
}
];
export default checkers;

5
es/checkers/index.d.ts vendored Normal file
View File

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

5
es/checkers/index.js Normal file
View File

@ -0,0 +1,5 @@
import aoCheckers from './accountOper';
const checkers = [
...aoCheckers,
];
export default checkers;

5
es/checkers/pay.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { Checker } from 'oak-domain/lib/types/Auth';
import { EntityDict } from '../oak-app-domain';
import { RuntimeCxt } from '../types/RuntimeCxt';
declare const checkers: Checker<EntityDict, 'pay', RuntimeCxt>[];
export default checkers;

88
es/checkers/pay.js Normal file
View File

@ -0,0 +1,88 @@
import { OakInputIllegalException } from 'oak-domain/lib/types';
import { PAY_CHANNEL_ACCOUNT_NAME } from '../types/PayConfig';
const checkers = [
{
entity: 'pay',
type: 'logical',
action: 'create',
checker(operation, context) {
const { data } = operation;
data.refunded = 0;
data.paid = 0;
data.applicationId = context.getApplicationId();
},
},
{
entity: 'pay',
type: 'data',
action: 'create',
checker(data) {
const { channel, price, orderId, accountId } = data;
if (price <= 0) {
throw new OakInputIllegalException('pay', ['price'], '支付金额必须大于0');
}
if (!orderId) {
// 充值类订单
if (!accountId) {
throw new OakInputIllegalException('pay', ['accountId'], '充值类支付必须指定accountId');
}
else if (channel === PAY_CHANNEL_ACCOUNT_NAME) {
throw new OakInputIllegalException('pay', ['channel'], '充值类支付不能使用帐户支付');
}
}
else {
if (channel === PAY_CHANNEL_ACCOUNT_NAME) {
if (!accountId) {
throw new OakInputIllegalException('pay', ['accountId'], '使用account支付必须指向accountId');
}
}
}
}
},
{
entity: 'pay',
type: 'logicalData',
action: 'create',
checker(operation, context) {
const { data } = operation;
const { orderId, price } = data;
if (orderId) {
// 所有已经支付和正在支付的pay之和不能超过订单总和
const order = context.select('order', {
data: {
id: 1,
price: 1,
pay$order: {
$entity: 'pay',
data: {
id: 1,
price: 1,
},
filter: {
iState: {
$in: ['paying', 'paid'],
}
}
}
},
filter: {
id: orderId,
}
}, {});
const checkPays = (order) => {
const { price: orderPrice, pay$order: pays } = order;
let pricePaying = 0;
pays.forEach((pay) => pricePaying += pay.price);
if (pricePaying + price > orderPrice) {
throw new OakInputIllegalException('pay', ['price'], 'pay.create.priceOverflow');
}
};
if (order instanceof Promise) {
return order.then(([o]) => checkPays(o));
}
return checkPays(order[0]);
}
}
}
];
export default checkers;

75
es/components/AbstractComponents.d.ts vendored Normal file
View File

@ -0,0 +1,75 @@
/**
* EntityDict的重新声明
* by Xc 20230807
*/
import { EntityDict } from '../oak-app-domain';
import { ReactComponentProps, ColumnProps, RowWithActions, OakExtraActionProps, OakAbsAttrDef, onActionFnDef, ListButtonProps, OakAbsAttrUpsertDef } from 'oak-frontend-base';
declare const FilterPanel: <T extends keyof EntityDict>(props: ReactComponentProps<EntityDict, T, false, {
entity: T;
columns: ColumnProps<EntityDict, T>[];
}>) => React.ReactElement;
declare const List: <T extends keyof EntityDict>(props: ReactComponentProps<EntityDict, T, false, {
entity: T;
extraActions: OakExtraActionProps[] | ((row: RowWithActions<EntityDict, T>) => OakExtraActionProps[]);
onAction: onActionFnDef;
disabledOp: boolean;
attributes: OakAbsAttrDef[];
data: RowWithActions<EntityDict, T>[];
loading: boolean;
tablePagination?: any;
rowSelection?: {
type: "checkbox" | "radio";
selectedRowKeys?: string[] | undefined;
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
type: "multiple" | "none" | "single";
} | undefined) => void;
} | undefined;
hideHeader: boolean;
size?: "small" | "middle" | "large" | undefined;
scroll?: any;
locale?: any;
}>) => React.ReactElement;
declare const ListPro: <T extends keyof EntityDict>(props: {
title?: any;
extraContent?: any;
hideDefaultButtons?: boolean | undefined;
buttonGroup?: ListButtonProps[] | undefined;
onReload?: (() => void) | undefined;
entity: T;
extraActions?: OakExtraActionProps[] | ((row: RowWithActions<EntityDict, T>) => OakExtraActionProps[]) | undefined;
onAction?: onActionFnDef | undefined;
disabledOp?: boolean | undefined;
attributes: OakAbsAttrDef[];
data: RowWithActions<EntityDict, T>[];
loading?: boolean | undefined;
tablePagination?: any;
rowSelection?: {
type: "checkbox" | "radio";
selectedRowKeys?: string[] | undefined;
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
type: "multiple" | "none" | "single";
} | undefined) => void;
} | undefined;
disableSerialNumber?: boolean | undefined;
size?: "small" | "middle" | "large" | undefined;
scroll?: any;
locale?: any;
}) => React.ReactElement;
declare const Detail: <T extends keyof EntityDict>(props: ReactComponentProps<EntityDict, T, false, {
column?: number | Record<Breakpoint, number> | undefined;
entity: T;
attributes: OakAbsAttrDef[];
data: Partial<EntityDict[T]["Schema"]>;
title?: string | undefined;
bordered?: boolean | undefined;
layout?: "vertical" | "horizontal" | undefined;
}>) => React.ReactElement;
declare const Upsert: <T extends keyof EntityDict>(props: ReactComponentProps<EntityDict, T, false, {
helps: Record<string, string>;
entity: T;
attributes: OakAbsAttrUpsertDef<EntityDict, T, string | number>[];
data: EntityDict[T]["Schema"];
layout: "vertical" | "horizontal";
mode: "default" | "card";
}>) => React.ReactElement;
export { FilterPanel, List, ListPro, Detail, Upsert, ReactComponentProps, ColumnProps, RowWithActions, OakExtraActionProps, OakAbsAttrDef, onActionFnDef, };

View File

@ -0,0 +1,15 @@
/**
* 抽象组件在业务层根据EntityDict的重新声明
* by Xc 20230807
*/
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;
const List = AbsList;
const ListPro = AbsListPro;
const Detail = AbsDetail;
const Upsert = AbsUpsert;
export { FilterPanel, List, ListPro, Detail, Upsert, };

View File

@ -0,0 +1,3 @@
/// <reference types="wechat-miniprogram" />
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "system", false, WechatMiniprogram.Component.DataOption>) => React.ReactElement;
export default _default;

View File

@ -0,0 +1,24 @@
export default OakComponent({
entity: 'system',
isList: false,
projection: {
id: 1,
payConfig: 1,
application$system: {
$entity: 'application',
data: {
id: 1,
payConfig: 1,
name: 1,
type: 1,
},
},
},
formData({ data, features }) {
const operation = this.state.oakFullpath && this.features.runningTree.getOperations(this.state.oakFullpath);
return {
operation: operation && operation[0].operation,
system: data,
};
},
});

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,5 @@
{
"system": "系统配置",
"appsBelow": "以下为application",
"mayLossUpdate": "%{name}上的更新可能会丢失,请尽快保存"
}

View File

@ -0,0 +1,18 @@
import React from 'react';
import { RowWithActions, WebComponentProps } from 'oak-frontend-base';
import { EntityDict } from '../../../oak-app-domain';
/**
*
* @param channel [label, value]
*/
export declare function registerSystemPayChannel(channel: [string, string]): void;
/**
*
* @param type
* @param channel [label, value]
*/
export declare function registerApplicationPayChannel(type: EntityDict['application']['OpSchema']['type'], channel: [string, string]): void;
export default function render(props: WebComponentProps<EntityDict, 'system', false, {
system: RowWithActions<EntityDict, 'system'>;
operation?: EntityDict['system']['Update'];
}>): React.JSX.Element | null;

View File

@ -0,0 +1,105 @@
import React, { useState } from 'react';
import { Button, Row, Tabs } from 'antd';
import Styles from './web.pc.module.less';
import PayConfigUpsert from '../upsert';
import { PAY_CHANNEL_WECHAT_JS_NAME, PAY_CHANNEL_WECHAT_H5_NAME, PAY_CHANNEL_WECHAT_MP_NAME, PAY_CHANNEL_WECHAT_NATIVE_NAME } from '../../../types/PayConfig';
import { generateNewId } from 'oak-domain/lib/utils/uuid';
const SystemPayChannels = []; // [label, value]
const ApplicationPayChannels = {};
/**
*
* @param channel [label, value]
*/
export function registerSystemPayChannel(channel) {
SystemPayChannels.push(channel);
}
/**
*
* @param type
* @param channel [label, value]
*/
export function registerApplicationPayChannel(type, channel) {
if (ApplicationPayChannels[type]) {
ApplicationPayChannels[type].push(channel);
}
else {
ApplicationPayChannels[type] = [channel];
}
}
const DefaultApplicationPayChannels = {
web: [PAY_CHANNEL_WECHAT_JS_NAME, PAY_CHANNEL_WECHAT_H5_NAME, PAY_CHANNEL_WECHAT_NATIVE_NAME],
wechatMp: [PAY_CHANNEL_WECHAT_MP_NAME],
wechatPublic: [PAY_CHANNEL_WECHAT_JS_NAME],
};
export default function render(props) {
const { system, oakFullpath, operation, oakDirty } = props.data;
const { t, update, setMessage, execute } = props.methods;
const defaultApplicationPayChannelDict = {
web: DefaultApplicationPayChannels.web.map(ele => [t(`payChannel::${ele}`), ele]),
wechatMp: DefaultApplicationPayChannels.wechatMp.map(ele => [t(`payChannel::${ele}`), ele]),
wechatPublic: DefaultApplicationPayChannels.wechatPublic.map(ele => [t(`payChannel::${ele}`), ele]),
};
const [key, setKey] = useState('');
if (system && oakFullpath) {
const { payConfig, application$system: applications } = system;
return (<div className={Styles.container}>
<Row justify="end" style={{ marginBottom: 12 }}>
<Button type="primary" disabled={!oakDirty} onClick={() => execute()}>
{t('common::action.save')}
</Button>
</Row>
<Tabs tabPosition="left" items={[
{
label: (<div className={Styles.systemLabel}>
{t('system')}
</div>),
key: 'system',
children: (<PayConfigUpsert key="system" config={payConfig} update={(config) => update({ payConfig: config })} channels={SystemPayChannels.concat([[t('payChannel::ACCOUNT'), 'ACCOUNT'], [t('payChannel::OFFLINE'), 'OFFLINE']])} t={t}/>),
},
{
label: (<div className={Styles.padding}>
{t('appsBelow')}
</div>),
disabled: true,
key: 'padding',
},
...applications.map((app) => {
const { type, id, payConfig: appPayConfig } = app;
return {
key: id,
label: (<div>
{app.name}
</div>),
children: (<PayConfigUpsert key={id} config={appPayConfig} update={(config) => update({
application$system: {
id: generateNewId(),
action: 'update',
data: {
payConfig: config,
},
filter: {
id,
}
}
})} channels={(defaultApplicationPayChannelDict[type] || []).concat(ApplicationPayChannels[type] || [])} t={t}/>),
};
})
]} onTabClick={(activeKey) => {
if (key && operation) {
const { application$system } = operation.data;
const { filter } = application$system;
if (filter?.id === key) {
setMessage({
type: 'warning',
content: t('mayLossUpdate', {
name: applications?.find(ele => ele.id === key).name
}),
});
}
}
setKey(activeKey);
}}/>
</div>);
}
return null;
}

View File

@ -0,0 +1,17 @@
.container {
background: var(--oak-bg-color-container);
padding: 8px;
height: 100%;
// .tabLabel {
// writing-mode: vertical-rl;
// letter-spacing: .2rem;
// }
.systemLabel {
font-weight: bolder;
}
.padding {
height: 10px;
font-size: small;
}
}

View File

@ -0,0 +1,7 @@
import { AccountPayConfig } from '../../../../types/PayConfig';
import React from 'react';
export default function Account(props: {
config: AccountPayConfig;
update: (config: AccountPayConfig) => void;
t: (k: string) => string;
}): React.JSX.Element;

View File

@ -0,0 +1,6 @@
import React from 'react';
import { Alert } from 'antd';
export default function Account(props) {
const { t } = props;
return <Alert type='info' message={t('tips')}/>;
}

View File

@ -0,0 +1,3 @@
{
"tips": "无需配置。开启后支持向系统帐户内充值,并使用帐户余额进行抵扣、支付等操作"
}

View File

@ -0,0 +1,15 @@
import React from 'react';
import { PayConfig, ConfigBase } from '../../../types/PayConfig';
type FC<T extends ConfigBase> = React.FC<{
config: T;
update: (config: Omit<T, 'channel'>) => void;
t: (k: string) => string;
}>;
export declare function registerPayConfigComponent<T extends ConfigBase>(channel: string, C: FC<T>): void;
export default function Upsert(props: {
config?: PayConfig | null;
channels: [string, string][];
update: (config: PayConfig) => void;
t: (k: string) => string;
}): React.JSX.Element;
export {};

View File

@ -0,0 +1,86 @@
import React, { useState } from 'react';
import { Button, Alert, Modal, Space, Select, Card } from 'antd';
import { CloseOutlined } from '@ant-design/icons';
import classnames from 'classnames';
import WechatPayConfigUpsert from './wechatPay';
import AccountConfigUpsert from './account';
import OfflineConfigUpsert from './offline';
import assert from 'assert';
import Styles from './web.pc.module.less';
const PayConfigComponentsDict = {
WECHAT_APP: WechatPayConfigUpsert,
WECHAT_H5: WechatPayConfigUpsert,
WECHAT_JS: WechatPayConfigUpsert,
WECHAT_MP: WechatPayConfigUpsert,
WECHAT_NATIVE: WechatPayConfigUpsert,
ACCOUNT: AccountConfigUpsert,
OFFLINE: OfflineConfigUpsert,
};
export function registerPayConfigComponent(channel, C) {
PayConfigComponentsDict[channel] = C;
}
export default function Upsert(props) {
const { config, channels, update, t } = props;
const [open, setOpen] = useState(false);
const AddButton = (<Button onClick={() => setOpen(true)} disabled={open}>
{t('common::action.add')}
</Button>);
let C = (<>
<Alert message={t('tips')} type="warning"/>
<div className={classnames(Styles.empty, Styles.container)}>
{AddButton}
</div>
</>);
const availableChannels = channels.filter((ele) => !config?.find(ele2 => ele2.channel === ele[1]));
if (config && config.length > 0) {
C = (<div className={Styles.container}>
<Space direction="vertical" size={16} style={{ width: '100%' }}>
{config.map((cf, idx) => {
const { channel } = cf;
const C = PayConfigComponentsDict[channel];
assert(C);
return (<Card title={channels.find(ele => ele[1] === channel)[0]} style={{
minWidth: 380,
}} key={idx} extra={<Button icon={<CloseOutlined />} type="text" onClick={() => {
config.splice(idx, 1);
update(config);
}}/>}>
<C config={cf} update={(cf2) => {
config.splice(idx, 1, {
channel,
...cf2,
});
update(config);
}} t={t}/>
</Card>);
})}
</Space>
{availableChannels.length > 0 && <div style={{ marginTop: 24, alignSelf: 'flex-end' }}>
{AddButton}
</div>}
</div>);
}
// 还没有配置config
return (<>
{C}
<Modal open={open} onCancel={() => setOpen(false)} title={t('pickChannel')} onOk={() => { }} footer={null} destroyOnClose={true}>
<Select style={{ width: 240 }} options={availableChannels.map(ele => ({
label: ele[0],
value: ele[1],
}))} onSelect={(value) => {
if (config) {
config.push({
channel: value,
});
update(config);
}
else {
update([{
channel: value,
}]);
}
setOpen(false);
}}/>
</Modal>
</>);
}

View File

@ -0,0 +1,4 @@
{
"tips": "在此创建的支付设置将对所有app有效",
"pickChannel": "选择支付通道"
}

View File

@ -0,0 +1,7 @@
import React from 'react';
import { OfflinePayConfig } from '../../../../types/PayConfig';
export default function Offline(props: {
config: OfflinePayConfig;
update: (config: Omit<OfflinePayConfig, 'channel'>) => void;
t: (k: string) => string;
}): React.JSX.Element;

View File

@ -0,0 +1,64 @@
import React, { useEffect, useRef, useState } from 'react';
import { Alert, Flex, Input, Tag, Form, Switch, theme } from 'antd';
import Styles from './web.pc.module.less';
import { PlusOutlined } from '@ant-design/icons';
const tagInputStyle = {
width: 64,
height: 22,
marginInlineEnd: 8,
verticalAlign: 'top',
};
export default function Offline(props) {
const { config, update, t } = props;
const { options = [], allowUser = false } = config;
const { token } = theme.useToken();
const tagPlusStyle = {
height: 22,
background: token.colorBgContainer,
borderStyle: 'dashed',
};
const [inputVisible, setInputVisible] = useState(false);
const [option, setOption] = useState('');
const inputRef = useRef(null);
useEffect(() => {
if (inputVisible) {
inputRef.current?.focus();
}
}, [inputVisible]);
const handleInputConfirm = () => {
if (option) {
options.push(option);
update({
options
});
}
setOption('');
setInputVisible(false);
};
return (<div className={Styles.container}>
<Alert type='info' message={t('tips')}/>
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 12 }} layout="horizontal" style={{ minWidth: 600 }}>
<Form.Item label={t('options')}>
<Flex gap="4px 0" wrap="wrap" style={{ marginTop: 22 }}>
{options.map((option, idx) => <Tag bordered={false} closable key={idx} onClose={() => {
options.splice(idx, 1);
update({
options,
});
}}>
{option}
</Tag>)}
{inputVisible ? (<Input ref={inputRef} type="text" size="small" style={tagInputStyle} value={option} onChange={({ currentTarget }) => setOption(currentTarget.value)} onBlur={handleInputConfirm} onPressEnter={handleInputConfirm}/>) : (<Tag style={tagPlusStyle} icon={<PlusOutlined />} onClick={() => setInputVisible(true)}>
{t('newOption')}
</Tag>)}
</Flex>
</Form.Item>
<Form.Item label={t('allowUser')}>
<Switch value={allowUser} onChange={(v) => {
config.allowUser = v;
update(config);
}}/>
</Form.Item>
</Form>
</div>);
}

View File

@ -0,0 +1,6 @@
{
"tips": "配置后系统允许手动同步来自系统以外的支付",
"newOption": "添加途径",
"options": "收银途径",
"allowUser": "用户主动发起"
}

View File

@ -0,0 +1,5 @@
.container {
display: flex;
flex-direction: column;
width: 100%;
}

View File

@ -0,0 +1,11 @@
.empty {
min-height: 600px;
}
.container {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}

View File

@ -0,0 +1,7 @@
import { WechatPayConfig } from '../../../../types/PayConfig';
import React from 'react';
export default function WechatPay(props: {
config: WechatPayConfig;
update: (config: Omit<WechatPayConfig, 'channel'>) => void;
t: (k: string) => string;
}): React.JSX.Element;

View File

@ -0,0 +1,25 @@
import React from 'react';
import { Form, Input } from 'antd';
export default function WechatPay(props) {
const { config, update, t } = props;
return (<Form labelCol={{ span: 6 }} wrapperCol={{ span: 12 }} layout="horizontal" style={{ minWidth: 600 }}>
<Form.Item label="mchId">
<Input value={config.mchId} onChange={({ currentTarget }) => {
config.mchId = currentTarget.value;
update(config);
}}/>
</Form.Item>
<Form.Item label={t('label.privateKeyFilePath')}>
<Input value={config.privateKeyFilePath} placeholder={t('placeholder.privateKeyFilePath')} onChange={({ currentTarget }) => {
config.privateKeyFilePath = currentTarget.value;
update(config);
}}/>
</Form.Item>
<Form.Item label={t('label.publicKeyFilePath')}>
<Input value={config.publicKeyFilePath} placeholder={t('placeholder.publicKeyFilePath')} onChange={({ currentTarget }) => {
config.publicKeyFilePath = currentTarget.value;
update(config);
}}/>
</Form.Item>
</Form>);
}

View File

@ -0,0 +1,10 @@
{
"label": {
"privateKeyFilePath": "私钥文件路径",
"publicKeyFilePath": "公钥文件路径"
},
"placeholder": {
"privateKeyFilePath": "服务器上存放微信支付帐户私钥文件的路径,注意访问权限",
"publicKeyFilePath": "服务器上存放微信支付帐户公钥文件的路径,注意访问权限"
}
}

5
es/config/connector.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import SimpleConnector from 'oak-domain/lib/utils/SimpleConnector';
import { EntityDict } from '../oak-app-domain';
import FrontendRuntimeContext from '../context/FrontendRuntimeContext';
declare const connector: SimpleConnector<EntityDict, FrontendRuntimeContext>;
export default connector;

5
es/config/connector.js Normal file
View File

@ -0,0 +1,5 @@
import SimpleConnector from 'oak-domain/lib/utils/SimpleConnector';
import accessConfiguration from '../configuration/access';
import { makeException } from '../types/Exception';
const connector = new SimpleConnector(accessConfiguration, makeException);
export default connector;

1
es/config/constants.d.ts vendored Normal file
View File

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

1
es/config/constants.js Normal file
View File

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

1
es/config/message.d.ts vendored Normal file
View File

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

1
es/config/message.js 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'; // 少量公共样式

2
es/configuration/access.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
import accessConfiguration from './access.dev';
export default accessConfiguration;

3
es/configuration/access.dev.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
declare const accessConfiguration: AccessConfiguration;
export default accessConfiguration;

View File

@ -0,0 +1,7 @@
const accessConfiguration = {
http: {
hostname: 'localhost',
port: 3001,
},
};
export default accessConfiguration;

View File

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

3
es/configuration/access.prod.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
declare const _default: AccessConfiguration;
export default _default;

View File

@ -0,0 +1,9 @@
import devConfiguration from './access.dev';
const 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,4 @@
import { AttrUpdateMatrix } from 'oak-domain/lib/types/EntityDesc';
import { EntityDict } from '../oak-app-domain';
declare const attrUpdateMatrix: AttrUpdateMatrix<EntityDict>;
export default attrUpdateMatrix;

View File

@ -0,0 +1,2 @@
const attrUpdateMatrix = {};
export default attrUpdateMatrix;

3
es/configuration/cache.d.ts vendored Normal file
View File

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

View File

@ -0,0 +1,2 @@
const cacheSavedEntities = [];
export default cacheSavedEntities;

3
es/configuration/dependency.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import { DependencyConfiguration } from 'oak-domain/lib/types/Configuration';
declare const dependencyConfiguration: DependencyConfiguration;
export default dependencyConfiguration;

View File

@ -0,0 +1,2 @@
const dependencyConfiguration = ["oak-general-business"];
export default dependencyConfiguration;

4
es/configuration/index.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
import { CommonConfiguration } from 'oak-domain/lib/types/Configuration';
import { EntityDict } from '../oak-app-domain';
declare const _default: CommonConfiguration<EntityDict>;
export default _default;

16
es/configuration/index.js Normal file
View File

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

11
es/configuration/relation.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
import { AuthDeduceRelationMap, UpdateFreeDict } from 'oak-domain/lib/types/Entity';
import { EntityDict } from '../oak-app-domain';
export declare const authDeduceRelationMap: AuthDeduceRelationMap<EntityDict>;
export declare const selectFreeEntities: string[];
export declare const updateFreeDict: UpdateFreeDict<EntityDict>;
declare const _default: {
authDeduceRelationMap: AuthDeduceRelationMap<EntityDict>;
selectFreeEntities: string[];
updateFreeDict: UpdateFreeDict<EntityDict>;
};
export default _default;

View File

@ -0,0 +1,11 @@
// 此对象所标识的entity的权限由其外键指向的父对象判定
export const authDeduceRelationMap = {};
export const selectFreeEntities = [
'payChannel',
];
export const updateFreeDict = {};
export default {
authDeduceRelationMap,
selectFreeEntities,
updateFreeDict,
};

4
es/configuration/render.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
import { RenderConfiguration } from 'oak-domain/lib/types/Configuration';
import { EntityDict } from '../oak-app-domain';
declare const _default: RenderConfiguration<EntityDict>;
export default _default;

View File

@ -0,0 +1,4 @@
import { styleDict } from '../oak-app-domain/StyleDict';
export default {
styleDict,
};

8
es/context/BackendRuntimeContext.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import { EntityDict } from '../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { RuntimeContext } from './RuntimeContext';
import { BackendRuntimeContext as DependentBackendRuntimeContext } from './DependentContext';
export declare class BackendRuntimeContext<ED extends EntityDict & BaseEntityDict> extends DependentBackendRuntimeContext<ED> implements RuntimeContext {
toString(): Promise<string>;
}
export default BackendRuntimeContext;

View File

@ -0,0 +1,9 @@
import { BackendRuntimeContext as DependentBackendRuntimeContext } from './DependentContext';
export class BackendRuntimeContext extends DependentBackendRuntimeContext {
async toString() {
const data = await this.getSerializedData();
return JSON.stringify(data);
}
}
;
export default BackendRuntimeContext;

1
es/context/DependentContext.d.ts vendored Normal file
View File

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

View File

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

View File

@ -0,0 +1,9 @@
import { EntityDict } from '../oak-app-domain';
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
import { FrontendRuntimeContext as DependentFrontendRuntimeContext, SerializedData } from './DependentContext';
import { RuntimeContext } from './RuntimeContext';
export { SerializedData, };
export declare class FrontendRuntimeContext<ED extends EntityDict & BaseEntityDict> extends DependentFrontendRuntimeContext<ED> implements RuntimeContext {
toString(): Promise<string>;
}
export default FrontendRuntimeContext;

View File

@ -0,0 +1,8 @@
import { FrontendRuntimeContext as DependentFrontendRuntimeContext } from './DependentContext';
export class FrontendRuntimeContext extends DependentFrontendRuntimeContext {
async toString() {
const data = await this.getSerializedData();
return JSON.stringify(data);
}
}
export default FrontendRuntimeContext;

5
es/context/RuntimeContext.d.ts vendored Normal file
View File

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

View File

@ -0,0 +1 @@
export {};

3
es/data/i18n.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
import { CreateOperationData as I18n } from "../oak-app-domain/I18n/Schema";
declare const i18ns: I18n[];
export default i18ns;

139
es/data/i18n.js Normal file
View File

@ -0,0 +1,139 @@
// 本文件为自动编译产生,请勿直接修改
const i18ns = [
{
id: "548c6f23c4d08f495b6eed1b757aceb5",
namespace: "oak-pay-business-c-payConfig-system",
language: "zh-CN",
module: "oak-pay-business",
position: "src/components/payConfig/system",
data: {
"system": "系统配置",
"appsBelow": "以下为application",
"mayLossUpdate": "%{name}上的更新可能会丢失,请尽快保存"
}
},
{
id: "b498c969e467aad958efb0c900eb6d27",
namespace: "oak-pay-business-c-payConfig-upsert-account",
language: "zh-CN",
module: "oak-pay-business",
position: "src/components/payConfig/upsert/account",
data: {
"tips": "无需配置。开启后支持向系统帐户内充值,并使用帐户余额进行抵扣、支付等操作"
}
},
{
id: "13dd1040fa574f095005854ea31fa913",
namespace: "oak-pay-business-c-payConfig-upsert",
language: "zh-CN",
module: "oak-pay-business",
position: "src/components/payConfig/upsert",
data: {
"tips": "在此创建的支付设置将对所有app有效",
"pickChannel": "选择支付通道"
}
},
{
id: "4ceac38d67e35b7e9c76f0d2c1ad1e9a",
namespace: "oak-pay-business-c-payConfig-upsert-offline",
language: "zh-CN",
module: "oak-pay-business",
position: "src/components/payConfig/upsert/offline",
data: {
"tips": "配置后系统允许手动同步来自系统以外的支付",
"newOption": "添加途径",
"options": "收银途径",
"allowUser": "用户主动发起"
}
},
{
id: "6fcb5b3689d3f682af148af94b385ae3",
namespace: "oak-pay-business-c-payConfig-upsert-wechatPay",
language: "zh-CN",
module: "oak-pay-business",
position: "src/components/payConfig/upsert/wechatPay",
data: {
"label": {
"privateKeyFilePath": "私钥文件路径",
"publicKeyFilePath": "公钥文件路径"
},
"placeholder": {
"privateKeyFilePath": "服务器上存放微信支付帐户私钥文件的路径,注意访问权限",
"publicKeyFilePath": "服务器上存放微信支付帐户公钥文件的路径,注意访问权限"
}
}
},
{
id: "2127948cb52e116e3ceccd93db8f319c",
namespace: "oak-pay-business-l-common",
language: "zh-CN",
module: "oak-pay-business",
position: "locales/common",
data: {
"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": "完成"
}
},
{
id: "e8c0a965783373d9117f9447ebbbad8d",
namespace: "oak-pay-business-l-payChannel",
language: "zh-CN",
module: "oak-pay-business",
position: "locales/payChannel",
data: {
"ACCOUNT": "系统内帐户",
"OFFLINE": "系统外支付",
"WECHAT_JS": "微信支付JS",
"WECHAT_MP": "微信小程序",
"WECHAT_NATIVE": "微信Native",
"WECHAT_H5": "微信H5",
"WECHAT_APP": "微信APP"
}
}
];
export default i18ns;

4
es/data/index.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
declare const _default: {
i18n: import("../oak-app-domain/I18n/Schema").CreateOperationData[];
};
export default _default;

4
es/data/index.js Normal file
View File

@ -0,0 +1,4 @@
import i18n from "./i18n";
export default {
i18n,
};

19
es/entities/Account.d.ts vendored Normal file
View File

@ -0,0 +1,19 @@
import { String, Price } from 'oak-domain/lib/types/DataType';
import { AbleAction, AbleState } from 'oak-domain/lib/actions/action';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { EntityDesc, ActionDef } from 'oak-domain/lib/types';
import { Schema as System } from 'oak-general-business/lib/entities/System';
export interface Schema extends EntityShape {
total: Price;
avail: Price;
system: System;
entity: String<32>;
entityId: String<64>;
}
type IAction = 'deposit' | 'withdraw' | 'withdrawBack' | 'consume' | 'loan' | 'repay';
export type Action = AbleAction | IAction;
export declare const AbleActionDef: ActionDef<AbleAction, AbleState>;
export declare const entityDesc: EntityDesc<Schema, Action, '', {
ableState: AbleState;
}>;
export {};

51
es/entities/Account.js Normal file
View File

@ -0,0 +1,51 @@
import { makeAbleActionDef } from 'oak-domain/lib/actions/action';
;
export const AbleActionDef = makeAbleActionDef('enabled');
export const entityDesc = {
locales: {
zh_CN: {
name: '帐户',
attr: {
total: '总余额',
avail: '可用余额',
ableState: '状态',
system: '系统',
entity: '所属对象',
entityId: '所属对象Id',
},
action: {
enable: '启用',
disable: '禁用',
deposit: '充值',
withdraw: '提现',
withdrawBack: '提现退还',
consume: '消费',
loan: '抵押',
repay: '偿还',
},
v: {
ableState: {
enabled: '可用的',
disabled: '禁用的',
}
}
},
},
style: {
icon: {
enable: '',
disable: '',
deposit: '',
withdraw: '',
consume: '',
loan: '',
repay: '',
},
color: {
ableState: {
enabled: '#008000',
disabled: '#A9A9A9'
}
}
}
};

17
es/entities/AccountOper.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import { String, Price } from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { EntityDesc } from 'oak-domain/lib/types';
import { Schema as Account } from './Account';
type Type = 'deposit' | 'withdraw' | 'consume' | 'loan' | 'repay' | 'withdrawBack';
export interface Schema extends EntityShape {
account: Account;
type: Type;
totalPlus: Price;
availPlus: Price;
entity: String<32>;
entityId: String<64>;
}
export declare const entityDesc: EntityDesc<Schema, '', '', {
type: Type;
}>;
export {};

View File

@ -0,0 +1,41 @@
;
export const entityDesc = {
locales: {
zh_CN: {
name: '帐号操作',
attr: {
account: '帐号',
type: '类型',
totalPlus: '余额变化',
availPlus: '可用余额变化',
entity: '关联对象',
entityId: '关联对象Id',
},
v: {
type: {
deposit: '充值',
withdraw: '提现',
consume: '消费',
loan: '抵押',
repay: '偿还',
withdrawBack: '提现失败',
},
},
},
},
style: {
color: {
type: {
deposit: '#3498DB',
withdraw: '#F7DC6F',
withdrawBack: '#F7DC6F',
consume: '#A569BD',
loan: '#CD6155',
repay: '#82E0AA',
}
}
},
configuration: {
actionType: 'appendOnly',
}
};

5
es/entities/Application.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { Schema as Application } from 'oak-general-business/lib/entities/Application';
import { PayConfig } from '../types/PayConfig';
export interface Schema extends Application {
payConfig?: PayConfig;
}

View File

@ -0,0 +1,38 @@
;
const entityDesc = {
locales: {
zh_CN: {
name: '应用',
attr: {
description: '描述',
type: '类型',
system: '系统',
name: '名称',
config: '设置',
style: '样式',
sessions: '会话',
domain: '域名',
payConfig: '支付配置',
},
v: {
type: {
web: '网站',
wechatPublic: '微信公众号',
wechatMp: '微信小程序',
native: 'App',
},
},
},
},
style: {
color: {
type: {
wechatMp: '#32CD32',
web: '#00FF7F',
wechatPublic: '#90EE90',
native: '#008000',
}
}
}
};
export {};

19
es/entities/Order.d.ts vendored Normal file
View File

@ -0,0 +1,19 @@
import { String, Price, 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 declare const IActionDef: ActionDef<IAction, IState>;
type Action = IAction;
export declare const entityDesc: EntityDesc<Schema, Action, '', {
iState: IState;
}>;
export {};

95
es/entities/Order.js Normal file
View File

@ -0,0 +1,95 @@
;
export const IActionDef = {
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',
};
export const entityDesc = {
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'
},
}
}
};

37
es/entities/Pay.d.ts vendored Normal file
View File

@ -0,0 +1,37 @@
import { String, Price, Datetime, Int } 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 Account } from './Account';
import { Schema as AccountOper } from './AccountOper';
import { Schema as Application } from 'oak-general-business/lib/entities/Application';
/**
* payorderId为nullaccountId指向要充值的帐户channel不能是ACCOUNT
* payorderId指向订单accountId指向付款的帐户channel必须是ACCOUNT
*/
export interface Schema extends EntityShape {
price: Price;
paid: Price;
refunded: Price;
channel: String<32>;
timeoutAt: Datetime;
forbidRefundAt?: Datetime;
account?: Account;
order?: Order;
externalId?: String<80>;
meta: Object;
opers: AccountOper[];
application: Application;
phantom1?: String<32>;
phantom2?: String<32>;
phantom3?: Int<4>;
phantom4?: Int<8>;
}
type IAction = 'startPaying' | 'succeedPaying' | 'close' | 'startRefunding' | 'refundAll' | 'refundPartially';
type IState = 'unpaid' | 'paying' | 'paid' | 'closed' | 'refunding' | 'partiallyRefunded' | 'refunded';
export declare const IActionDef: ActionDef<IAction, IState>;
type Action = IAction;
export declare const entityDesc: EntityDesc<Schema, Action, '', {
iState: IState;
}>;
export {};

103
es/entities/Pay.js Normal file
View File

@ -0,0 +1,103 @@
;
export const IActionDef = {
stm: {
startPaying: ['unpaid', 'paying'],
succeedPaying: [['unpaid', 'paying'], 'paid'],
close: [['unpaid', 'paying'], 'closed'],
startRefunding: [['paid', 'partiallyRefunded', 'refunding'], 'refunding'],
refundAll: [['paid', 'refunding', 'partiallyRefunded'], 'refunded'],
refundPartially: [['paid', 'refunding', 'partiallyRefunded'], 'partiallyRefunded'],
},
is: 'unpaid',
};
export const entityDesc = {
indexes: [
//索引
{
name: 'index_iState',
attributes: [
{
name: 'iState',
},
],
},
{
name: 'index_externalId_channel',
attributes: [
{
name: 'externalId',
},
{
name: 'channel',
}
],
config: {
unique: true,
}
},
],
locales: {
zh_CN: {
name: '订单',
attr: {
price: '订单金额',
paid: '已支付金额',
refunded: '已退款金额',
iState: '支付状态',
channel: '支付渠道',
order: '所属订单',
timeoutAt: '过期时间',
forbidRefundAt: '停止退款时间',
account: '充值帐户',
meta: '支付metadata',
externalId: '外部订单Id',
opers: '被关联帐户操作',
application: '关联应用',
phantom1: '索引项一',
phantom2: '索引项二',
phantom3: '索引项三',
phantom4: '索引项四',
},
action: {
startPaying: '开始支付',
succeedPaying: '支付成功',
close: '关闭',
startRefunding: '开始退款',
refundAll: '完全退款',
refundPartially: '部分退款',
},
v: {
iState: {
unpaid: '待付款',
paying: '支付中',
paid: '已付款',
closed: '已关闭',
refunding: '退款中',
refunded: '已退款',
partiallyRefunded: '已部分退款',
},
}
},
},
style: {
icon: {
startPaying: '',
succeedPaying: '',
close: '',
startRefunding: '',
refundAll: '',
refundPartially: '',
},
color: {
iState: {
unpaid: '#48C9B0',
paid: '#3498DB',
paying: '#D6EAF8',
closed: '#5D6D7E',
refunded: '#FAE5D3',
partiallyRefunded: '#F0B27A',
refunding: '#CA6F1E'
},
}
}
};

7
es/entities/System.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
import { EntityDesc } from 'oak-domain/lib/types/EntityDesc';
import { Schema as System } from 'oak-general-business/lib/entities/System';
import { PayConfig } from '../types/PayConfig';
export interface Schema extends System {
payConfig?: PayConfig;
}
export declare const entityDesc: EntityDesc<Schema>;

20
es/entities/System.js Normal file
View File

@ -0,0 +1,20 @@
;
export const entityDesc = {
locales: {
zh_CN: {
name: '系统',
attr: {
name: '名称',
description: '描述',
config: '设置',
platform: '平台',
super: '超级系统',
folder: '代码目录名',
style: '样式',
entity: '关联对象',
entityId: '关联对象id',
payConfig: '支付配置',
},
},
}
};

16
es/entities/User.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
import { ActionDef } from 'oak-domain/lib/types/Action';
import { EntityDesc } from 'oak-domain/lib/types/EntityDesc';
import { Schema as User, IdAction, IdState, UserAction, UserState } from 'oak-general-business/lib/entities/User';
import { Schema as Account } from './Account';
export interface Schema extends User {
accounts: Account[];
}
export type Action = UserAction | IdAction;
export declare const IdActionDef: ActionDef<IdAction, IdState>;
export declare const UserActionDef: ActionDef<UserAction, UserState>;
export declare const entityDesc: EntityDesc<Schema, Action, '', {
userState: UserState;
idState: IdState;
gender: Required<Schema>['gender'];
idCardType: Required<Schema>['idCardType'];
}>;

146
es/entities/User.js Normal file
View File

@ -0,0 +1,146 @@
;
export const IdActionDef = {
stm: {
verify: ['unverified', 'verifying'],
accept: [['unverified', 'verifying'], 'verified'],
reject: [['verifying', 'verified'], 'unverified'],
},
is: 'unverified',
};
export const UserActionDef = {
stm: {
activate: ['shadow', 'normal'],
disable: [['normal', 'shadow'], 'disabled'],
enable: ['disabled', 'normal'],
mergeTo: [['normal', 'shadow'], 'merged'],
mergeFrom: ['normal', 'normal'],
},
};
export const entityDesc = {
locales: {
"zh_CN": {
name: '用户',
attr: {
name: '姓名',
nickname: '昵称',
birth: '生日',
password: '密码',
passwordSha1: 'sha1加密密码',
gender: '性别',
idCardType: '证件类型',
idNumber: '证件号码',
ref: '指向用户',
files: '相关文件',
userState: '用户状态',
idState: '身份验证状态',
codes: '微信分享二维码',
isRoot: '是否超级用户',
addresses: '收货地址',
accounts: '用户帐户',
},
action: {
activate: '激活',
accept: '同意',
verify: '验证',
reject: '拒绝',
enable: '启用',
disable: '禁用',
mergeTo: '合并',
mergeFrom: '使合并',
},
v: {
userState: {
shadow: '未激活',
normal: '正常',
disabled: '禁用',
merged: '已被合并',
},
idState: {
unverified: '未验证',
verifying: '验证中',
verified: '已验证',
},
gender: {
male: '男',
female: '女',
},
idCardType: {
"ID-Card": '身份证',
passport: '护照',
"Mainland-passport": '港澳台通行证',
},
}
}
},
indexes: [
{
name: 'index_birth',
attributes: [
{
name: 'birth',
direction: 'ASC',
},
],
},
{
name: 'index_fulltext',
attributes: [
{
name: 'name',
},
{
name: 'nickname',
}
],
config: {
type: 'fulltext',
parser: 'ngram',
}
},
{
name: 'index_userState_refId',
attributes: [
{
name: 'userState',
},
{
name: 'ref',
}
]
},
],
style: {
icon: {
verify: '',
accept: '',
reject: '',
activate: '',
enable: '',
disable: '',
mergeTo: '',
mergeFrom: '',
},
color: {
userState: {
normal: '#0000FF',
disabled: '#FF0000',
merged: '#9A9A9A',
shadow: '#D3D3D3',
},
idState: {
unverified: '#FF0000',
verified: '#0000FF',
verifying: '#EEE8AA',
},
gender: {
male: '#0000FF',
female: '#EE82EE',
},
idCardType: {
'ID-Card': '#E0FFFF',
'Mainland-passport': '#2E8B57',
'passport': '#2F4F4F',
},
}
}
};

20
es/entities/Withdraw.d.ts vendored Normal file
View File

@ -0,0 +1,20 @@
import { Price } 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 Account } from './Account';
import { Schema as WithdrawChannel } from './WithdrawChannel';
import { Schema as AccountOper } from './AccountOper';
export interface Schema extends EntityShape {
account: Account;
price: Price;
channel: WithdrawChannel;
opers: AccountOper[];
}
type IState = 'withdrawing' | 'successful' | 'failed';
type IAction = 'succeed' | 'fail';
export declare const IActionDef: ActionDef<IAction, IState>;
type Action = IAction;
export declare const entityDesc: EntityDesc<Schema, Action, '', {
iState: IState;
}>;
export {};

46
es/entities/Withdraw.js Normal file
View File

@ -0,0 +1,46 @@
;
export const IActionDef = {
stm: {
succeed: ['withdrawing', 'successful'],
fail: ['withdrawing', 'failed'],
},
is: 'withdrawing',
};
export const entityDesc = {
locales: {
zh_CN: {
name: '提现',
attr: {
account: '帐户',
price: '金额',
channel: '途径',
iState: '状态',
opers: '被关联帐户操作',
},
v: {
iState: {
withdrawing: '提现中',
successful: '成功的',
failed: '失败的',
},
},
action: {
succeed: '成功',
fail: '失败',
},
},
},
style: {
icon: {
succeed: '',
fail: '',
},
color: {
iState: {
withdrawing: '#D2B4DE',
successful: '#2E86C1',
failed: '#D6DBDF',
}
}
}
};

10
es/entities/WithdrawChannel.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
import { String } from 'oak-domain/lib/types/DataType';
import { EntityShape } from 'oak-domain/lib/types/Entity';
import { EntityDesc } from 'oak-domain/lib/types';
export interface Schema extends EntityShape {
name: String<64>;
code: String<64>;
data: Object;
channel: String<32>;
}
export declare const entityDesc: EntityDesc<Schema>;

View File

@ -0,0 +1,27 @@
;
export const entityDesc = {
locales: {
zh_CN: {
name: '提现途径',
attr: {
name: '姓名',
code: '帐号',
data: 'metadata',
channel: '提现通道',
}
},
},
indexes: [
{
name: 'code_uniqe',
attributes: [
{
name: 'code',
}
],
config: {
unique: true,
},
},
],
};

8
es/exceptionHandler.d.ts vendored Normal file
View File

@ -0,0 +1,8 @@
import { AFD } from './types/RuntimeCxt';
/**
* backUrl
* @param location
* @param encode
* @returns
*/
export declare const handler: (reason: any, features: AFD) => Promise<boolean>;

View File

@ -1,47 +1,35 @@
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';
import { OakException, OakUnloggedInException, OakAttrNotNullException, OakInputIllegalException, } from 'oak-domain/lib/types/Exception';
import { ExampleException, } from './types/Exception';
/**
* 构造backUrl
* @param location
* @param encode
* @returns
*/
export const handler = async (reason: any, features: AFD) => {
export const handler = async (reason, features) => {
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.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) {
}
else if (reason instanceof OakAttrNotNullException) {
features.message.setMessage({
content: reason.message,
type: 'error',
});
} else if (reason instanceof ExampleException) {
}
else if (reason instanceof ExampleException) {
console.log('在此处理ExampleException');
} else {
}
else {
console.warn(reason);
features.message.setMessage({
content: reason.message,

12
es/features/Console.d.ts vendored Normal file
View File

@ -0,0 +1,12 @@
import { EntityDict } from '../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;
constructor(cache: Cache<EntityDict>);
getMode(allowUninitialized?: boolean): IMode;
initialize(): Promise<void>;
destroy(): Promise<void>;
}
export {};

15
es/features/Console.js Normal file
View File

@ -0,0 +1,15 @@
import { Feature } from 'oak-frontend-base';
export default class Console extends Feature {
cache;
constructor(cache) {
super();
this.cache = cache;
}
getMode(allowUninitialized) {
return 'systemProvider';
}
async initialize() {
}
async destroy() {
}
}

20
es/features/Menu.d.ts vendored Normal file
View File

@ -0,0 +1,20 @@
import { EntityDict } from '../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';
export interface OMenu {
name: GroupName | string;
icon: string;
url?: string;
children?: Array<OMenu>;
}
export default class Menu extends Feature {
private contextMenuFactory;
private console;
private menus?;
constructor(contextMenuFactory: ContextMenuFactory<EntityDict>, console: Console);
refreshMenus(): void;
getMenus(): OMenu[] | undefined;
}
export {};

View File

@ -1,41 +1,13 @@
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 = [
;
;
const groups = [
{
name: 'System', // 系统级别配置
name: 'System', // 系统级别配置
icon: 'setup_fill',
},
];
const menus: IMenu<keyof EntityDict>[] = [
const menus = [
{
name: 'Dashboard',
icon: 'document',
@ -51,27 +23,19 @@ const menus: IMenu<keyof EntityDict>[] = [
paths: [],
},
];
export default class Menu extends Feature {
private contextMenuFactory: ContextMenuFactory<EntityDict>;
private console: Console;
private menus?: OMenu[];
constructor(
contextMenuFactory: ContextMenuFactory<EntityDict>,
console: Console
) {
contextMenuFactory;
console;
menus;
constructor(contextMenuFactory, console) {
super();
this.contextMenuFactory = contextMenuFactory;
this.contextMenuFactory.setMenus(menus);
this.console = console;
this.console.subscribe(
() => {
this.refreshMenus();
}
);
this.console.subscribe(() => {
this.refreshMenus();
});
}
refreshMenus() {
/* const roomId = this.console.getRoomId();
const menus = this.contextMenuFactory.getMenusByContext<IMenu<keyof EntityDict>>('room', roomId);
@ -89,7 +53,6 @@ export default class Menu extends Feature {
);
this.publish(); */
}
getMenus() {
if (!this.menus) {
this.refreshMenus();

Some files were not shown because too many files have changed in this diff Show More