编写了大量支付相关的逻辑
This commit is contained in:
parent
288426babb
commit
f9166d1c9c
|
|
@ -1,5 +1,7 @@
|
||||||
import aoCheckers from './accountOper';
|
import aoCheckers from './accountOper';
|
||||||
|
import payCheckers from './pay';
|
||||||
const checkers = [
|
const checkers = [
|
||||||
...aoCheckers,
|
...aoCheckers,
|
||||||
|
...payCheckers,
|
||||||
];
|
];
|
||||||
export default checkers;
|
export default checkers;
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,11 @@ declare const List: <T extends keyof EntityDict>(props: ReactComponentProps<Enti
|
||||||
type: "checkbox" | "radio";
|
type: "checkbox" | "radio";
|
||||||
selectedRowKeys?: string[] | undefined;
|
selectedRowKeys?: string[] | undefined;
|
||||||
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
|
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
|
||||||
type: "multiple" | "none" | "single";
|
type: "multiple" | "single" | "none";
|
||||||
} | undefined) => void;
|
} | undefined) => void;
|
||||||
} | undefined;
|
} | undefined;
|
||||||
hideHeader: boolean;
|
hideHeader: boolean;
|
||||||
size?: "small" | "middle" | "large" | undefined;
|
size?: "small" | "large" | "middle" | undefined;
|
||||||
scroll?: any;
|
scroll?: any;
|
||||||
locale?: any;
|
locale?: any;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
|
|
@ -47,11 +47,11 @@ declare const ListPro: <T extends keyof EntityDict>(props: {
|
||||||
type: "checkbox" | "radio";
|
type: "checkbox" | "radio";
|
||||||
selectedRowKeys?: string[] | undefined;
|
selectedRowKeys?: string[] | undefined;
|
||||||
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
|
onChange: (selectedRowKeys: string[], row: RowWithActions<EntityDict, T>[], info?: {
|
||||||
type: "multiple" | "none" | "single";
|
type: "multiple" | "single" | "none";
|
||||||
} | undefined) => void;
|
} | undefined) => void;
|
||||||
} | undefined;
|
} | undefined;
|
||||||
disableSerialNumber?: boolean | undefined;
|
disableSerialNumber?: boolean | undefined;
|
||||||
size?: "small" | "middle" | "large" | undefined;
|
size?: "small" | "large" | "middle" | undefined;
|
||||||
scroll?: any;
|
scroll?: any;
|
||||||
locale?: any;
|
locale?: any;
|
||||||
}) => React.ReactElement;
|
}) => React.ReactElement;
|
||||||
|
|
@ -62,14 +62,14 @@ declare const Detail: <T extends keyof EntityDict>(props: ReactComponentProps<En
|
||||||
data: Partial<EntityDict[T]["Schema"]>;
|
data: Partial<EntityDict[T]["Schema"]>;
|
||||||
title?: string | undefined;
|
title?: string | undefined;
|
||||||
bordered?: boolean | undefined;
|
bordered?: boolean | undefined;
|
||||||
layout?: "vertical" | "horizontal" | undefined;
|
layout?: "horizontal" | "vertical" | undefined;
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
declare const Upsert: <T extends keyof EntityDict>(props: ReactComponentProps<EntityDict, T, false, {
|
declare const Upsert: <T extends keyof EntityDict>(props: ReactComponentProps<EntityDict, T, false, {
|
||||||
helps: Record<string, string>;
|
helps: Record<string, string>;
|
||||||
entity: T;
|
entity: T;
|
||||||
attributes: OakAbsAttrUpsertDef<EntityDict, T, string | number>[];
|
attributes: OakAbsAttrUpsertDef<EntityDict, T, string | number>[];
|
||||||
data: EntityDict[T]["Schema"];
|
data: EntityDict[T]["Schema"];
|
||||||
layout: "vertical" | "horizontal";
|
layout: "horizontal" | "vertical";
|
||||||
mode: "default" | "card";
|
mode: "default" | "card";
|
||||||
}>) => React.ReactElement;
|
}>) => React.ReactElement;
|
||||||
export { FilterPanel, List, ListPro, Detail, Upsert, ReactComponentProps, ColumnProps, RowWithActions, OakExtraActionProps, OakAbsAttrDef, onActionFnDef, };
|
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,14 +87,16 @@ export default function render(props) {
|
||||||
]} onTabClick={(activeKey) => {
|
]} onTabClick={(activeKey) => {
|
||||||
if (key && operation) {
|
if (key && operation) {
|
||||||
const { application$system } = operation.data;
|
const { application$system } = operation.data;
|
||||||
const { filter } = application$system;
|
if (application$system) {
|
||||||
if (filter?.id === key) {
|
const { filter } = application$system;
|
||||||
setMessage({
|
if (filter?.id === key) {
|
||||||
type: 'warning',
|
setMessage({
|
||||||
content: t('mayLossUpdate', {
|
type: 'warning',
|
||||||
name: applications?.find(ele => ele.id === key).name
|
content: t('mayLossUpdate', {
|
||||||
}),
|
name: applications?.find(ele => ele.id === key).name
|
||||||
});
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setKey(activeKey);
|
setKey(activeKey);
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,9 @@ export default function Offline(props) {
|
||||||
};
|
};
|
||||||
return (<div className={Styles.container}>
|
return (<div className={Styles.container}>
|
||||||
<Alert type='info' message={t('tips')}/>
|
<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')}>
|
<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.map((option, idx) => <Tag bordered={false} closable key={idx} onClose={() => {
|
||||||
options.splice(idx, 1);
|
options.splice(idx, 1);
|
||||||
update({
|
update({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,48 @@
|
||||||
// 本文件为自动编译产生,请勿直接修改
|
// 本文件为自动编译产生,请勿直接修改
|
||||||
const i18ns = [
|
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",
|
id: "548c6f23c4d08f495b6eed1b757aceb5",
|
||||||
namespace: "oak-pay-business-c-payConfig-system",
|
namespace: "oak-pay-business-c-payConfig-system",
|
||||||
|
|
@ -116,7 +159,11 @@ const i18ns = [
|
||||||
"close": "关",
|
"close": "关",
|
||||||
"enter": "请输入",
|
"enter": "请输入",
|
||||||
"change": "修改",
|
"change": "修改",
|
||||||
"finish": "完成"
|
"finish": "完成",
|
||||||
|
"pay": {
|
||||||
|
"symbol": "¥",
|
||||||
|
"scale": "元"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -126,13 +173,13 @@ const i18ns = [
|
||||||
module: "oak-pay-business",
|
module: "oak-pay-business",
|
||||||
position: "locales/payChannel",
|
position: "locales/payChannel",
|
||||||
data: {
|
data: {
|
||||||
"ACCOUNT": "系统内帐户",
|
"ACCOUNT": "系统帐户",
|
||||||
"OFFLINE": "系统外支付",
|
"OFFLINE": "线下支付",
|
||||||
"WECHAT_JS": "微信支付JS",
|
"WECHAT_JS": "微信支付",
|
||||||
"WECHAT_MP": "微信小程序",
|
"WECHAT_MP": "微信支付",
|
||||||
"WECHAT_NATIVE": "微信Native",
|
"WECHAT_NATIVE": "微信支付",
|
||||||
"WECHAT_H5": "微信H5",
|
"WECHAT_H5": "微信支付",
|
||||||
"WECHAT_APP": "微信APP"
|
"WECHAT_APP": "微信支付"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export interface Schema extends EntityShape {
|
||||||
timeoutAt: Datetime;
|
timeoutAt: Datetime;
|
||||||
}
|
}
|
||||||
type IAction = 'startPaying' | 'payAll' | 'payPartially' | 'payNone' | 'timeout' | 'cancel' | 'startRefunding' | 'refundAll' | 'refundPartially' | 'refundNone';
|
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>;
|
export declare const IActionDef: ActionDef<IAction, IState>;
|
||||||
type Action = IAction;
|
type Action = IAction;
|
||||||
export declare const entityDesc: EntityDesc<Schema, Action, '', {
|
export declare const entityDesc: EntityDesc<Schema, Action, '', {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,18 @@
|
||||||
;
|
;
|
||||||
export const IActionDef = {
|
export const IActionDef = {
|
||||||
stm: {
|
stm: {
|
||||||
startPaying: ['unPaid', 'paying'],
|
startPaying: ['unpaid', 'paying'],
|
||||||
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
|
payAll: [['unpaid', 'paying', 'partiallyPaid'], 'paid'],
|
||||||
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
|
payPartially: [['unpaid', 'paying'], 'partiallyPaid'],
|
||||||
payNone: ['paying', 'unPaid'],
|
payNone: ['paying', 'unpaid'],
|
||||||
timeout: ['unPaid', 'timeout'],
|
timeout: ['unpaid', 'timeout'],
|
||||||
cancel: ['unPaid', 'cancelled'],
|
cancel: ['unpaid', 'cancelled'],
|
||||||
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
||||||
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
||||||
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
||||||
refundNone: ['refunding', 'paid'],
|
refundNone: ['refunding', 'paid'],
|
||||||
},
|
},
|
||||||
is: 'unPaid',
|
is: 'unpaid',
|
||||||
};
|
};
|
||||||
export const entityDesc = {
|
export const entityDesc = {
|
||||||
indexes: [
|
indexes: [
|
||||||
|
|
@ -55,7 +55,7 @@ export const entityDesc = {
|
||||||
paid: '已付款',
|
paid: '已付款',
|
||||||
partiallyPaid: '部分支付',
|
partiallyPaid: '部分支付',
|
||||||
paying: '支付中',
|
paying: '支付中',
|
||||||
unPaid: '待付款',
|
unpaid: '待付款',
|
||||||
timeout: '已超时',
|
timeout: '已超时',
|
||||||
cancelled: '已取消',
|
cancelled: '已取消',
|
||||||
refunded: '已退款',
|
refunded: '已退款',
|
||||||
|
|
@ -80,7 +80,7 @@ export const entityDesc = {
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
iState: {
|
iState: {
|
||||||
unPaid: '#52BE80',
|
unpaid: '#52BE80',
|
||||||
partiallyPaid: '#5DADE2',
|
partiallyPaid: '#5DADE2',
|
||||||
cancelled: '#D6DBDF',
|
cancelled: '#D6DBDF',
|
||||||
paid: '#2E86C1',
|
paid: '#2E86C1',
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export interface Schema extends EntityShape {
|
||||||
paid: Price;
|
paid: Price;
|
||||||
refunded: Price;
|
refunded: Price;
|
||||||
channel: String<32>;
|
channel: String<32>;
|
||||||
timeoutAt: Datetime;
|
timeoutAt?: Datetime;
|
||||||
forbidRefundAt?: Datetime;
|
forbidRefundAt?: Datetime;
|
||||||
account?: Account;
|
account?: Account;
|
||||||
order?: Order;
|
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 { EntityDict } from '../oak-app-domain';
|
||||||
|
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
|
||||||
import { BasicFeatures } from 'oak-frontend-base';
|
import { BasicFeatures } from 'oak-frontend-base';
|
||||||
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business";
|
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business";
|
||||||
export declare function create<ED extends EntityDict>(features: BasicFeatures<ED> & Ogb0FeatureDict<ED>): {};
|
import Cos from 'oak-general-business/es/types/Cos';
|
||||||
export type FeatureDict<ED extends EntityDict> = {};
|
import Pay from './Pay';
|
||||||
export declare function initialize<ED extends EntityDict>(features: FeatureDict<ED> & BasicFeatures<ED> & Ogb0FeatureDict<ED>): Promise<void>;
|
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) {
|
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": "关",
|
"close": "关",
|
||||||
"enter": "请输入",
|
"enter": "请输入",
|
||||||
"change": "修改",
|
"change": "修改",
|
||||||
"finish": "完成"
|
"finish": "完成",
|
||||||
|
"pay": {
|
||||||
|
"symbol": "¥",
|
||||||
|
"scale": "元"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"ACCOUNT": "系统内帐户",
|
"ACCOUNT": "系统帐户",
|
||||||
"OFFLINE": "系统外支付",
|
"OFFLINE": "线下支付",
|
||||||
"WECHAT_JS": "微信支付JS",
|
"WECHAT_JS": "微信支付",
|
||||||
"WECHAT_MP": "微信小程序",
|
"WECHAT_MP": "微信支付",
|
||||||
"WECHAT_NATIVE": "微信Native",
|
"WECHAT_NATIVE": "微信支付",
|
||||||
"WECHAT_H5": "微信H5",
|
"WECHAT_H5": "微信支付",
|
||||||
"WECHAT_APP": "微信APP"
|
"WECHAT_APP": "微信支付"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,16 +93,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "relationId" | "
|
||||||
} | {
|
} | {
|
||||||
relation?: never;
|
relation?: never;
|
||||||
relationId?: ForeignKey<"relation">;
|
relationId?: ForeignKey<"relation">;
|
||||||
}) & ({
|
}) & {
|
||||||
pathId?: never;
|
|
||||||
path: Path.CreateSingleOperation;
|
|
||||||
} | {
|
|
||||||
pathId: ForeignKey<"path">;
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId: ForeignKey<"path">;
|
pathId: ForeignKey<"path">;
|
||||||
}));
|
});
|
||||||
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
||||||
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
||||||
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
||||||
|
|
@ -118,26 +112,15 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "relationId" | "
|
||||||
} | {
|
} | {
|
||||||
relation?: never;
|
relation?: never;
|
||||||
relationId?: ForeignKey<"relation"> | null;
|
relationId?: ForeignKey<"relation"> | null;
|
||||||
}) & ({
|
}) & {
|
||||||
path?: Path.CreateSingleOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.RemoveOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId?: ForeignKey<"path">;
|
pathId?: ForeignKey<"path">;
|
||||||
})) & {
|
}) & {
|
||||||
[k: string]: any;
|
[k: string]: any;
|
||||||
};
|
};
|
||||||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||||
export type RemoveOperationData = {} & (({
|
export type RemoveOperationData = {} & (({
|
||||||
relation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
relation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||||
}) & ({
|
|
||||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
|
||||||
}));
|
}));
|
||||||
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
||||||
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { ActionDef } from "oak-domain/lib/types/Action";
|
import { ActionDef } from "oak-domain/lib/types/Action";
|
||||||
import { GenericAction } from "oak-domain/lib/actions/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 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 declare const IActionDef: ActionDef<IAction, IState>;
|
||||||
export type ParticularAction = IAction;
|
export type ParticularAction = IAction;
|
||||||
export declare const actions: string[];
|
export declare const actions: string[];
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
export const IActionDef = {
|
export const IActionDef = {
|
||||||
stm: {
|
stm: {
|
||||||
startPaying: ['unPaid', 'paying'],
|
startPaying: ['unpaid', 'paying'],
|
||||||
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
|
payAll: [['unpaid', 'paying', 'partiallyPaid'], 'paid'],
|
||||||
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
|
payPartially: [['unpaid', 'paying'], 'partiallyPaid'],
|
||||||
payNone: ['paying', 'unPaid'],
|
payNone: ['paying', 'unpaid'],
|
||||||
timeout: ['unPaid', 'timeout'],
|
timeout: ['unpaid', 'timeout'],
|
||||||
cancel: ['unPaid', 'cancelled'],
|
cancel: ['unpaid', 'cancelled'],
|
||||||
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
||||||
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
||||||
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
||||||
refundNone: ['refunding', 'paid'],
|
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 actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "startPaying", "payAll", "payPartially", "payNone", "timeout", "cancel", "startRefunding", "refundAll", "refundPartially", "refundNone"];
|
||||||
export const actionDefDict = {
|
export const actionDefDict = {
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export const desc = {
|
||||||
},
|
},
|
||||||
iState: {
|
iState: {
|
||||||
type: "enum",
|
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",
|
actionType: "crud",
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const style = {
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
iState: {
|
iState: {
|
||||||
unPaid: '#52BE80',
|
unpaid: '#52BE80',
|
||||||
partiallyPaid: '#5DADE2',
|
partiallyPaid: '#5DADE2',
|
||||||
cancelled: '#D6DBDF',
|
cancelled: '#D6DBDF',
|
||||||
paid: '#2E86C1',
|
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",
|
actionType: "crud",
|
||||||
actions,
|
actions,
|
||||||
indexes: [
|
indexes: [
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export type OpSchema = EntityShape & {
|
||||||
paid: Price;
|
paid: Price;
|
||||||
refunded: Price;
|
refunded: Price;
|
||||||
channel: String<32>;
|
channel: String<32>;
|
||||||
timeoutAt: Datetime;
|
timeoutAt?: Datetime | null;
|
||||||
forbidRefundAt?: Datetime | null;
|
forbidRefundAt?: Datetime | null;
|
||||||
accountId?: ForeignKey<"account"> | null;
|
accountId?: ForeignKey<"account"> | null;
|
||||||
orderId?: ForeignKey<"order"> | null;
|
orderId?: ForeignKey<"order"> | null;
|
||||||
|
|
@ -32,7 +32,7 @@ export type Schema = EntityShape & {
|
||||||
paid: Price;
|
paid: Price;
|
||||||
refunded: Price;
|
refunded: Price;
|
||||||
channel: String<32>;
|
channel: String<32>;
|
||||||
timeoutAt: Datetime;
|
timeoutAt?: Datetime | null;
|
||||||
forbidRefundAt?: Datetime | null;
|
forbidRefundAt?: Datetime | null;
|
||||||
accountId?: ForeignKey<"account"> | null;
|
accountId?: ForeignKey<"account"> | null;
|
||||||
orderId?: ForeignKey<"order"> | null;
|
orderId?: ForeignKey<"order"> | null;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ export const desc = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
timeoutAt: {
|
timeoutAt: {
|
||||||
notNull: true,
|
|
||||||
type: "datetime"
|
type: "datetime"
|
||||||
},
|
},
|
||||||
forbidRefundAt: {
|
forbidRefundAt: {
|
||||||
|
|
|
||||||
|
|
@ -98,16 +98,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "sourceRelationI
|
||||||
} | {
|
} | {
|
||||||
sourceRelation?: never;
|
sourceRelation?: never;
|
||||||
sourceRelationId: ForeignKey<"sourceRelation">;
|
sourceRelationId: ForeignKey<"sourceRelation">;
|
||||||
}) & ({
|
}) & {
|
||||||
pathId?: never;
|
|
||||||
path: Path.CreateSingleOperation;
|
|
||||||
} | {
|
|
||||||
pathId: ForeignKey<"path">;
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId: ForeignKey<"path">;
|
pathId: ForeignKey<"path">;
|
||||||
}) & ({
|
} & ({
|
||||||
destRelationId?: never;
|
destRelationId?: never;
|
||||||
destRelation: Relation.CreateSingleOperation;
|
destRelation: Relation.CreateSingleOperation;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -132,19 +126,10 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
||||||
} | {
|
} | {
|
||||||
sourceRelation?: never;
|
sourceRelation?: never;
|
||||||
sourceRelationId?: ForeignKey<"sourceRelation">;
|
sourceRelationId?: ForeignKey<"sourceRelation">;
|
||||||
}) & ({
|
}) & {
|
||||||
path?: Path.CreateSingleOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.RemoveOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId?: ForeignKey<"path">;
|
pathId?: ForeignKey<"path">;
|
||||||
}) & ({
|
} & ({
|
||||||
destRelation?: Relation.CreateSingleOperation;
|
destRelation?: Relation.CreateSingleOperation;
|
||||||
destRelationId?: never;
|
destRelationId?: never;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -162,8 +147,6 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
||||||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||||
export type RemoveOperationData = {} & (({
|
export type RemoveOperationData = {} & (({
|
||||||
sourceRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
sourceRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||||
}) & ({
|
|
||||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
|
||||||
}) & ({
|
}) & ({
|
||||||
destRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
destRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,7 @@ const triggers = [
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
action: ['startPaying'],
|
action: ['startPaying'],
|
||||||
when: 'before',
|
when: 'before',
|
||||||
|
priority: 99,
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { data, filter } = operation;
|
const { data, filter } = operation;
|
||||||
const pays = await context.select('pay', {
|
const pays = await context.select('pay', {
|
||||||
|
|
@ -244,14 +245,9 @@ const triggers = [
|
||||||
const [pay] = pays;
|
const [pay] = pays;
|
||||||
const { applicationId, channel, iState } = pay;
|
const { applicationId, channel, iState } = pay;
|
||||||
assert(iState === 'unpaid');
|
assert(iState === 'unpaid');
|
||||||
if (![PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME].includes(channel)) {
|
const payClazz = await getPayClazz(applicationId, channel, context);
|
||||||
const payClazz = getPayClazz(applicationId, channel);
|
await payClazz.prepay(pay, data, context);
|
||||||
const [prePayId, meta] = await payClazz.prepay(pay);
|
return 1;
|
||||||
data.externalId = prePayId;
|
|
||||||
data.meta = meta;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -270,7 +266,7 @@ const triggers = [
|
||||||
const { applicationId, channel, iState, externalId } = pay;
|
const { applicationId, channel, iState, externalId } = pay;
|
||||||
assert(iState === 'unpaid' || iState === 'paying');
|
assert(iState === 'unpaid' || iState === 'paying');
|
||||||
if (iState === 'paying' && externalId && ![PAY_CHANNEL_ACCOUNT_NAME, PAY_CHANNEL_OFFLINE_NAME].includes(channel)) {
|
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);
|
await payClazz.close(pay);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
|
import { BRC } from '../types/RuntimeCxt';
|
||||||
type IState = EntityDict['pay']['OpSchema']['iState'];
|
type IState = EntityDict['pay']['OpSchema']['iState'];
|
||||||
export default interface PayClazz {
|
export default interface PayClazz {
|
||||||
type: string;
|
channel: string;
|
||||||
prepay(pay: EntityDict['pay']['OpSchema']): Promise<[string, object]>;
|
prepay(pay: EntityDict['pay']['OpSchema'], data: EntityDict['pay']['Update']['data'], context: BRC): Promise<void>;
|
||||||
getState(pay: EntityDict['pay']['OpSchema']): Promise<IState>;
|
getState(pay: EntityDict['pay']['OpSchema']): Promise<IState>;
|
||||||
close(pay: EntityDict['pay']['OpSchema']): Promise<void>;
|
close(pay: EntityDict['pay']['OpSchema']): Promise<void>;
|
||||||
decodeNotification(params: Record<string, string>, body: any): Promise<Array<{
|
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';
|
import PayClazz from '../../types/PayClazz';
|
||||||
export declare function registerPayClazz(appId: string, channel: string, clazz: PayClazz): void;
|
import { BRC } from '../../types/RuntimeCxt';
|
||||||
export declare function getPayClazz(appId: string, channel: string): PayClazz;
|
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 assert from 'assert';
|
||||||
|
import Offline from './Offline';
|
||||||
|
import Account from './Account';
|
||||||
const PayChannelDict = {};
|
const PayChannelDict = {};
|
||||||
export function registerPayClazz(appId, channel, clazz) {
|
const PayClazzConstructorDict = {
|
||||||
const key = `${appId}.${channel}`;
|
[PAY_CHANNEL_OFFLINE_NAME]: async () => new Offline(),
|
||||||
assert(!PayChannelDict.hasOwnProperty(key));
|
[PAY_CHANNEL_ACCOUNT_NAME]: async () => new Account(),
|
||||||
PayChannelDict[key] = clazz;
|
};
|
||||||
|
export function registerAppPayClazzConstructor(channel, constructor) {
|
||||||
|
PayClazzConstructorDict[channel] = constructor;
|
||||||
}
|
}
|
||||||
export function getPayClazz(appId, channel) {
|
export async function getPayClazz(appId, channel, context) {
|
||||||
const key = `${appId}.${channel}`;
|
const key = `${appId}.${channel}`;
|
||||||
assert(PayChannelDict.hasOwnProperty(key));
|
if (PayChannelDict.hasOwnProperty(key)) {
|
||||||
return PayChannelDict[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 = [];
|
const results = [];
|
||||||
for (const pay of data) {
|
for (const pay of data) {
|
||||||
const { applicationId, channel, timeoutAt } = pay;
|
const { applicationId, channel, timeoutAt } = pay;
|
||||||
const clazz = getPayClazz(applicationId, channel);
|
const clazz = await getPayClazz(applicationId, channel, context);
|
||||||
const iState = await clazz.getState(pay);
|
const iState = await clazz.getState(pay);
|
||||||
if (iState !== pay.iState) {
|
if (iState !== pay.iState) {
|
||||||
let action = 'close';
|
let action = 'close';
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const tslib_1 = require("tslib");
|
const tslib_1 = require("tslib");
|
||||||
const accountOper_1 = tslib_1.__importDefault(require("./accountOper"));
|
const accountOper_1 = tslib_1.__importDefault(require("./accountOper"));
|
||||||
|
const pay_1 = tslib_1.__importDefault(require("./pay"));
|
||||||
const checkers = [
|
const checkers = [
|
||||||
...accountOper_1.default,
|
...accountOper_1.default,
|
||||||
|
...pay_1.default,
|
||||||
];
|
];
|
||||||
exports.default = checkers;
|
exports.default = checkers;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,49 @@
|
||||||
// 本文件为自动编译产生,请勿直接修改
|
// 本文件为自动编译产生,请勿直接修改
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const i18ns = [
|
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",
|
id: "548c6f23c4d08f495b6eed1b757aceb5",
|
||||||
namespace: "oak-pay-business-c-payConfig-system",
|
namespace: "oak-pay-business-c-payConfig-system",
|
||||||
|
|
@ -118,7 +161,11 @@ const i18ns = [
|
||||||
"close": "关",
|
"close": "关",
|
||||||
"enter": "请输入",
|
"enter": "请输入",
|
||||||
"change": "修改",
|
"change": "修改",
|
||||||
"finish": "完成"
|
"finish": "完成",
|
||||||
|
"pay": {
|
||||||
|
"symbol": "¥",
|
||||||
|
"scale": "元"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -128,13 +175,13 @@ const i18ns = [
|
||||||
module: "oak-pay-business",
|
module: "oak-pay-business",
|
||||||
position: "locales/payChannel",
|
position: "locales/payChannel",
|
||||||
data: {
|
data: {
|
||||||
"ACCOUNT": "系统内帐户",
|
"ACCOUNT": "系统帐户",
|
||||||
"OFFLINE": "系统外支付",
|
"OFFLINE": "线下支付",
|
||||||
"WECHAT_JS": "微信支付JS",
|
"WECHAT_JS": "微信支付",
|
||||||
"WECHAT_MP": "微信小程序",
|
"WECHAT_MP": "微信支付",
|
||||||
"WECHAT_NATIVE": "微信Native",
|
"WECHAT_NATIVE": "微信支付",
|
||||||
"WECHAT_H5": "微信H5",
|
"WECHAT_H5": "微信支付",
|
||||||
"WECHAT_APP": "微信APP"
|
"WECHAT_APP": "微信支付"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export interface Schema extends EntityShape {
|
||||||
timeoutAt: Datetime;
|
timeoutAt: Datetime;
|
||||||
}
|
}
|
||||||
type IAction = 'startPaying' | 'payAll' | 'payPartially' | 'payNone' | 'timeout' | 'cancel' | 'startRefunding' | 'refundAll' | 'refundPartially' | 'refundNone';
|
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>;
|
export declare const IActionDef: ActionDef<IAction, IState>;
|
||||||
type Action = IAction;
|
type Action = IAction;
|
||||||
export declare const entityDesc: EntityDesc<Schema, Action, '', {
|
export declare const entityDesc: EntityDesc<Schema, Action, '', {
|
||||||
|
|
|
||||||
|
|
@ -4,18 +4,18 @@ exports.entityDesc = exports.IActionDef = void 0;
|
||||||
;
|
;
|
||||||
exports.IActionDef = {
|
exports.IActionDef = {
|
||||||
stm: {
|
stm: {
|
||||||
startPaying: ['unPaid', 'paying'],
|
startPaying: ['unpaid', 'paying'],
|
||||||
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
|
payAll: [['unpaid', 'paying', 'partiallyPaid'], 'paid'],
|
||||||
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
|
payPartially: [['unpaid', 'paying'], 'partiallyPaid'],
|
||||||
payNone: ['paying', 'unPaid'],
|
payNone: ['paying', 'unpaid'],
|
||||||
timeout: ['unPaid', 'timeout'],
|
timeout: ['unpaid', 'timeout'],
|
||||||
cancel: ['unPaid', 'cancelled'],
|
cancel: ['unpaid', 'cancelled'],
|
||||||
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
||||||
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
||||||
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
||||||
refundNone: ['refunding', 'paid'],
|
refundNone: ['refunding', 'paid'],
|
||||||
},
|
},
|
||||||
is: 'unPaid',
|
is: 'unpaid',
|
||||||
};
|
};
|
||||||
exports.entityDesc = {
|
exports.entityDesc = {
|
||||||
indexes: [
|
indexes: [
|
||||||
|
|
@ -58,7 +58,7 @@ exports.entityDesc = {
|
||||||
paid: '已付款',
|
paid: '已付款',
|
||||||
partiallyPaid: '部分支付',
|
partiallyPaid: '部分支付',
|
||||||
paying: '支付中',
|
paying: '支付中',
|
||||||
unPaid: '待付款',
|
unpaid: '待付款',
|
||||||
timeout: '已超时',
|
timeout: '已超时',
|
||||||
cancelled: '已取消',
|
cancelled: '已取消',
|
||||||
refunded: '已退款',
|
refunded: '已退款',
|
||||||
|
|
@ -83,7 +83,7 @@ exports.entityDesc = {
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
iState: {
|
iState: {
|
||||||
unPaid: '#52BE80',
|
unpaid: '#52BE80',
|
||||||
partiallyPaid: '#5DADE2',
|
partiallyPaid: '#5DADE2',
|
||||||
cancelled: '#D6DBDF',
|
cancelled: '#D6DBDF',
|
||||||
paid: '#2E86C1',
|
paid: '#2E86C1',
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export interface Schema extends EntityShape {
|
||||||
paid: Price;
|
paid: Price;
|
||||||
refunded: Price;
|
refunded: Price;
|
||||||
channel: String<32>;
|
channel: String<32>;
|
||||||
timeoutAt: Datetime;
|
timeoutAt?: Datetime;
|
||||||
forbidRefundAt?: Datetime;
|
forbidRefundAt?: Datetime;
|
||||||
account?: Account;
|
account?: Account;
|
||||||
order?: Order;
|
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 { EntityDict } from '../oak-app-domain';
|
||||||
|
import { AccessConfiguration } from 'oak-domain/lib/types/Configuration';
|
||||||
import { BasicFeatures } from 'oak-frontend-base';
|
import { BasicFeatures } from 'oak-frontend-base';
|
||||||
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business";
|
import { FeatureDict as Ogb0FeatureDict } from "oak-general-business";
|
||||||
export declare function create<ED extends EntityDict>(features: BasicFeatures<ED> & Ogb0FeatureDict<ED>): {};
|
import Cos from 'oak-general-business/es/types/Cos';
|
||||||
export type FeatureDict<ED extends EntityDict> = {};
|
import Pay from './Pay';
|
||||||
export declare function initialize<ED extends EntityDict>(features: FeatureDict<ED> & BasicFeatures<ED> & Ogb0FeatureDict<ED>): Promise<void>;
|
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";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.initialize = exports.create = void 0;
|
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) {
|
function create(features) {
|
||||||
return {};
|
const pay = new Pay_1.default(features.application);
|
||||||
|
return {
|
||||||
|
pay,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
exports.create = create;
|
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;
|
exports.initialize = initialize;
|
||||||
|
|
|
||||||
|
|
@ -45,5 +45,9 @@
|
||||||
"close": "关",
|
"close": "关",
|
||||||
"enter": "请输入",
|
"enter": "请输入",
|
||||||
"change": "修改",
|
"change": "修改",
|
||||||
"finish": "完成"
|
"finish": "完成",
|
||||||
|
"pay": {
|
||||||
|
"symbol": "¥",
|
||||||
|
"scale": "元"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
{
|
{
|
||||||
"ACCOUNT": "系统内帐户",
|
"ACCOUNT": "系统帐户",
|
||||||
"OFFLINE": "系统外支付",
|
"OFFLINE": "线下支付",
|
||||||
"WECHAT_JS": "微信支付JS",
|
"WECHAT_JS": "微信支付",
|
||||||
"WECHAT_MP": "微信小程序",
|
"WECHAT_MP": "微信支付",
|
||||||
"WECHAT_NATIVE": "微信Native",
|
"WECHAT_NATIVE": "微信支付",
|
||||||
"WECHAT_H5": "微信H5",
|
"WECHAT_H5": "微信支付",
|
||||||
"WECHAT_APP": "微信APP"
|
"WECHAT_APP": "微信支付"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,16 +93,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "relationId" | "
|
||||||
} | {
|
} | {
|
||||||
relation?: never;
|
relation?: never;
|
||||||
relationId?: ForeignKey<"relation">;
|
relationId?: ForeignKey<"relation">;
|
||||||
}) & ({
|
}) & {
|
||||||
pathId?: never;
|
|
||||||
path: Path.CreateSingleOperation;
|
|
||||||
} | {
|
|
||||||
pathId: ForeignKey<"path">;
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId: ForeignKey<"path">;
|
pathId: ForeignKey<"path">;
|
||||||
}));
|
});
|
||||||
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
export type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
|
||||||
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
export type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
|
||||||
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
export type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
|
||||||
|
|
@ -118,26 +112,15 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "relationId" | "
|
||||||
} | {
|
} | {
|
||||||
relation?: never;
|
relation?: never;
|
||||||
relationId?: ForeignKey<"relation"> | null;
|
relationId?: ForeignKey<"relation"> | null;
|
||||||
}) & ({
|
}) & {
|
||||||
path?: Path.CreateSingleOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.RemoveOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId?: ForeignKey<"path">;
|
pathId?: ForeignKey<"path">;
|
||||||
})) & {
|
}) & {
|
||||||
[k: string]: any;
|
[k: string]: any;
|
||||||
};
|
};
|
||||||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||||
export type RemoveOperationData = {} & (({
|
export type RemoveOperationData = {} & (({
|
||||||
relation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
relation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||||
}) & ({
|
|
||||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
|
||||||
}));
|
}));
|
||||||
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>;
|
||||||
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
export type Operation = CreateOperation | UpdateOperation | RemoveOperation;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { ActionDef } from "oak-domain/lib/types/Action";
|
import { ActionDef } from "oak-domain/lib/types/Action";
|
||||||
import { GenericAction } from "oak-domain/lib/actions/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 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 declare const IActionDef: ActionDef<IAction, IState>;
|
||||||
export type ParticularAction = IAction;
|
export type ParticularAction = IAction;
|
||||||
export declare const actions: string[];
|
export declare const actions: string[];
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.actionDefDict = exports.actions = exports.IActionDef = void 0;
|
exports.actionDefDict = exports.actions = exports.IActionDef = void 0;
|
||||||
exports.IActionDef = {
|
exports.IActionDef = {
|
||||||
stm: {
|
stm: {
|
||||||
startPaying: ['unPaid', 'paying'],
|
startPaying: ['unpaid', 'paying'],
|
||||||
payAll: [['unPaid', 'paying', 'partiallyPaid'], 'paid'],
|
payAll: [['unpaid', 'paying', 'partiallyPaid'], 'paid'],
|
||||||
payPartially: [['unPaid', 'paying'], 'partiallyPaid'],
|
payPartially: [['unpaid', 'paying'], 'partiallyPaid'],
|
||||||
payNone: ['paying', 'unPaid'],
|
payNone: ['paying', 'unpaid'],
|
||||||
timeout: ['unPaid', 'timeout'],
|
timeout: ['unpaid', 'timeout'],
|
||||||
cancel: ['unPaid', 'cancelled'],
|
cancel: ['unpaid', 'cancelled'],
|
||||||
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
startRefunding: [['paid', 'partiallyPaid'], 'refunding'],
|
||||||
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
refundAll: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'refunded'],
|
||||||
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
refundPartially: [['paid', 'refunding', 'partiallyPaid', 'partiallyRefunded'], 'partiallyRefunded'],
|
||||||
refundNone: ['refunding', 'paid'],
|
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.actions = ["count", "stat", "download", "select", "aggregate", "create", "remove", "update", "startPaying", "payAll", "payPartially", "payNone", "timeout", "cancel", "startRefunding", "refundAll", "refundPartially", "refundNone"];
|
||||||
exports.actionDefDict = {
|
exports.actionDefDict = {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ exports.desc = {
|
||||||
},
|
},
|
||||||
iState: {
|
iState: {
|
||||||
type: "enum",
|
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",
|
actionType: "crud",
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ exports.style = {
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
iState: {
|
iState: {
|
||||||
unPaid: '#52BE80',
|
unpaid: '#52BE80',
|
||||||
partiallyPaid: '#5DADE2',
|
partiallyPaid: '#5DADE2',
|
||||||
cancelled: '#D6DBDF',
|
cancelled: '#D6DBDF',
|
||||||
paid: '#2E86C1',
|
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",
|
actionType: "crud",
|
||||||
actions: action_1.genericActions,
|
actions: action_1.genericActions,
|
||||||
indexes: [
|
indexes: [
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export type OpSchema = EntityShape & {
|
||||||
paid: Price;
|
paid: Price;
|
||||||
refunded: Price;
|
refunded: Price;
|
||||||
channel: String<32>;
|
channel: String<32>;
|
||||||
timeoutAt: Datetime;
|
timeoutAt?: Datetime | null;
|
||||||
forbidRefundAt?: Datetime | null;
|
forbidRefundAt?: Datetime | null;
|
||||||
accountId?: ForeignKey<"account"> | null;
|
accountId?: ForeignKey<"account"> | null;
|
||||||
orderId?: ForeignKey<"order"> | null;
|
orderId?: ForeignKey<"order"> | null;
|
||||||
|
|
@ -32,7 +32,7 @@ export type Schema = EntityShape & {
|
||||||
paid: Price;
|
paid: Price;
|
||||||
refunded: Price;
|
refunded: Price;
|
||||||
channel: String<32>;
|
channel: String<32>;
|
||||||
timeoutAt: Datetime;
|
timeoutAt?: Datetime | null;
|
||||||
forbidRefundAt?: Datetime | null;
|
forbidRefundAt?: Datetime | null;
|
||||||
accountId?: ForeignKey<"account"> | null;
|
accountId?: ForeignKey<"account"> | null;
|
||||||
orderId?: ForeignKey<"order"> | null;
|
orderId?: ForeignKey<"order"> | null;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,6 @@ exports.desc = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
timeoutAt: {
|
timeoutAt: {
|
||||||
notNull: true,
|
|
||||||
type: "datetime"
|
type: "datetime"
|
||||||
},
|
},
|
||||||
forbidRefundAt: {
|
forbidRefundAt: {
|
||||||
|
|
|
||||||
|
|
@ -98,16 +98,10 @@ export type CreateOperationData = FormCreateData<Omit<OpSchema, "sourceRelationI
|
||||||
} | {
|
} | {
|
||||||
sourceRelation?: never;
|
sourceRelation?: never;
|
||||||
sourceRelationId: ForeignKey<"sourceRelation">;
|
sourceRelationId: ForeignKey<"sourceRelation">;
|
||||||
}) & ({
|
}) & {
|
||||||
pathId?: never;
|
|
||||||
path: Path.CreateSingleOperation;
|
|
||||||
} | {
|
|
||||||
pathId: ForeignKey<"path">;
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId: ForeignKey<"path">;
|
pathId: ForeignKey<"path">;
|
||||||
}) & ({
|
} & ({
|
||||||
destRelationId?: never;
|
destRelationId?: never;
|
||||||
destRelation: Relation.CreateSingleOperation;
|
destRelation: Relation.CreateSingleOperation;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -132,19 +126,10 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
||||||
} | {
|
} | {
|
||||||
sourceRelation?: never;
|
sourceRelation?: never;
|
||||||
sourceRelationId?: ForeignKey<"sourceRelation">;
|
sourceRelationId?: ForeignKey<"sourceRelation">;
|
||||||
}) & ({
|
}) & {
|
||||||
path?: Path.CreateSingleOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.UpdateOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: Path.RemoveOperation;
|
|
||||||
pathId?: never;
|
|
||||||
} | {
|
|
||||||
path?: never;
|
path?: never;
|
||||||
pathId?: ForeignKey<"path">;
|
pathId?: ForeignKey<"path">;
|
||||||
}) & ({
|
} & ({
|
||||||
destRelation?: Relation.CreateSingleOperation;
|
destRelation?: Relation.CreateSingleOperation;
|
||||||
destRelationId?: never;
|
destRelationId?: never;
|
||||||
} | {
|
} | {
|
||||||
|
|
@ -162,8 +147,6 @@ export type UpdateOperationData = FormUpdateData<Omit<OpSchema, "sourceRelationI
|
||||||
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>;
|
||||||
export type RemoveOperationData = {} & (({
|
export type RemoveOperationData = {} & (({
|
||||||
sourceRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
sourceRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||||
}) & ({
|
|
||||||
path?: Path.UpdateOperation | Path.RemoveOperation;
|
|
||||||
}) & ({
|
}) & ({
|
||||||
destRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
destRelation?: Relation.UpdateOperation | Relation.RemoveOperation;
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -237,6 +237,7 @@ const triggers = [
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
action: ['startPaying'],
|
action: ['startPaying'],
|
||||||
when: 'before',
|
when: 'before',
|
||||||
|
priority: 99,
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { data, filter } = operation;
|
const { data, filter } = operation;
|
||||||
const pays = await context.select('pay', {
|
const pays = await context.select('pay', {
|
||||||
|
|
@ -247,14 +248,9 @@ const triggers = [
|
||||||
const [pay] = pays;
|
const [pay] = pays;
|
||||||
const { applicationId, channel, iState } = pay;
|
const { applicationId, channel, iState } = pay;
|
||||||
(0, assert_1.default)(iState === 'unpaid');
|
(0, assert_1.default)(iState === 'unpaid');
|
||||||
if (![PayConfig_1.PAY_CHANNEL_ACCOUNT_NAME, PayConfig_1.PAY_CHANNEL_OFFLINE_NAME].includes(channel)) {
|
const payClazz = await (0, payClazz_1.getPayClazz)(applicationId, channel, context);
|
||||||
const payClazz = (0, payClazz_1.getPayClazz)(applicationId, channel);
|
await payClazz.prepay(pay, data, context);
|
||||||
const [prePayId, meta] = await payClazz.prepay(pay);
|
return 1;
|
||||||
data.externalId = prePayId;
|
|
||||||
data.meta = meta;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -273,7 +269,7 @@ const triggers = [
|
||||||
const { applicationId, channel, iState, externalId } = pay;
|
const { applicationId, channel, iState, externalId } = pay;
|
||||||
(0, assert_1.default)(iState === 'unpaid' || iState === 'paying');
|
(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)) {
|
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);
|
await payClazz.close(pay);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
|
import { BRC } from '../types/RuntimeCxt';
|
||||||
type IState = EntityDict['pay']['OpSchema']['iState'];
|
type IState = EntityDict['pay']['OpSchema']['iState'];
|
||||||
export default interface PayClazz {
|
export default interface PayClazz {
|
||||||
type: string;
|
channel: string;
|
||||||
prepay(pay: EntityDict['pay']['OpSchema']): Promise<[string, object]>;
|
prepay(pay: EntityDict['pay']['OpSchema'], data: EntityDict['pay']['Update']['data'], context: BRC): Promise<void>;
|
||||||
getState(pay: EntityDict['pay']['OpSchema']): Promise<IState>;
|
getState(pay: EntityDict['pay']['OpSchema']): Promise<IState>;
|
||||||
close(pay: EntityDict['pay']['OpSchema']): Promise<void>;
|
close(pay: EntityDict['pay']['OpSchema']): Promise<void>;
|
||||||
decodeNotification(params: Record<string, string>, body: any): Promise<Array<{
|
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';
|
import PayClazz from '../../types/PayClazz';
|
||||||
export declare function registerPayClazz(appId: string, channel: string, clazz: PayClazz): void;
|
import { BRC } from '../../types/RuntimeCxt';
|
||||||
export declare function getPayClazz(appId: string, channel: string): PayClazz;
|
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";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.getPayClazz = exports.registerPayClazz = void 0;
|
exports.getPayClazz = exports.registerAppPayClazzConstructor = void 0;
|
||||||
const tslib_1 = require("tslib");
|
const tslib_1 = require("tslib");
|
||||||
|
const PayConfig_1 = require("../../types/PayConfig");
|
||||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
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 = {};
|
const PayChannelDict = {};
|
||||||
function registerPayClazz(appId, channel, clazz) {
|
const PayClazzConstructorDict = {
|
||||||
const key = `${appId}.${channel}`;
|
[PayConfig_1.PAY_CHANNEL_OFFLINE_NAME]: async () => new Offline_1.default(),
|
||||||
(0, assert_1.default)(!PayChannelDict.hasOwnProperty(key));
|
[PayConfig_1.PAY_CHANNEL_ACCOUNT_NAME]: async () => new Account_1.default(),
|
||||||
PayChannelDict[key] = clazz;
|
};
|
||||||
|
function registerAppPayClazzConstructor(channel, constructor) {
|
||||||
|
PayClazzConstructorDict[channel] = constructor;
|
||||||
}
|
}
|
||||||
exports.registerPayClazz = registerPayClazz;
|
exports.registerAppPayClazzConstructor = registerAppPayClazzConstructor;
|
||||||
function getPayClazz(appId, channel) {
|
async function getPayClazz(appId, channel, context) {
|
||||||
const key = `${appId}.${channel}`;
|
const key = `${appId}.${channel}`;
|
||||||
(0, assert_1.default)(PayChannelDict.hasOwnProperty(key));
|
if (PayChannelDict.hasOwnProperty(key)) {
|
||||||
return PayChannelDict[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;
|
exports.getPayClazz = getPayClazz;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ const watchers = [
|
||||||
const results = [];
|
const results = [];
|
||||||
for (const pay of data) {
|
for (const pay of data) {
|
||||||
const { applicationId, channel, timeoutAt } = pay;
|
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);
|
const iState = await clazz.getState(pay);
|
||||||
if (iState !== pay.iState) {
|
if (iState !== pay.iState) {
|
||||||
let action = 'close';
|
let action = 'close';
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ import { EntityDict } from '@oak-app-domain';
|
||||||
import { Checker } from 'oak-domain/lib/types';
|
import { Checker } from 'oak-domain/lib/types';
|
||||||
import { RuntimeCxt } from '../types/RuntimeCxt';
|
import { RuntimeCxt } from '../types/RuntimeCxt';
|
||||||
import aoCheckers from './accountOper';
|
import aoCheckers from './accountOper';
|
||||||
|
import payCheckers from './pay';
|
||||||
|
|
||||||
const checkers = [
|
const checkers = [
|
||||||
...aoCheckers,
|
...aoCheckers,
|
||||||
|
...payCheckers,
|
||||||
] as Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
|
] as Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
|
||||||
|
|
||||||
export default checkers;
|
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