编写了大量支付相关的逻辑
This commit is contained in:
parent
288426babb
commit
f9166d1c9c
|
|
@ -1,5 +1,7 @@
|
|||
import aoCheckers from './accountOper';
|
||||
import payCheckers from './pay';
|
||||
const checkers = [
|
||||
...aoCheckers,
|
||||
...payCheckers,
|
||||
];
|
||||
export default checkers;
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ declare const List: <T extends keyof EntityDict>(props: ReactComponentProps<Enti
|
|||
type: "checkbox" | "radio";
|
||||
selectedRowKeys?: string[] | undefined;
|
||||
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
|
||||
type: "multiple" | "none" | "single";
|
||||
type: "multiple" | "single" | "none";
|
||||
} | undefined) => void;
|
||||
} | undefined;
|
||||
hideHeader: boolean;
|
||||
size?: "small" | "middle" | "large" | undefined;
|
||||
size?: "small" | "large" | "middle" | undefined;
|
||||
scroll?: any;
|
||||
locale?: any;
|
||||
}>) => React.ReactElement;
|
||||
|
|
@ -47,11 +47,11 @@ declare const ListPro: <T extends keyof EntityDict>(props: {
|
|||
type: "checkbox" | "radio";
|
||||
selectedRowKeys?: string[] | undefined;
|
||||
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
|
||||
type: "multiple" | "none" | "single";
|
||||
type: "multiple" | "single" | "none";
|
||||
} | undefined) => void;
|
||||
} | undefined;
|
||||
disableSerialNumber?: boolean | undefined;
|
||||
size?: "small" | "middle" | "large" | undefined;
|
||||
size?: "small" | "large" | "middle" | undefined;
|
||||
scroll?: any;
|
||||
locale?: any;
|
||||
}) => React.ReactElement;
|
||||
|
|
@ -62,14 +62,14 @@ declare const Detail: <T extends keyof EntityDict>(props: ReactComponentProps<En
|
|||
data: Partial<EntityDict[T]["Schema"]>;
|
||||
title?: string | undefined;
|
||||
bordered?: boolean | undefined;
|
||||
layout?: "vertical" | "horizontal" | undefined;
|
||||
layout?: "horizontal" | "vertical" | 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";
|
||||
layout: "horizontal" | "vertical";
|
||||
mode: "default" | "card";
|
||||
}>) => React.ReactElement;
|
||||
export { FilterPanel, List, ListPro, Detail, Upsert, ReactComponentProps, ColumnProps, RowWithActions, OakExtraActionProps, OakAbsAttrDef, onActionFnDef, };
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, boolean, {
|
||||
depositMax: number;
|
||||
onSetPrice: (price: null | number) => void;
|
||||
onSetChannel: (channel: string) => void;
|
||||
onSetMeta: (meta: any) => void;
|
||||
price: number | null;
|
||||
channel: string;
|
||||
meta: any;
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import { PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME } from '../../../types/PayConfig';
|
||||
export default OakComponent({
|
||||
properties: {
|
||||
depositMax: 10000,
|
||||
onSetPrice: (price) => undefined,
|
||||
onSetChannel: (channel) => undefined,
|
||||
onSetMeta: (meta) => undefined,
|
||||
price: null,
|
||||
channel: '',
|
||||
meta: {},
|
||||
},
|
||||
formData({ data }) {
|
||||
const payConfig2 = this.features.pay.getPayConfigs();
|
||||
let accountConfig;
|
||||
const payConfig = [];
|
||||
for (const config of payConfig2) {
|
||||
if (config.channel === PAY_CHANNEL_ACCOUNT_NAME) {
|
||||
accountConfig = config;
|
||||
}
|
||||
else if (config.channel !== PAY_CHANNEL_OFFLINE_NAME || config.allowUser) {
|
||||
payConfig.push(config);
|
||||
}
|
||||
}
|
||||
return {
|
||||
account: data,
|
||||
payConfig,
|
||||
// accountConfig,
|
||||
};
|
||||
},
|
||||
features: ['application'],
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"placeholder": "一次最大充值%{max}元",
|
||||
"label": {
|
||||
"depPrice": "充值金额",
|
||||
"channel": "充值渠道"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
import { AccountPayConfig, PayConfig } from '../../../types/PayConfig';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'account', false, {
|
||||
depositMax: number;
|
||||
payConfig: PayConfig;
|
||||
accountConfig?: AccountPayConfig;
|
||||
}>): null;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { useState } from 'react';
|
||||
export default function Render(props) {
|
||||
const { depositMax, payConfig } = props.data;
|
||||
const { t } = props.methods;
|
||||
const [depPrice, setDepPrice] = useState(null);
|
||||
const [depositChannel, setDepositChannel] = useState();
|
||||
const [depositMeta, setDepositMeta] = useState();
|
||||
return null;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
import { AccountPayConfig, PayConfig } from '../../../types/PayConfig';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'account', false, {
|
||||
depositMax: number;
|
||||
payConfig: PayConfig;
|
||||
accountConfig?: AccountPayConfig;
|
||||
onSetPrice: (price: null | number) => void;
|
||||
onSetChannel: (channel: string) => void;
|
||||
onSetMeta: (meta: any) => void;
|
||||
price: number;
|
||||
channel: string;
|
||||
meta: any;
|
||||
}>): React.JSX.Element | null;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
import { Form, InputNumber } from 'antd';
|
||||
import ChannelPicker from '../../pay/channelPicker';
|
||||
export default function Render(props) {
|
||||
const { depositMax, payConfig, price, channel, meta, onSetChannel, onSetMeta, onSetPrice } = props.data;
|
||||
const { t } = props.methods;
|
||||
if (payConfig) {
|
||||
return (<Form labelCol={{ span: 4 }} wrapperCol={{ span: 14 }} layout="horizontal" style={{ minWidth: 600 }} colon={false}>
|
||||
<Form.Item label={<span>{t("label.depPrice")}:</span>}>
|
||||
<InputNumber placeholder={t('placeholder', { max: depositMax })} max={depositMax} min={1} value={price} addonAfter={t('common::pay.symbol')} onChange={(value) => {
|
||||
onSetPrice(value);
|
||||
}}/>
|
||||
</Form.Item>
|
||||
<Form.Item label={<span style={{ marginTop: 10 }}>
|
||||
{t('label.channel')}:
|
||||
</span>}>
|
||||
<ChannelPicker payConfig={payConfig} onPick={(channel) => {
|
||||
onSetChannel(channel);
|
||||
}} channel={channel} meta={meta} onSetMeta={(meta) => onSetMeta(meta)}/>
|
||||
</Form.Item>
|
||||
</Form>);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, "account", false, {
|
||||
depositMax: number;
|
||||
onDeposit: (payId: string) => void;
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import { generateNewIdAsync } from "oak-domain/lib/utils/uuid";
|
||||
export default OakComponent({
|
||||
entity: 'account',
|
||||
isList: false,
|
||||
projection: {
|
||||
id: 1,
|
||||
total: 1,
|
||||
avail: 1,
|
||||
systemId: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
properties: {
|
||||
depositMax: 10000,
|
||||
onDeposit: (payId) => undefined,
|
||||
},
|
||||
formData({ data }) {
|
||||
return {
|
||||
account: data,
|
||||
};
|
||||
},
|
||||
actions: ['deposit', 'withdraw'],
|
||||
methods: {
|
||||
async deposit(price, channel, meta, success) {
|
||||
const payId = await generateNewIdAsync();
|
||||
const { onDeposit, oakId } = this.props;
|
||||
await this.execute(undefined, undefined, undefined, [
|
||||
{
|
||||
entity: 'account',
|
||||
operation: {
|
||||
id: await generateNewIdAsync(),
|
||||
action: 'deposit',
|
||||
data: {
|
||||
pay$account: {
|
||||
id: await generateNewIdAsync(),
|
||||
action: 'create',
|
||||
data: {
|
||||
id: payId,
|
||||
channel,
|
||||
price,
|
||||
meta,
|
||||
},
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
id: oakId,
|
||||
}
|
||||
},
|
||||
}
|
||||
]);
|
||||
success();
|
||||
onDeposit && onDeposit(payId);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"title": "帐户详情",
|
||||
"total": "总余额",
|
||||
"avail": "可用余额",
|
||||
"loan": "抵押金额",
|
||||
"depositing": "充值中",
|
||||
"deposit": {
|
||||
"title": "帐户充值"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import React from 'react';
|
||||
import { RowWithActions, WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'account', false, {
|
||||
account: RowWithActions<EntityDict, 'account'>;
|
||||
}>): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import React from 'react';
|
||||
export default function Render(props) {
|
||||
return <div>account/detail</div>;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react';
|
||||
import { RowWithActions, WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'account', false, {
|
||||
account: RowWithActions<EntityDict, 'account'>;
|
||||
depositMax: number;
|
||||
}, {
|
||||
deposit: (price: number, channel: string, meta: any, success: () => void) => Promise<void>;
|
||||
}>): React.JSX.Element | null;
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Button, Modal, Card, Flex } from 'antd';
|
||||
import Styles from './web.pc.module.less';
|
||||
import { CentToString } from 'oak-domain/lib/utils/money';
|
||||
import classNames from 'classnames';
|
||||
import AccountDeposit from '../deposit';
|
||||
export default function Render(props) {
|
||||
const { account, depositMax } = props.data;
|
||||
const { t, deposit } = props.methods;
|
||||
const [depositOpen, setDepositOpen] = useState(false);
|
||||
const [depPrice, setDepPrice] = useState(null);
|
||||
const [depositChannel, setDepositChannel] = useState();
|
||||
const [depositMeta, setDepositMeta] = useState();
|
||||
const [depositing, setDepositing] = useState(false);
|
||||
if (account) {
|
||||
const { total, avail, '#oakLegalActions': legalActions } = account;
|
||||
return (<div className={Styles.container}>
|
||||
<Card className={Styles.card} title={t('title')} extra={<Flex gap="middle">
|
||||
{legalActions?.includes('deposit') && <Button type="primary" onClick={() => setDepositOpen(true)}>
|
||||
{t('account:action.deposit')}
|
||||
</Button>}
|
||||
{legalActions?.includes('withdraw') && <Button>
|
||||
{t('account:action.withdraw')}
|
||||
</Button>}
|
||||
</Flex>}>
|
||||
<Flex gap="middle" justify='space-around'>
|
||||
<div className={classNames(Styles.grid, Styles.fortify)}>
|
||||
<span className={Styles.label}>{t('avail')}</span>
|
||||
<span className={Styles.value}>{t('common::pay.symbol')} {CentToString(avail, 2)}</span>
|
||||
</div>
|
||||
<div className={Styles.grid}>
|
||||
<span className={Styles.label}>{t('total')}</span>
|
||||
<span className={Styles.value}>{t('common::pay.symbol')} {CentToString(total, 2)}</span>
|
||||
</div>
|
||||
<div className={Styles.grid}>
|
||||
<span className={Styles.label}>{t('loan')}</span>
|
||||
<span className={Styles.value}>{t('common::pay.symbol')} {CentToString(total - avail, 2)}</span>
|
||||
</div>
|
||||
</Flex>
|
||||
</Card>
|
||||
<Modal title={t('deposit.title')} open={depositOpen} onCancel={() => {
|
||||
setDepositOpen(false);
|
||||
setDepPrice(null);
|
||||
setDepositChannel(undefined);
|
||||
setDepositMeta(undefined);
|
||||
}} destroyOnClose={true} footer={<Button loading={depositing} type="primary" disabled={!depPrice || !depositChannel || depositing} onClick={() => {
|
||||
setDepositing(true);
|
||||
deposit(depPrice, depositChannel, depositMeta || {}, () => {
|
||||
setDepPrice(null);
|
||||
setDepositChannel(undefined);
|
||||
setDepositMeta(undefined);
|
||||
setDepositing(false);
|
||||
});
|
||||
}}>
|
||||
{depositing ? t('depositing') : t('common::confirm')}
|
||||
</Button>}>
|
||||
<div style={{ padding: 12 }}>
|
||||
<AccountDeposit depositMax={depositMax} price={depPrice} channel={depositChannel} meta={depositMeta} onSetPrice={(price) => setDepPrice(price)} onSetChannel={(channel) => setDepositChannel(channel)} onSetMeta={(meta) => setDepositMeta(meta)}/>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.card {
|
||||
margin-top: 18px;
|
||||
margin-bottom: 18px;
|
||||
width: 80%;
|
||||
min-width: 800px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
min-width: 133px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 13px;
|
||||
|
||||
.label {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: var(--oak-color-primary);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: var(--oak-color-primary);
|
||||
line-height: 33.6px;
|
||||
}
|
||||
}
|
||||
|
||||
.fortify {
|
||||
background-color: var(--oak-color-primary-light);
|
||||
|
||||
.label {
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/// <reference types="react" />
|
||||
import { PayConfig } from "../../../types/PayConfig";
|
||||
/**
|
||||
* 支持自定义支付通道的选择器注入
|
||||
* 未来遇到真正需求时再实现,by Xc 20240426
|
||||
*/
|
||||
type ExtraPicker = {
|
||||
label: string;
|
||||
name: string;
|
||||
icon: React.ForwardRefExoticComponent<any>;
|
||||
component?: React.ForwardRefExoticComponent<{
|
||||
onSetMeta?: (meta: object) => void;
|
||||
}>;
|
||||
};
|
||||
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<import("../../../oak-app-domain").EntityDict, keyof import("../../../oak-app-domain").EntityDict, boolean, {
|
||||
payConfig: PayConfig;
|
||||
channel: string;
|
||||
meta: object;
|
||||
extraChannelPickers: ExtraPicker[];
|
||||
onPick: (channel: string) => void;
|
||||
onSetMeta: (meta?: object) => void;
|
||||
}>) => React.ReactElement;
|
||||
export default _default;
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { PAY_CHANNEL_OFFLINE_NAME } from "../../../types/PayConfig";
|
||||
import assert from 'assert';
|
||||
export default OakComponent({
|
||||
properties: {
|
||||
payConfig: [],
|
||||
channel: '',
|
||||
meta: {},
|
||||
extraChannelPickers: [],
|
||||
onPick: (channel) => undefined,
|
||||
onSetMeta: (meta) => undefined,
|
||||
},
|
||||
formData() {
|
||||
const { payConfig } = this.props;
|
||||
assert(payConfig);
|
||||
const offlineConfig = payConfig.find(ele => ele.channel === PAY_CHANNEL_OFFLINE_NAME);
|
||||
return {
|
||||
offlineConfig,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"label": {
|
||||
"option": "渠道"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
import { PayConfig } from '../../../types/PayConfig';
|
||||
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
|
||||
channels: PayConfig[];
|
||||
onPick: (channel: string, meta?: object) => void;
|
||||
}>): null;
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default function Render(props) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '../../../oak-app-domain';
|
||||
import { OfflinePayConfig, PayConfig } from '../../../types/PayConfig';
|
||||
export default function Render(props: WebComponentProps<EntityDict, keyof EntityDict, false, {
|
||||
payConfig: PayConfig;
|
||||
offlineConfig?: OfflinePayConfig;
|
||||
channel: string;
|
||||
meta?: any;
|
||||
onPick: (channel: string, meta?: object) => void;
|
||||
onSetMeta: (meta?: object) => void;
|
||||
}>): React.JSX.Element;
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import React from 'react';
|
||||
import { Radio, Space, Select, Flex } from 'antd';
|
||||
import Styles from './web.pc.module.less';
|
||||
import { PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME, PAY_CHANNEL_WECHAT_APP_NAME, PAY_CHANNEL_WECHAT_H5_NAME, PAY_CHANNEL_WECHAT_JS_NAME, PAY_CHANNEL_WECHAT_MP_NAME, PAY_CHANNEL_WECHAT_NATIVE_NAME } from '../../../types/PayConfig';
|
||||
import { WechatOutlined, WalletOutlined } from '@ant-design/icons';
|
||||
const ChannelIconDict = {
|
||||
[PAY_CHANNEL_ACCOUNT_NAME]: <WalletOutlined />,
|
||||
[PAY_CHANNEL_OFFLINE_NAME]: <WalletOutlined />,
|
||||
[PAY_CHANNEL_WECHAT_APP_NAME]: <WechatOutlined />,
|
||||
[PAY_CHANNEL_WECHAT_JS_NAME]: <WechatOutlined />,
|
||||
[PAY_CHANNEL_WECHAT_NATIVE_NAME]: <WechatOutlined />,
|
||||
[PAY_CHANNEL_WECHAT_H5_NAME]: <WechatOutlined />,
|
||||
[PAY_CHANNEL_WECHAT_MP_NAME]: <WechatOutlined />,
|
||||
};
|
||||
export default function Render(props) {
|
||||
const { payConfig, offlineConfig, channel, onPick, meta, onSetMeta } = props.data;
|
||||
const { t } = props.methods;
|
||||
const Offline = offlineConfig && offlineConfig.options?.length && (<span className={Styles.span}>
|
||||
<Select style={{ width: 140 }} value={meta?.option} options={offlineConfig.options.map(ele => ({
|
||||
label: ele,
|
||||
value: ele,
|
||||
}))} onSelect={(value) => {
|
||||
onSetMeta({
|
||||
...meta,
|
||||
option: value,
|
||||
});
|
||||
}}/>
|
||||
</span>);
|
||||
return (<Radio.Group onChange={({ target }) => onPick(target.value)} value={channel}>
|
||||
<Space direction="vertical">
|
||||
{payConfig.map((v) => (<Radio value={v.channel} key={v.channel}>
|
||||
<Flex gap="middle" className={Styles.option} align='center'>
|
||||
<span className={Styles.span}>
|
||||
{t(`payChannel::${v.channel}`)}
|
||||
</span>
|
||||
{v.channel === 'OFFLINE' && channel === 'OFFLINE' && Offline}
|
||||
</Flex>
|
||||
</Radio>))}
|
||||
</Space>
|
||||
</Radio.Group>);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
.span {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.option {
|
||||
height: 44px;
|
||||
}
|
||||
|
|
@ -87,6 +87,7 @@ export default function render(props) {
|
|||
]} onTabClick={(activeKey) => {
|
||||
if (key && operation) {
|
||||
const { application$system } = operation.data;
|
||||
if (application$system) {
|
||||
const { filter } = application$system;
|
||||
if (filter?.id === key) {
|
||||
setMessage({
|
||||
|
|
@ -97,6 +98,7 @@ export default function render(props) {
|
|||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
setKey(activeKey);
|
||||
}}/>
|
||||
</div>);
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ export default function Offline(props) {
|
|||
};
|
||||
return (<div className={Styles.container}>
|
||||
<Alert type='info' message={t('tips')}/>
|
||||
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 12 }} layout="horizontal" style={{ minWidth: 600 }}>
|
||||
<Form labelCol={{ span: 6 }} wrapperCol={{ span: 12 }} layout="horizontal" style={{ minWidth: 600, marginTop: 22 }}>
|
||||
<Form.Item label={t('options')}>
|
||||
<Flex gap="4px 0" wrap="wrap" style={{ marginTop: 22 }}>
|
||||
<Flex gap="4px 0" wrap="wrap">
|
||||
{options.map((option, idx) => <Tag bordered={false} closable key={idx} onClose={() => {
|
||||
options.splice(idx, 1);
|
||||
update({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,48 @@
|
|||
// 本文件为自动编译产生,请勿直接修改
|
||||
const i18ns = [
|
||||
{
|
||||
id: "a7dab1e9edd21024ad094a553064102d",
|
||||
namespace: "oak-pay-business-c-account-deposit",
|
||||
language: "zh-CN",
|
||||
module: "oak-pay-business",
|
||||
position: "src/components/account/deposit",
|
||||
data: {
|
||||
"placeholder": "一次最大充值%{max}元",
|
||||
"label": {
|
||||
"depPrice": "充值金额",
|
||||
"channel": "充值渠道"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "f86292a7fab630dee76783fe38c35381",
|
||||
namespace: "oak-pay-business-c-account-detail",
|
||||
language: "zh-CN",
|
||||
module: "oak-pay-business",
|
||||
position: "src/components/account/detail",
|
||||
data: {
|
||||
"title": "帐户详情",
|
||||
"total": "总余额",
|
||||
"avail": "可用余额",
|
||||
"loan": "抵押金额",
|
||||
"depositing": "充值中",
|
||||
"deposit": {
|
||||
"title": "帐户充值"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "3500cc465492fca3797b75c9c0dbf517",
|
||||
namespace: "oak-pay-business-c-pay-channelPicker",
|
||||
language: "zh-CN",
|
||||
module: "oak-pay-business",
|
||||
position: "src/components/pay/channelPicker",
|
||||
data: {
|
||||
"label": {
|
||||
"option": "渠道"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "548c6f23c4d08f495b6eed1b757aceb5",
|
||||
namespace: "oak-pay-business-c-payConfig-system",
|
||||
|
|
@ -116,7 +159,11 @@ const i18ns = [
|
|||
"close": "关",
|
||||
"enter": "请输入",
|
||||
"change": "修改",
|
||||
"finish": "完成"
|
||||
"finish": "完成",
|
||||
"pay": {
|
||||
"symbol": "¥",
|
||||
"scale": "元"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -126,13 +173,13 @@ const i18ns = [
|
|||
module: "oak-pay-business",
|
||||
position: "locales/payChannel",
|
||||
data: {
|
||||
"ACCOUNT": "系统内帐户",
|
||||
"OFFLINE": "系统外支付",
|
||||
"WECHAT_JS": "微信支付JS",
|
||||
"WECHAT_MP": "微信小程序",
|
||||
"WECHAT_NATIVE": "微信Native",
|
||||
"WECHAT_H5": "微信H5",
|
||||
"WECHAT_APP": "微信APP"
|
||||
"ACCOUNT": "系统帐户",
|
||||
"OFFLINE": "线下支付",
|
||||
"WECHAT_JS": "微信支付",
|
||||
"WECHAT_MP": "微信支付",
|
||||
"WECHAT_NATIVE": "微信支付",
|
||||
"WECHAT_H5": "微信支付",
|
||||
"WECHAT_APP": "微信支付"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export interface Schema extends EntityShape {
|
|||
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';
|
||||
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, '', {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
;
|
||||
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'],
|
||||
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',
|
||||
is: 'unpaid',
|
||||
};
|
||||
export const entityDesc = {
|
||||
indexes: [
|
||||
|
|
@ -55,7 +55,7 @@ export const entityDesc = {
|
|||
paid: '已付款',
|
||||
partiallyPaid: '部分支付',
|
||||
paying: '支付中',
|
||||
unPaid: '待付款',
|
||||
unpaid: '待付款',
|
||||
timeout: '已超时',
|
||||
cancelled: '已取消',
|
||||
refunded: '已退款',
|
||||
|
|
@ -80,7 +80,7 @@ export const entityDesc = {
|
|||
},
|
||||
color: {
|
||||
iState: {
|
||||
unPaid: '#52BE80',
|
||||
unpaid: '#52BE80',
|
||||
partiallyPaid: '#5DADE2',
|
||||
cancelled: '#D6DBDF',
|
||||
paid: '#2E86C1',
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface Schema extends EntityShape {
|
|||
paid: Price;
|
||||
refunded: Price;
|
||||
channel: String<32>;
|
||||
timeoutAt: Datetime;
|
||||
timeoutAt?: Datetime;
|
||||
forbidRefundAt?: Datetime;
|
||||
account?: Account;
|
||||
order?: Order;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import { Feature } from "oak-frontend-base";
|
||||
import { FeatureDict as GeneralFeatures } from 'oak-general-business';
|
||||
import { EntityDict } from '../oak-app-domain';
|
||||
export default class Pay extends Feature {
|
||||
private application;
|
||||
constructor(application: GeneralFeatures<EntityDict>['application']);
|
||||
getPayChannels(): string[];
|
||||
getPayConfigs(): (import("../types/PayConfig").WechatPayConfig | import("../types/PayConfig").AccountPayConfig | import("../types/PayConfig").OfflinePayConfig)[];
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { Feature } from "oak-frontend-base";
|
||||
export default class Pay extends Feature {
|
||||
application;
|
||||
constructor(application) {
|
||||
super();
|
||||
this.application = application;
|
||||
}
|
||||
getPayChannels() {
|
||||
const application = this.application.getApplication();
|
||||
const { payConfig, system } = application;
|
||||
const { payConfig: systemPayConfig } = system;
|
||||
return (payConfig || []).map(ele => ele.channel).concat((systemPayConfig || []).map(ele => ele.channel));
|
||||
}
|
||||
getPayConfigs() {
|
||||
const application = this.application.getApplication();
|
||||
const { payConfig, system } = application;
|
||||
const { payConfig: systemPayConfig } = system;
|
||||
return (payConfig || []).concat((systemPayConfig || []));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,16 @@
|
|||
import { EntityDict } from '../oak-app-domain';
|
||||
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
|
||||
import { BasicFeatures } from 'oak-frontend-base';
|
||||
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business";
|
||||
export declare function create<ED extends EntityDict>(features: BasicFeatures<ED> & Ogb0FeatureDict<ED>): {};
|
||||
export type FeatureDict<ED extends EntityDict> = {};
|
||||
export declare function initialize<ED extends EntityDict>(features: FeatureDict<ED> & BasicFeatures<ED> & Ogb0FeatureDict<ED>): Promise<void>;
|
||||
import Cos from 'oak-general-business/es/types/Cos';
|
||||
import Pay from './Pay';
|
||||
export declare function create<ED extends EntityDict>(features: BasicFeatures<ED> & Ogb0FeatureDict<ED>): {
|
||||
pay: Pay;
|
||||
};
|
||||
export type FeatureDict<ED extends EntityDict> = {
|
||||
pay: Pay;
|
||||
};
|
||||
export declare function initialize<ED extends EntityDict>(features: FeatureDict<ED> & BasicFeatures<ED> & Ogb0FeatureDict<ED>, access: AccessConfiguration, config?: {
|
||||
applicationExtraProjection?: ED['application']['Selection']['data'];
|
||||
dontAutoLoginInWechatmp?: true;
|
||||
}, clazzes?: Array<new () => Cos<ED>>): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,23 @@
|
|||
import { merge } from 'oak-domain/lib/utils/lodash';
|
||||
import { initialize as initializeGeneral } from 'oak-general-business/es/features';
|
||||
import Pay from './Pay';
|
||||
export function create(features) {
|
||||
return {};
|
||||
const pay = new Pay(features.application);
|
||||
return {
|
||||
pay,
|
||||
};
|
||||
}
|
||||
export async function initialize(features) {
|
||||
export async function initialize(features, access, config, clazzes) {
|
||||
const applicationProjection = {
|
||||
payConfig: 1,
|
||||
system: {
|
||||
payConfig: 1,
|
||||
},
|
||||
};
|
||||
await initializeGeneral(features, access, config ? {
|
||||
dontAutoLoginInWechatmp: config.dontAutoLoginInWechatmp,
|
||||
applicationExtraProjection: merge(applicationProjection, config.applicationExtraProjection || {}),
|
||||
} : {
|
||||
applicationExtraProjection: applicationProjection,
|
||||
}, clazzes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,5 +45,9 @@
|
|||
"close": "关",
|
||||
"enter": "请输入",
|
||||
"change": "修改",
|
||||
"finish": "完成"
|
||||
"finish": "完成",
|
||||
"pay": {
|
||||
"symbol": "¥",
|
||||
"scale": "元"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"ACCOUNT": "系统内帐户",
|
||||
"OFFLINE": "系统外支付",
|
||||
"WECHAT_JS": "微信支付JS",
|
||||
"WECHAT_MP": "微信小程序",
|
||||
"WECHAT_NATIVE": "微信Native",
|
||||
"WECHAT_H5": "微信H5",
|
||||
"WECHAT_APP": "微信APP"
|
||||
"ACCOUNT": "系统帐户",
|
||||
"OFFLINE": "线下支付",
|
||||
"WECHAT_JS": "微信支付",
|
||||
"WECHAT_MP": "微信支付",
|
||||
"WECHAT_NATIVE": "微信支付",
|
||||
"WECHAT_H5": "微信支付",
|
||||
"WECHAT_APP": "微信支付"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,16 +93,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "relationId" | "
|
|||
} | {
|
||||
relation?: never;
|
||||
relationId?: ForeignKey<"relation">;
|
||||
}) & ({
|
||||
pathId?: never;
|
||||
path: Path.CreateSingleOperation;
|
||||
} | {
|
||||
pathId: ForeignKey<"path">;
|
||||
path?: Path.UpdateOperation;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId: ForeignKey<"path">;
|
||||
}));
|
||||
});
|
||||
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
||||
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
||||
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
||||
|
|
@ -118,26 +112,15 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "relationId" | "
|
|||
} | {
|
||||
relation?: never;
|
||||
relationId?: ForeignKey<"relation"> | null;
|
||||
}) & ({
|
||||
path?: Path.CreateSingleOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.UpdateOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.RemoveOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId?: ForeignKey<"path">;
|
||||
})) & {
|
||||
}) & {
|
||||
[k: string]: any;
|
||||
};
|
||||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||
export type RemoveOperationData = {} & (({
|
||||
relation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||
}) & ({
|
||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
||||
}));
|
||||
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
||||
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ActionDef } from "oak-domain/lib/types/Action";
|
||||
import { GenericAction } from "oak-domain/lib/actions/action";
|
||||
export type IAction = 'startPaying' | 'payAll' | 'payPartially' | 'payNone' | 'timeout' | 'cancel' | 'startRefunding' | 'refundAll' | 'refundPartially' | 'refundNone' | string;
|
||||
export type IState = 'paid' | 'unPaid' | 'timeout' | 'cancelled' | 'paying' | 'partiallyPaid' | 'paid' | 'refunding' | 'partiallyRefunded' | 'refunded' | string;
|
||||
export type IState = 'paid' | 'unpaid' | 'timeout' | 'cancelled' | 'paying' | 'partiallyPaid' | 'paid' | 'refunding' | 'partiallyRefunded' | 'refunded' | string;
|
||||
export declare const IActionDef: ActionDef<IAction, IState>;
|
||||
export type ParticularAction = IAction;
|
||||
export declare const actions: string[];
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
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'],
|
||||
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',
|
||||
is: 'unpaid',
|
||||
};
|
||||
export const actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "startPaying", "payAll", "payPartially", "payNone", "timeout", "cancel", "startRefunding", "refundAll", "refundPartially", "refundNone"];
|
||||
export const actionDefDict = {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const desc = {
|
|||
},
|
||||
iState: {
|
||||
type: "enum",
|
||||
enumeration: ["paid", "unPaid", "timeout", "cancelled", "paying", "partiallyPaid", "paid", "refunding", "partiallyRefunded", "refunded"]
|
||||
enumeration: ["paid", "unpaid", "timeout", "cancelled", "paying", "partiallyPaid", "paid", "refunding", "partiallyRefunded", "refunded"]
|
||||
}
|
||||
},
|
||||
actionType: "crud",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const style = {
|
|||
},
|
||||
color: {
|
||||
iState: {
|
||||
unPaid: '#52BE80',
|
||||
unpaid: '#52BE80',
|
||||
partiallyPaid: '#5DADE2',
|
||||
cancelled: '#D6DBDF',
|
||||
paid: '#2E86C1',
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{ "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": "退款中" } } }
|
||||
{ "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": "退款中" } } }
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export const desc = {
|
|||
}
|
||||
}
|
||||
},
|
||||
static: true,
|
||||
actionType: "crud",
|
||||
actions,
|
||||
indexes: [
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export type OpSchema = EntityShape & {
|
|||
paid: Price;
|
||||
refunded: Price;
|
||||
channel: String<32>;
|
||||
timeoutAt: Datetime;
|
||||
timeoutAt?: Datetime | null;
|
||||
forbidRefundAt?: Datetime | null;
|
||||
accountId?: ForeignKey<"account"> | null;
|
||||
orderId?: ForeignKey<"order"> | null;
|
||||
|
|
@ -32,7 +32,7 @@ export type Schema = EntityShape & {
|
|||
paid: Price;
|
||||
refunded: Price;
|
||||
channel: String<32>;
|
||||
timeoutAt: Datetime;
|
||||
timeoutAt?: Datetime | null;
|
||||
forbidRefundAt?: Datetime | null;
|
||||
accountId?: ForeignKey<"account"> | null;
|
||||
orderId?: ForeignKey<"order"> | null;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ export const desc = {
|
|||
}
|
||||
},
|
||||
timeoutAt: {
|
||||
notNull: true,
|
||||
type: "datetime"
|
||||
},
|
||||
forbidRefundAt: {
|
||||
|
|
|
|||
|
|
@ -98,16 +98,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "sourceRelationI
|
|||
} | {
|
||||
sourceRelation?: never;
|
||||
sourceRelationId: ForeignKey<"sourceRelation">;
|
||||
}) & ({
|
||||
pathId?: never;
|
||||
path: Path.CreateSingleOperation;
|
||||
} | {
|
||||
pathId: ForeignKey<"path">;
|
||||
path?: Path.UpdateOperation;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId: ForeignKey<"path">;
|
||||
}) & ({
|
||||
} & ({
|
||||
destRelationId?: never;
|
||||
destRelation: Relation.CreateSingleOperation;
|
||||
} | {
|
||||
|
|
@ -132,19 +126,10 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
|||
} | {
|
||||
sourceRelation?: never;
|
||||
sourceRelationId?: ForeignKey<"sourceRelation">;
|
||||
}) & ({
|
||||
path?: Path.CreateSingleOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.UpdateOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.RemoveOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId?: ForeignKey<"path">;
|
||||
}) & ({
|
||||
} & ({
|
||||
destRelation?: Relation.CreateSingleOperation;
|
||||
destRelationId?: never;
|
||||
} | {
|
||||
|
|
@ -162,8 +147,6 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
|||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||
export type RemoveOperationData = {} & (({
|
||||
sourceRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||
}) & ({
|
||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
||||
}) & ({
|
||||
destRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ const triggers = [
|
|||
entity: 'pay',
|
||||
action: ['startPaying'],
|
||||
when: 'before',
|
||||
priority: 99,
|
||||
fn: async ({ operation }, context, option) => {
|
||||
const { data, filter } = operation;
|
||||
const pays = await context.select('pay', {
|
||||
|
|
@ -244,14 +245,9 @@ const triggers = [
|
|||
const [pay] = pays;
|
||||
const { applicationId, channel, iState } = pay;
|
||||
assert(iState === 'unpaid');
|
||||
if (![PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME].includes(channel)) {
|
||||
const payClazz = getPayClazz(applicationId, channel);
|
||||
const [prePayId, meta] = await payClazz.prepay(pay);
|
||||
data.externalId = prePayId;
|
||||
data.meta = meta;
|
||||
const payClazz = await getPayClazz(applicationId, channel, context);
|
||||
await payClazz.prepay(pay, data, context);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -270,7 +266,7 @@ const triggers = [
|
|||
const { applicationId, channel, iState, externalId } = pay;
|
||||
assert(iState === 'unpaid' || iState === 'paying');
|
||||
if (iState === 'paying' && externalId && ![PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME].includes(channel)) {
|
||||
const payClazz = getPayClazz(applicationId, channel);
|
||||
const payClazz = await getPayClazz(applicationId, channel, context);
|
||||
await payClazz.close(pay);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { EntityDict } from '../oak-app-domain';
|
||||
import { BRC } from '../types/RuntimeCxt';
|
||||
type IState = EntityDict['pay']['OpSchema']['iState'];
|
||||
export default interface PayClazz {
|
||||
type: string;
|
||||
prepay(pay: EntityDict['pay']['OpSchema']): Promise<[string, object]>;
|
||||
channel: string;
|
||||
prepay(pay: EntityDict['pay']['OpSchema'], data: EntityDict['pay']['Update']['data'], context: BRC): Promise<void>;
|
||||
getState(pay: EntityDict['pay']['OpSchema']): Promise<IState>;
|
||||
close(pay: EntityDict['pay']['OpSchema']): Promise<void>;
|
||||
decodeNotification(params: Record<string, string>, body: any): Promise<Array<{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import { OpSchema, UpdateOperationData } from "../../oak-app-domain/Pay/Schema";
|
||||
import PayClazz from "../../types/PayClazz";
|
||||
export default class Account implements PayClazz {
|
||||
channel: string;
|
||||
prepay(pay: OpSchema, data: UpdateOperationData): Promise<void>;
|
||||
getState(pay: OpSchema): Promise<string | null | undefined>;
|
||||
close(pay: OpSchema): Promise<void>;
|
||||
decodeNotification(params: Record<string, string>, body: any): Promise<{
|
||||
payId: string;
|
||||
iState: string | null | undefined;
|
||||
extra?: any;
|
||||
answer: string;
|
||||
}[]>;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import { PAY_CHANNEL_ACCOUNT_NAME } from '../../types/PayConfig';
|
||||
import assert from 'assert';
|
||||
import { generateNewIdAsync } from "oak-domain/lib/utils/uuid";
|
||||
export default class Account {
|
||||
channel = PAY_CHANNEL_ACCOUNT_NAME;
|
||||
async prepay(pay, data) {
|
||||
const { accountId, price } = pay;
|
||||
assert(accountId);
|
||||
/**
|
||||
* account类型的支付就是直接从account中扣除款项
|
||||
*/
|
||||
data.iState = 'paid',
|
||||
data.accountOper$entity = [
|
||||
{
|
||||
id: await generateNewIdAsync(),
|
||||
action: 'create',
|
||||
data: {
|
||||
id: await generateNewIdAsync(),
|
||||
totalPlus: -price,
|
||||
availPlus: -price,
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
getState(pay) {
|
||||
throw new Error("account类型的pay不应该需要查询此状态");
|
||||
}
|
||||
close(pay) {
|
||||
throw new Error("account类型的pay无法关闭");
|
||||
}
|
||||
decodeNotification(params, body) {
|
||||
throw new Error("account类型的pay不需调用此接口");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { OpSchema, UpdateOperationData } from "../../oak-app-domain/Pay/Schema";
|
||||
import PayClazz from "../../types/PayClazz";
|
||||
import { BRC } from "../../types/RuntimeCxt";
|
||||
export default class Offline implements PayClazz {
|
||||
channel: string;
|
||||
prepay(pay: OpSchema, data: UpdateOperationData, context: BRC): Promise<void>;
|
||||
getState(pay: OpSchema): Promise<string | null | undefined>;
|
||||
close(pay: OpSchema): Promise<void>;
|
||||
decodeNotification(params: Record<string, string>, body: any): Promise<{
|
||||
payId: string;
|
||||
iState: string | null | undefined;
|
||||
extra?: any;
|
||||
answer: string;
|
||||
}[]>;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { PAY_CHANNEL_OFFLINE_NAME } from "../../types/PayConfig";
|
||||
import assert from "assert";
|
||||
export default class Offline {
|
||||
channel = PAY_CHANNEL_OFFLINE_NAME;
|
||||
async prepay(pay, data, context) {
|
||||
return;
|
||||
}
|
||||
async getState(pay) {
|
||||
const { iState } = pay;
|
||||
assert(iState === 'paying');
|
||||
return iState;
|
||||
}
|
||||
async close(pay) {
|
||||
return;
|
||||
}
|
||||
decodeNotification(params, body) {
|
||||
throw new Error("offline类型的pay不应当跑到这里");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import PayClazz from '../../types/PayClazz';
|
||||
export declare function registerPayClazz(appId: string, channel: string, clazz: PayClazz): void;
|
||||
export declare function getPayClazz(appId: string, channel: string): PayClazz;
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
type PayClazzConstructor = <ED extends EntityDict>(application: ED['application']['Schema'], channel: string, context: BRC) => Promise<PayClazz>;
|
||||
export declare function registerAppPayClazzConstructor(channel: string, constructor: PayClazzConstructor): void;
|
||||
export declare function getPayClazz(appId: string, channel: string, context: BRC): Promise<PayClazz>;
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,38 @@
|
|||
import { PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME } from "../../types/PayConfig";
|
||||
import assert from 'assert';
|
||||
import Offline from './Offline';
|
||||
import Account from './Account';
|
||||
const PayChannelDict = {};
|
||||
export function registerPayClazz(appId, channel, clazz) {
|
||||
const key = `${appId}.${channel}`;
|
||||
assert(!PayChannelDict.hasOwnProperty(key));
|
||||
PayChannelDict[key] = clazz;
|
||||
const PayClazzConstructorDict = {
|
||||
[PAY_CHANNEL_OFFLINE_NAME]: async () => new Offline(),
|
||||
[PAY_CHANNEL_ACCOUNT_NAME]: async () => new Account(),
|
||||
};
|
||||
export function registerAppPayClazzConstructor(channel, constructor) {
|
||||
PayClazzConstructorDict[channel] = constructor;
|
||||
}
|
||||
export function getPayClazz(appId, channel) {
|
||||
export async function getPayClazz(appId, channel, context) {
|
||||
const key = `${appId}.${channel}`;
|
||||
assert(PayChannelDict.hasOwnProperty(key));
|
||||
if (PayChannelDict.hasOwnProperty(key)) {
|
||||
return PayChannelDict[key];
|
||||
}
|
||||
const [application] = await context.select('application', {
|
||||
data: {
|
||||
id: 1,
|
||||
config: 1,
|
||||
payConfig: 1,
|
||||
type: 1,
|
||||
system: {
|
||||
id: 1,
|
||||
config: 1,
|
||||
payConfig: 1,
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
id: appId,
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
assert(PayClazzConstructorDict.hasOwnProperty(channel));
|
||||
const PayClazz = await PayClazzConstructorDict[channel](application, channel, context);
|
||||
PayChannelDict[key] = PayClazz;
|
||||
return PayClazz;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const watchers = [
|
|||
const results = [];
|
||||
for (const pay of data) {
|
||||
const { applicationId, channel, timeoutAt } = pay;
|
||||
const clazz = getPayClazz(applicationId, channel);
|
||||
const clazz = await getPayClazz(applicationId, channel, context);
|
||||
const iState = await clazz.getState(pay);
|
||||
if (iState !== pay.iState) {
|
||||
let action = 'close';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tslib_1 = require("tslib");
|
||||
const accountOper_1 = tslib_1.__importDefault(require("./accountOper"));
|
||||
const pay_1 = tslib_1.__importDefault(require("./pay"));
|
||||
const checkers = [
|
||||
...accountOper_1.default,
|
||||
...pay_1.default,
|
||||
];
|
||||
exports.default = checkers;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,49 @@
|
|||
// 本文件为自动编译产生,请勿直接修改
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const i18ns = [
|
||||
{
|
||||
id: "a7dab1e9edd21024ad094a553064102d",
|
||||
namespace: "oak-pay-business-c-account-deposit",
|
||||
language: "zh-CN",
|
||||
module: "oak-pay-business",
|
||||
position: "src/components/account/deposit",
|
||||
data: {
|
||||
"placeholder": "一次最大充值%{max}元",
|
||||
"label": {
|
||||
"depPrice": "充值金额",
|
||||
"channel": "充值渠道"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "f86292a7fab630dee76783fe38c35381",
|
||||
namespace: "oak-pay-business-c-account-detail",
|
||||
language: "zh-CN",
|
||||
module: "oak-pay-business",
|
||||
position: "src/components/account/detail",
|
||||
data: {
|
||||
"title": "帐户详情",
|
||||
"total": "总余额",
|
||||
"avail": "可用余额",
|
||||
"loan": "抵押金额",
|
||||
"depositing": "充值中",
|
||||
"deposit": {
|
||||
"title": "帐户充值"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "3500cc465492fca3797b75c9c0dbf517",
|
||||
namespace: "oak-pay-business-c-pay-channelPicker",
|
||||
language: "zh-CN",
|
||||
module: "oak-pay-business",
|
||||
position: "src/components/pay/channelPicker",
|
||||
data: {
|
||||
"label": {
|
||||
"option": "渠道"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "548c6f23c4d08f495b6eed1b757aceb5",
|
||||
namespace: "oak-pay-business-c-payConfig-system",
|
||||
|
|
@ -118,7 +161,11 @@ const i18ns = [
|
|||
"close": "关",
|
||||
"enter": "请输入",
|
||||
"change": "修改",
|
||||
"finish": "完成"
|
||||
"finish": "完成",
|
||||
"pay": {
|
||||
"symbol": "¥",
|
||||
"scale": "元"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -128,13 +175,13 @@ const i18ns = [
|
|||
module: "oak-pay-business",
|
||||
position: "locales/payChannel",
|
||||
data: {
|
||||
"ACCOUNT": "系统内帐户",
|
||||
"OFFLINE": "系统外支付",
|
||||
"WECHAT_JS": "微信支付JS",
|
||||
"WECHAT_MP": "微信小程序",
|
||||
"WECHAT_NATIVE": "微信Native",
|
||||
"WECHAT_H5": "微信H5",
|
||||
"WECHAT_APP": "微信APP"
|
||||
"ACCOUNT": "系统帐户",
|
||||
"OFFLINE": "线下支付",
|
||||
"WECHAT_JS": "微信支付",
|
||||
"WECHAT_MP": "微信支付",
|
||||
"WECHAT_NATIVE": "微信支付",
|
||||
"WECHAT_H5": "微信支付",
|
||||
"WECHAT_APP": "微信支付"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export interface Schema extends EntityShape {
|
|||
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';
|
||||
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, '', {
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@ exports.entityDesc = exports.IActionDef = void 0;
|
|||
;
|
||||
exports.IActionDef = {
|
||||
stm: {
|
||||
startPaying: ['unPaid', 'paying'],
|
||||
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
|
||||
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
|
||||
payNone: ['paying', 'unPaid'],
|
||||
timeout: ['unPaid', 'timeout'],
|
||||
cancel: ['unPaid', 'cancelled'],
|
||||
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',
|
||||
is: 'unpaid',
|
||||
};
|
||||
exports.entityDesc = {
|
||||
indexes: [
|
||||
|
|
@ -58,7 +58,7 @@ exports.entityDesc = {
|
|||
paid: '已付款',
|
||||
partiallyPaid: '部分支付',
|
||||
paying: '支付中',
|
||||
unPaid: '待付款',
|
||||
unpaid: '待付款',
|
||||
timeout: '已超时',
|
||||
cancelled: '已取消',
|
||||
refunded: '已退款',
|
||||
|
|
@ -83,7 +83,7 @@ exports.entityDesc = {
|
|||
},
|
||||
color: {
|
||||
iState: {
|
||||
unPaid: '#52BE80',
|
||||
unpaid: '#52BE80',
|
||||
partiallyPaid: '#5DADE2',
|
||||
cancelled: '#D6DBDF',
|
||||
paid: '#2E86C1',
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface Schema extends EntityShape {
|
|||
paid: Price;
|
||||
refunded: Price;
|
||||
channel: String<32>;
|
||||
timeoutAt: Datetime;
|
||||
timeoutAt?: Datetime;
|
||||
forbidRefundAt?: Datetime;
|
||||
account?: Account;
|
||||
order?: Order;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import { Feature } from "oak-frontend-base";
|
||||
import { FeatureDict as GeneralFeatures } from 'oak-general-business';
|
||||
import { EntityDict } from '../oak-app-domain';
|
||||
export default class Pay extends Feature {
|
||||
private application;
|
||||
constructor(application: GeneralFeatures<EntityDict>['application']);
|
||||
getPayChannels(): string[];
|
||||
getPayConfigs(): (import("../types/PayConfig").WechatPayConfig | import("../types/PayConfig").AccountPayConfig | import("../types/PayConfig").OfflinePayConfig)[];
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const oak_frontend_base_1 = require("oak-frontend-base");
|
||||
class Pay extends oak_frontend_base_1.Feature {
|
||||
application;
|
||||
constructor(application) {
|
||||
super();
|
||||
this.application = application;
|
||||
}
|
||||
getPayChannels() {
|
||||
const application = this.application.getApplication();
|
||||
const { payConfig, system } = application;
|
||||
const { payConfig: systemPayConfig } = system;
|
||||
return (payConfig || []).map(ele => ele.channel).concat((systemPayConfig || []).map(ele => ele.channel));
|
||||
}
|
||||
getPayConfigs() {
|
||||
const application = this.application.getApplication();
|
||||
const { payConfig, system } = application;
|
||||
const { payConfig: systemPayConfig } = system;
|
||||
return (payConfig || []).concat((systemPayConfig || []));
|
||||
}
|
||||
}
|
||||
exports.default = Pay;
|
||||
|
|
@ -1,6 +1,16 @@
|
|||
import { EntityDict } from '../oak-app-domain';
|
||||
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
|
||||
import { BasicFeatures } from 'oak-frontend-base';
|
||||
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business";
|
||||
export declare function create<ED extends EntityDict>(features: BasicFeatures<ED> & Ogb0FeatureDict<ED>): {};
|
||||
export type FeatureDict<ED extends EntityDict> = {};
|
||||
export declare function initialize<ED extends EntityDict>(features: FeatureDict<ED> & BasicFeatures<ED> & Ogb0FeatureDict<ED>): Promise<void>;
|
||||
import Cos from 'oak-general-business/es/types/Cos';
|
||||
import Pay from './Pay';
|
||||
export declare function create<ED extends EntityDict>(features: BasicFeatures<ED> & Ogb0FeatureDict<ED>): {
|
||||
pay: Pay;
|
||||
};
|
||||
export type FeatureDict<ED extends EntityDict> = {
|
||||
pay: Pay;
|
||||
};
|
||||
export declare function initialize<ED extends EntityDict>(features: FeatureDict<ED> & BasicFeatures<ED> & Ogb0FeatureDict<ED>, access: AccessConfiguration, config?: {
|
||||
applicationExtraProjection?: ED['application']['Selection']['data'];
|
||||
dontAutoLoginInWechatmp?: true;
|
||||
}, clazzes?: Array<new () => Cos<ED>>): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,29 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.initialize = exports.create = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
const lodash_1 = require("oak-domain/lib/utils/lodash");
|
||||
const features_1 = require("oak-general-business/es/features");
|
||||
const Pay_1 = tslib_1.__importDefault(require("./Pay"));
|
||||
function create(features) {
|
||||
return {};
|
||||
const pay = new Pay_1.default(features.application);
|
||||
return {
|
||||
pay,
|
||||
};
|
||||
}
|
||||
exports.create = create;
|
||||
async function initialize(features) {
|
||||
async function initialize(features, access, config, clazzes) {
|
||||
const applicationProjection = {
|
||||
payConfig: 1,
|
||||
system: {
|
||||
payConfig: 1,
|
||||
},
|
||||
};
|
||||
await (0, features_1.initialize)(features, access, config ? {
|
||||
dontAutoLoginInWechatmp: config.dontAutoLoginInWechatmp,
|
||||
applicationExtraProjection: (0, lodash_1.merge)(applicationProjection, config.applicationExtraProjection || {}),
|
||||
} : {
|
||||
applicationExtraProjection: applicationProjection,
|
||||
}, clazzes);
|
||||
}
|
||||
exports.initialize = initialize;
|
||||
|
|
|
|||
|
|
@ -45,5 +45,9 @@
|
|||
"close": "关",
|
||||
"enter": "请输入",
|
||||
"change": "修改",
|
||||
"finish": "完成"
|
||||
"finish": "完成",
|
||||
"pay": {
|
||||
"symbol": "¥",
|
||||
"scale": "元"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"ACCOUNT": "系统内帐户",
|
||||
"OFFLINE": "系统外支付",
|
||||
"WECHAT_JS": "微信支付JS",
|
||||
"WECHAT_MP": "微信小程序",
|
||||
"WECHAT_NATIVE": "微信Native",
|
||||
"WECHAT_H5": "微信H5",
|
||||
"WECHAT_APP": "微信APP"
|
||||
"ACCOUNT": "系统帐户",
|
||||
"OFFLINE": "线下支付",
|
||||
"WECHAT_JS": "微信支付",
|
||||
"WECHAT_MP": "微信支付",
|
||||
"WECHAT_NATIVE": "微信支付",
|
||||
"WECHAT_H5": "微信支付",
|
||||
"WECHAT_APP": "微信支付"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,16 +93,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "relationId" | "
|
|||
} | {
|
||||
relation?: never;
|
||||
relationId?: ForeignKey<"relation">;
|
||||
}) & ({
|
||||
pathId?: never;
|
||||
path: Path.CreateSingleOperation;
|
||||
} | {
|
||||
pathId: ForeignKey<"path">;
|
||||
path?: Path.UpdateOperation;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId: ForeignKey<"path">;
|
||||
}));
|
||||
});
|
||||
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
||||
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
||||
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
||||
|
|
@ -118,26 +112,15 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "relationId" | "
|
|||
} | {
|
||||
relation?: never;
|
||||
relationId?: ForeignKey<"relation"> | null;
|
||||
}) & ({
|
||||
path?: Path.CreateSingleOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.UpdateOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.RemoveOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId?: ForeignKey<"path">;
|
||||
})) & {
|
||||
}) & {
|
||||
[k: string]: any;
|
||||
};
|
||||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||
export type RemoveOperationData = {} & (({
|
||||
relation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||
}) & ({
|
||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
||||
}));
|
||||
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
||||
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ActionDef } from "oak-domain/lib/types/Action";
|
||||
import { GenericAction } from "oak-domain/lib/actions/action";
|
||||
export type IAction = 'startPaying' | 'payAll' | 'payPartially' | 'payNone' | 'timeout' | 'cancel' | 'startRefunding' | 'refundAll' | 'refundPartially' | 'refundNone' | string;
|
||||
export type IState = 'paid' | 'unPaid' | 'timeout' | 'cancelled' | 'paying' | 'partiallyPaid' | 'paid' | 'refunding' | 'partiallyRefunded' | 'refunded' | string;
|
||||
export type IState = 'paid' | 'unpaid' | 'timeout' | 'cancelled' | 'paying' | 'partiallyPaid' | 'paid' | 'refunding' | 'partiallyRefunded' | 'refunded' | string;
|
||||
export declare const IActionDef: ActionDef<IAction, IState>;
|
||||
export type ParticularAction = IAction;
|
||||
export declare const actions: string[];
|
||||
|
|
|
|||
|
|
@ -3,18 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
exports.actionDefDict = exports.actions = exports.IActionDef = void 0;
|
||||
exports.IActionDef = {
|
||||
stm: {
|
||||
startPaying: ['unPaid', 'paying'],
|
||||
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
|
||||
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
|
||||
payNone: ['paying', 'unPaid'],
|
||||
timeout: ['unPaid', 'timeout'],
|
||||
cancel: ['unPaid', 'cancelled'],
|
||||
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',
|
||||
is: 'unpaid',
|
||||
};
|
||||
exports.actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "startPaying", "payAll", "payPartially", "payNone", "timeout", "cancel", "startRefunding", "refundAll", "refundPartially", "refundNone"];
|
||||
exports.actionDefDict = {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ exports.desc = {
|
|||
},
|
||||
iState: {
|
||||
type: "enum",
|
||||
enumeration: ["paid", "unPaid", "timeout", "cancelled", "paying", "partiallyPaid", "paid", "refunding", "partiallyRefunded", "refunded"]
|
||||
enumeration: ["paid", "unpaid", "timeout", "cancelled", "paying", "partiallyPaid", "paid", "refunding", "partiallyRefunded", "refunded"]
|
||||
}
|
||||
},
|
||||
actionType: "crud",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ exports.style = {
|
|||
},
|
||||
color: {
|
||||
iState: {
|
||||
unPaid: '#52BE80',
|
||||
unpaid: '#52BE80',
|
||||
partiallyPaid: '#5DADE2',
|
||||
cancelled: '#D6DBDF',
|
||||
paid: '#2E86C1',
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{ "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": "退款中" } } }
|
||||
{ "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": "退款中" } } }
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ exports.desc = {
|
|||
}
|
||||
}
|
||||
},
|
||||
static: true,
|
||||
actionType: "crud",
|
||||
actions: action_1.genericActions,
|
||||
indexes: [
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export type OpSchema = EntityShape & {
|
|||
paid: Price;
|
||||
refunded: Price;
|
||||
channel: String<32>;
|
||||
timeoutAt: Datetime;
|
||||
timeoutAt?: Datetime | null;
|
||||
forbidRefundAt?: Datetime | null;
|
||||
accountId?: ForeignKey<"account"> | null;
|
||||
orderId?: ForeignKey<"order"> | null;
|
||||
|
|
@ -32,7 +32,7 @@ export type Schema = EntityShape & {
|
|||
paid: Price;
|
||||
refunded: Price;
|
||||
channel: String<32>;
|
||||
timeoutAt: Datetime;
|
||||
timeoutAt?: Datetime | null;
|
||||
forbidRefundAt?: Datetime | null;
|
||||
accountId?: ForeignKey<"account"> | null;
|
||||
orderId?: ForeignKey<"order"> | null;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ exports.desc = {
|
|||
}
|
||||
},
|
||||
timeoutAt: {
|
||||
notNull: true,
|
||||
type: "datetime"
|
||||
},
|
||||
forbidRefundAt: {
|
||||
|
|
|
|||
|
|
@ -98,16 +98,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "sourceRelationI
|
|||
} | {
|
||||
sourceRelation?: never;
|
||||
sourceRelationId: ForeignKey<"sourceRelation">;
|
||||
}) & ({
|
||||
pathId?: never;
|
||||
path: Path.CreateSingleOperation;
|
||||
} | {
|
||||
pathId: ForeignKey<"path">;
|
||||
path?: Path.UpdateOperation;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId: ForeignKey<"path">;
|
||||
}) & ({
|
||||
} & ({
|
||||
destRelationId?: never;
|
||||
destRelation: Relation.CreateSingleOperation;
|
||||
} | {
|
||||
|
|
@ -132,19 +126,10 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
|||
} | {
|
||||
sourceRelation?: never;
|
||||
sourceRelationId?: ForeignKey<"sourceRelation">;
|
||||
}) & ({
|
||||
path?: Path.CreateSingleOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.UpdateOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
path?: Path.RemoveOperation;
|
||||
pathId?: never;
|
||||
} | {
|
||||
}) & {
|
||||
path?: never;
|
||||
pathId?: ForeignKey<"path">;
|
||||
}) & ({
|
||||
} & ({
|
||||
destRelation?: Relation.CreateSingleOperation;
|
||||
destRelationId?: never;
|
||||
} | {
|
||||
|
|
@ -162,8 +147,6 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
|||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||
export type RemoveOperationData = {} & (({
|
||||
sourceRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||
}) & ({
|
||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
||||
}) & ({
|
||||
destRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -237,6 +237,7 @@ const triggers = [
|
|||
entity: 'pay',
|
||||
action: ['startPaying'],
|
||||
when: 'before',
|
||||
priority: 99,
|
||||
fn: async ({ operation }, context, option) => {
|
||||
const { data, filter } = operation;
|
||||
const pays = await context.select('pay', {
|
||||
|
|
@ -247,14 +248,9 @@ const triggers = [
|
|||
const [pay] = pays;
|
||||
const { applicationId, channel, iState } = pay;
|
||||
(0, assert_1.default)(iState === 'unpaid');
|
||||
if (![PayConfig_1.PAY_CHANNEL_ACCOUNT_NAME, PayConfig_1.PAY_CHANNEL_OFFLINE_NAME].includes(channel)) {
|
||||
const payClazz = (0, payClazz_1.getPayClazz)(applicationId, channel);
|
||||
const [prePayId, meta] = await payClazz.prepay(pay);
|
||||
data.externalId = prePayId;
|
||||
data.meta = meta;
|
||||
const payClazz = await (0, payClazz_1.getPayClazz)(applicationId, channel, context);
|
||||
await payClazz.prepay(pay, data, context);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -273,7 +269,7 @@ const triggers = [
|
|||
const { applicationId, channel, iState, externalId } = pay;
|
||||
(0, assert_1.default)(iState === 'unpaid' || iState === 'paying');
|
||||
if (iState === 'paying' && externalId && ![PayConfig_1.PAY_CHANNEL_ACCOUNT_NAME, PayConfig_1.PAY_CHANNEL_OFFLINE_NAME].includes(channel)) {
|
||||
const payClazz = (0, payClazz_1.getPayClazz)(applicationId, channel);
|
||||
const payClazz = await (0, payClazz_1.getPayClazz)(applicationId, channel, context);
|
||||
await payClazz.close(pay);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { EntityDict } from '../oak-app-domain';
|
||||
import { BRC } from '../types/RuntimeCxt';
|
||||
type IState = EntityDict['pay']['OpSchema']['iState'];
|
||||
export default interface PayClazz {
|
||||
type: string;
|
||||
prepay(pay: EntityDict['pay']['OpSchema']): Promise<[string, object]>;
|
||||
channel: string;
|
||||
prepay(pay: EntityDict['pay']['OpSchema'], data: EntityDict['pay']['Update']['data'], context: BRC): Promise<void>;
|
||||
getState(pay: EntityDict['pay']['OpSchema']): Promise<IState>;
|
||||
close(pay: EntityDict['pay']['OpSchema']): Promise<void>;
|
||||
decodeNotification(params: Record<string, string>, body: any): Promise<Array<{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import { OpSchema, UpdateOperationData } from "../../oak-app-domain/Pay/Schema";
|
||||
import PayClazz from "../../types/PayClazz";
|
||||
export default class Account implements PayClazz {
|
||||
channel: string;
|
||||
prepay(pay: OpSchema, data: UpdateOperationData): Promise<void>;
|
||||
getState(pay: OpSchema): Promise<string | null | undefined>;
|
||||
close(pay: OpSchema): Promise<void>;
|
||||
decodeNotification(params: Record<string, string>, body: any): Promise<{
|
||||
payId: string;
|
||||
iState: string | null | undefined;
|
||||
extra?: any;
|
||||
answer: string;
|
||||
}[]>;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tslib_1 = require("tslib");
|
||||
const PayConfig_1 = require("../../types/PayConfig");
|
||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||||
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
||||
class Account {
|
||||
channel = PayConfig_1.PAY_CHANNEL_ACCOUNT_NAME;
|
||||
async prepay(pay, data) {
|
||||
const { accountId, price } = pay;
|
||||
(0, assert_1.default)(accountId);
|
||||
/**
|
||||
* account类型的支付就是直接从account中扣除款项
|
||||
*/
|
||||
data.iState = 'paid',
|
||||
data.accountOper$entity = [
|
||||
{
|
||||
id: await (0, uuid_1.generateNewIdAsync)(),
|
||||
action: 'create',
|
||||
data: {
|
||||
id: await (0, uuid_1.generateNewIdAsync)(),
|
||||
totalPlus: -price,
|
||||
availPlus: -price,
|
||||
},
|
||||
}
|
||||
];
|
||||
}
|
||||
getState(pay) {
|
||||
throw new Error("account类型的pay不应该需要查询此状态");
|
||||
}
|
||||
close(pay) {
|
||||
throw new Error("account类型的pay无法关闭");
|
||||
}
|
||||
decodeNotification(params, body) {
|
||||
throw new Error("account类型的pay不需调用此接口");
|
||||
}
|
||||
}
|
||||
exports.default = Account;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { OpSchema, UpdateOperationData } from "../../oak-app-domain/Pay/Schema";
|
||||
import PayClazz from "../../types/PayClazz";
|
||||
import { BRC } from "../../types/RuntimeCxt";
|
||||
export default class Offline implements PayClazz {
|
||||
channel: string;
|
||||
prepay(pay: OpSchema, data: UpdateOperationData, context: BRC): Promise<void>;
|
||||
getState(pay: OpSchema): Promise<string | null | undefined>;
|
||||
close(pay: OpSchema): Promise<void>;
|
||||
decodeNotification(params: Record<string, string>, body: any): Promise<{
|
||||
payId: string;
|
||||
iState: string | null | undefined;
|
||||
extra?: any;
|
||||
answer: string;
|
||||
}[]>;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tslib_1 = require("tslib");
|
||||
const PayConfig_1 = require("../../types/PayConfig");
|
||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||||
class Offline {
|
||||
channel = PayConfig_1.PAY_CHANNEL_OFFLINE_NAME;
|
||||
async prepay(pay, data, context) {
|
||||
return;
|
||||
}
|
||||
async getState(pay) {
|
||||
const { iState } = pay;
|
||||
(0, assert_1.default)(iState === 'paying');
|
||||
return iState;
|
||||
}
|
||||
async close(pay) {
|
||||
return;
|
||||
}
|
||||
decodeNotification(params, body) {
|
||||
throw new Error("offline类型的pay不应当跑到这里");
|
||||
}
|
||||
}
|
||||
exports.default = Offline;
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
import { EntityDict } from '../../oak-app-domain';
|
||||
import PayClazz from '../../types/PayClazz';
|
||||
export declare function registerPayClazz(appId: string, channel: string, clazz: PayClazz): void;
|
||||
export declare function getPayClazz(appId: string, channel: string): PayClazz;
|
||||
import { BRC } from '../../types/RuntimeCxt';
|
||||
type PayClazzConstructor = <ED extends EntityDict>(application: ED['application']['Schema'], channel: string, context: BRC) => Promise<PayClazz>;
|
||||
export declare function registerAppPayClazzConstructor(channel: string, constructor: PayClazzConstructor): void;
|
||||
export declare function getPayClazz(appId: string, channel: string, context: BRC): Promise<PayClazz>;
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -1,18 +1,44 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getPayClazz = exports.registerPayClazz = void 0;
|
||||
exports.getPayClazz = exports.registerAppPayClazzConstructor = void 0;
|
||||
const tslib_1 = require("tslib");
|
||||
const PayConfig_1 = require("../../types/PayConfig");
|
||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||||
const Offline_1 = tslib_1.__importDefault(require("./Offline"));
|
||||
const Account_1 = tslib_1.__importDefault(require("./Account"));
|
||||
const PayChannelDict = {};
|
||||
function registerPayClazz(appId, channel, clazz) {
|
||||
const key = `${appId}.${channel}`;
|
||||
(0, assert_1.default)(!PayChannelDict.hasOwnProperty(key));
|
||||
PayChannelDict[key] = clazz;
|
||||
const PayClazzConstructorDict = {
|
||||
[PayConfig_1.PAY_CHANNEL_OFFLINE_NAME]: async () => new Offline_1.default(),
|
||||
[PayConfig_1.PAY_CHANNEL_ACCOUNT_NAME]: async () => new Account_1.default(),
|
||||
};
|
||||
function registerAppPayClazzConstructor(channel, constructor) {
|
||||
PayClazzConstructorDict[channel] = constructor;
|
||||
}
|
||||
exports.registerPayClazz = registerPayClazz;
|
||||
function getPayClazz(appId, channel) {
|
||||
exports.registerAppPayClazzConstructor = registerAppPayClazzConstructor;
|
||||
async function getPayClazz(appId, channel, context) {
|
||||
const key = `${appId}.${channel}`;
|
||||
(0, assert_1.default)(PayChannelDict.hasOwnProperty(key));
|
||||
if (PayChannelDict.hasOwnProperty(key)) {
|
||||
return PayChannelDict[key];
|
||||
}
|
||||
const [application] = await context.select('application', {
|
||||
data: {
|
||||
id: 1,
|
||||
config: 1,
|
||||
payConfig: 1,
|
||||
type: 1,
|
||||
system: {
|
||||
id: 1,
|
||||
config: 1,
|
||||
payConfig: 1,
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
id: appId,
|
||||
}
|
||||
}, { dontCollect: true });
|
||||
(0, assert_1.default)(PayClazzConstructorDict.hasOwnProperty(channel));
|
||||
const PayClazz = await PayClazzConstructorDict[channel](application, channel, context);
|
||||
PayChannelDict[key] = PayClazz;
|
||||
return PayClazz;
|
||||
}
|
||||
exports.getPayClazz = getPayClazz;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const watchers = [
|
|||
const results = [];
|
||||
for (const pay of data) {
|
||||
const { applicationId, channel, timeoutAt } = pay;
|
||||
const clazz = (0, payClazz_1.getPayClazz)(applicationId, channel);
|
||||
const clazz = await (0, payClazz_1.getPayClazz)(applicationId, channel, context);
|
||||
const iState = await clazz.getState(pay);
|
||||
if (iState !== pay.iState) {
|
||||
let action = 'close';
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ import { EntityDict } from '@oak-app-domain';
|
|||
import { Checker } from 'oak-domain/lib/types';
|
||||
import { RuntimeCxt } from '../types/RuntimeCxt';
|
||||
import aoCheckers from './accountOper';
|
||||
import payCheckers from './pay';
|
||||
|
||||
const checkers = [
|
||||
...aoCheckers,
|
||||
...payCheckers,
|
||||
] as Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
|
||||
|
||||
export default checkers;
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import { AccountPayConfig, OfflinePayConfig,
|
||||
PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME } from '../../../types/PayConfig';
|
||||
export default OakComponent({
|
||||
properties: {
|
||||
depositMax: 10000,
|
||||
onSetPrice: (price: null | number) => undefined as void,
|
||||
onSetChannel: (channel: string) => undefined as void,
|
||||
onSetMeta: (meta: any) => undefined as void,
|
||||
price: null as number | null,
|
||||
channel: '',
|
||||
meta: {} as any,
|
||||
},
|
||||
formData({ data }) {
|
||||
const payConfig2 = this.features.pay.getPayConfigs();
|
||||
let accountConfig: AccountPayConfig | undefined;
|
||||
const payConfig: typeof payConfig2 = [];
|
||||
for (const config of payConfig2) {
|
||||
if (config.channel === PAY_CHANNEL_ACCOUNT_NAME) {
|
||||
accountConfig = config;
|
||||
}
|
||||
else if (config.channel !== PAY_CHANNEL_OFFLINE_NAME || (<OfflinePayConfig>config).allowUser) {
|
||||
payConfig.push(config);
|
||||
}
|
||||
}
|
||||
return {
|
||||
account: data,
|
||||
payConfig,
|
||||
// accountConfig,
|
||||
};
|
||||
},
|
||||
features: ['application'],
|
||||
})
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"placeholder": "一次最大充值%{max}元",
|
||||
"label": {
|
||||
"depPrice": "充值金额",
|
||||
"channel": "充值渠道"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Form, InputNumber } from 'antd';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '@project/oak-app-domain';
|
||||
import ChannelPicker from '../../pay/channelPicker';
|
||||
import { AccountPayConfig, PayConfig } from '@project/types/PayConfig';
|
||||
|
||||
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'account', false, {
|
||||
depositMax: number;
|
||||
payConfig: PayConfig;
|
||||
accountConfig?: AccountPayConfig;
|
||||
onSetPrice: (price: null | number) => void;
|
||||
onSetChannel: (channel: string) => void;
|
||||
onSetMeta: (meta: any) => void;
|
||||
price: number;
|
||||
channel: string;
|
||||
meta: any;
|
||||
}>) {
|
||||
const { depositMax, payConfig, price, channel, meta,
|
||||
onSetChannel, onSetMeta, onSetPrice } = props.data;
|
||||
const { t } = props.methods;
|
||||
|
||||
if (payConfig) {
|
||||
|
||||
return (
|
||||
<Form
|
||||
labelCol={{ span: 4 }}
|
||||
wrapperCol={{ span: 14 }}
|
||||
layout="horizontal"
|
||||
style={{ minWidth: 600 }}
|
||||
colon={false}
|
||||
>
|
||||
<Form.Item label={<span>{t("label.depPrice")}:</span>}>
|
||||
<InputNumber
|
||||
placeholder={t('placeholder', { max: depositMax })}
|
||||
max={depositMax}
|
||||
min={1}
|
||||
value={price}
|
||||
addonAfter={t('common::pay.symbol')}
|
||||
onChange={(value) => {
|
||||
onSetPrice(value);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label={<span style={{ marginTop: 10 }}>
|
||||
{t('label.channel')}:
|
||||
</span>}>
|
||||
<ChannelPicker
|
||||
payConfig={payConfig}
|
||||
onPick={(channel) => {
|
||||
onSetChannel(channel);
|
||||
}}
|
||||
channel={channel}
|
||||
meta={meta}
|
||||
onSetMeta={(meta) => onSetMeta(meta)}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import React, { useState } from 'react';
|
||||
import { WebComponentProps } from 'oak-frontend-base';
|
||||
import { EntityDict } from '@project/oak-app-domain';
|
||||
import ChannelPicker from '../../pay/channelPicker';
|
||||
import { AccountPayConfig, PayConfig } from '@project/types/PayConfig';
|
||||
|
||||
|
||||
export default function Render(props: WebComponentProps<EntityDict, 'account', false, {
|
||||
depositMax: number;
|
||||
payConfig: PayConfig;
|
||||
accountConfig?: AccountPayConfig;
|
||||
}>) {
|
||||
const { depositMax, payConfig } = props.data;
|
||||
const { t } = props.methods;
|
||||
|
||||
const [depPrice, setDepPrice] = useState<null | number>(null);
|
||||
const [depositChannel, setDepositChannel] = useState<string | undefined>();
|
||||
const [depositMeta, setDepositMeta] = useState<any>();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
import { generateNewIdAsync } from "oak-domain/lib/utils/uuid";
|
||||
|
||||
export default OakComponent({
|
||||
entity: 'account',
|
||||
isList: false,
|
||||
projection: {
|
||||
id: 1,
|
||||
total: 1,
|
||||
avail: 1,
|
||||
systemId: 1,
|
||||
entity: 1,
|
||||
entityId: 1,
|
||||
},
|
||||
properties: {
|
||||
depositMax: 10000,
|
||||
onDeposit: (payId: string) => undefined as void,
|
||||
},
|
||||
formData({ data }) {
|
||||
return {
|
||||
account: data,
|
||||
};
|
||||
},
|
||||
actions: ['deposit', 'withdraw'],
|
||||
methods: {
|
||||
async deposit(price: number, channel: string, meta: object, success: () => void) {
|
||||
const payId = await generateNewIdAsync();
|
||||
const { onDeposit, oakId } = this.props;
|
||||
await this.execute(undefined, undefined, undefined, [
|
||||
{
|
||||
entity: 'account',
|
||||
operation: {
|
||||
id: await generateNewIdAsync(),
|
||||
action: 'deposit',
|
||||
data: {
|
||||
pay$account: {
|
||||
id: await generateNewIdAsync(),
|
||||
action: 'create',
|
||||
data: {
|
||||
id: payId,
|
||||
channel,
|
||||
price,
|
||||
meta,
|
||||
},
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
id: oakId!,
|
||||
}
|
||||
},
|
||||
}
|
||||
]);
|
||||
success();
|
||||
onDeposit && onDeposit(payId);
|
||||
}
|
||||
}
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue