增加了sysAccount/survey的部分能力
This commit is contained in:
parent
3a0e6d3035
commit
4340d8bbe1
|
|
@ -143,6 +143,9 @@ export async function getWithdrawCreateData(params, context) {
|
||||||
data: ele,
|
data: ele,
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
data.refund$entity = [];
|
||||||
|
}
|
||||||
if (totalPrice > price2) {
|
if (totalPrice > price2) {
|
||||||
// 如果还有要退的部分,就从withdrawAccount来进行转账
|
// 如果还有要退的部分,就从withdrawAccount来进行转账
|
||||||
const rest = totalPrice - price2;
|
const rest = totalPrice - price2;
|
||||||
|
|
@ -196,6 +199,10 @@ export async function getWithdrawCreateData(params, context) {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// 保持结构完整,让上层可以和withdraw$detail同构渲染
|
||||||
|
data.withdrawTransfer$withdraw = [];
|
||||||
|
}
|
||||||
data.loss = totalLoss;
|
data.loss = totalLoss;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
import { RuntimeCxt } from '../types/RuntimeCxt';
|
import { RuntimeCxt } from '../types/RuntimeCxt';
|
||||||
import { Checker } from 'oak-domain/lib/types/Auth';
|
import { Checker } from 'oak-domain/lib/types/Auth';
|
||||||
|
export declare function registerAccountEntity<ED extends EntityDict>(entity: keyof ED): void;
|
||||||
|
export declare const accountEntities: string[];
|
||||||
declare const triggers: Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
|
declare const triggers: Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
|
||||||
export default triggers;
|
export default triggers;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import { generateNewId } from 'oak-domain/lib/utils/uuid';
|
import { generateNewId } from 'oak-domain/lib/utils/uuid';
|
||||||
import { getPayClazzAccountEntities } from '../utils/payClazz';
|
// 当注入一个新的account entity时,将withdrawChannel的删除与之相关联
|
||||||
// 当注入一个新的pay entity时,将account的删除与之相关联
|
export function registerAccountEntity(entity) {
|
||||||
const entities = getPayClazzAccountEntities();
|
accountEntities.push(entity);
|
||||||
|
}
|
||||||
|
export const accountEntities = ['wpAccount', 'offlineAccount'];
|
||||||
const triggers = [
|
const triggers = [
|
||||||
...entities.filter(ele => !!ele).map((entity) => [
|
...accountEntities.filter(ele => !!ele).map((entity) => [
|
||||||
{
|
{
|
||||||
entity,
|
entity,
|
||||||
action: 'remove',
|
action: 'remove',
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ import applicationCheckers from './application';
|
||||||
import offlineAccountCheckers from './offlineAccount';
|
import offlineAccountCheckers from './offlineAccount';
|
||||||
import wpProductCheckers from './wpProduct';
|
import wpProductCheckers from './wpProduct';
|
||||||
import abstractCheckers from './abstractChecker';
|
import abstractCheckers from './abstractChecker';
|
||||||
|
import withdrawAccounts from './withdrawAccount';
|
||||||
const checkers = [
|
const checkers = [
|
||||||
|
...withdrawAccounts,
|
||||||
...abstractCheckers,
|
...abstractCheckers,
|
||||||
...aoCheckers,
|
...aoCheckers,
|
||||||
...payCheckers,
|
...payCheckers,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { Checker } from 'oak-domain/lib/types/Auth';
|
||||||
|
import { EntityDict } from '../oak-app-domain';
|
||||||
|
import { RuntimeCxt } from '../types/RuntimeCxt';
|
||||||
|
declare const checkers: Checker<EntityDict, 'withdrawAccount', RuntimeCxt>[];
|
||||||
|
export default checkers;
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import { generateNewId } from 'oak-domain/lib/utils/uuid';
|
||||||
|
import { pipeline } from 'oak-domain/lib/utils/executor';
|
||||||
|
import assert from 'assert';
|
||||||
|
const checkers = [
|
||||||
|
{
|
||||||
|
entity: 'withdrawAccount',
|
||||||
|
type: 'logical',
|
||||||
|
action: 'create',
|
||||||
|
checker(operation, context, option) {
|
||||||
|
const { data } = operation;
|
||||||
|
if (data) {
|
||||||
|
const { id, entity, entityId, isDefault } = data;
|
||||||
|
if (entity && entityId && isDefault) {
|
||||||
|
return context.operate('withdrawAccount', {
|
||||||
|
id: generateNewId(),
|
||||||
|
action: 'update',
|
||||||
|
data: {
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
entity,
|
||||||
|
entityId,
|
||||||
|
isDefault: true,
|
||||||
|
id: {
|
||||||
|
$ne: id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entity: 'withdrawAccount',
|
||||||
|
type: 'logical',
|
||||||
|
action: 'update',
|
||||||
|
checker(operation, context, option) {
|
||||||
|
const { data, filter } = operation;
|
||||||
|
if (data?.isDefault) {
|
||||||
|
return pipeline(() => context.select('withdrawAccount', {
|
||||||
|
data: {
|
||||||
|
id: 1,
|
||||||
|
entity: 1,
|
||||||
|
entityId: 1,
|
||||||
|
},
|
||||||
|
filter,
|
||||||
|
}, {}), (accounts) => {
|
||||||
|
assert(accounts.length === 1);
|
||||||
|
const [account] = accounts;
|
||||||
|
const { entity, entityId, id } = account;
|
||||||
|
return context.operate('withdrawAccount', {
|
||||||
|
id: generateNewId(),
|
||||||
|
action: 'update',
|
||||||
|
data: {
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
entity,
|
||||||
|
entityId,
|
||||||
|
isDefault: true,
|
||||||
|
id: {
|
||||||
|
$ne: id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, option);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
export default checkers;
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { EntityDict } from "../../../oak-app-domain";
|
||||||
|
declare const _default: (props: import("oak-frontend-base").ReactComponentProps<EntityDict, keyof EntityDict, boolean, {
|
||||||
|
entities: string[];
|
||||||
|
systemId: string;
|
||||||
|
}>) => React.ReactElement;
|
||||||
|
export default _default;
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
import assert from 'assert';
|
||||||
|
import { uniq } from "oak-domain/lib/utils/lodash";
|
||||||
|
export default OakComponent({
|
||||||
|
properties: {
|
||||||
|
entities: [],
|
||||||
|
systemId: '',
|
||||||
|
},
|
||||||
|
lifetimes: {
|
||||||
|
ready() {
|
||||||
|
this.refreshData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
refreshData() {
|
||||||
|
const { entities, systemId } = this.props;
|
||||||
|
const schema = this.features.cache.getSchema();
|
||||||
|
uniq(['wpAccount', 'offlineAccount'].concat(entities || [])).forEach((entity) => {
|
||||||
|
const projection = {
|
||||||
|
id: 1,
|
||||||
|
$$createAt$$: 1,
|
||||||
|
$$updateAt$$: 1,
|
||||||
|
};
|
||||||
|
Object.keys(schema[entity].attributes).forEach(ele => {
|
||||||
|
if (!ele.startsWith('$$')) {
|
||||||
|
projection[ele] = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.features.cache.refresh(entity, {
|
||||||
|
data: projection,
|
||||||
|
filter: {
|
||||||
|
systemId,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
formData({ features }) {
|
||||||
|
const { entities, systemId } = this.props;
|
||||||
|
assert(systemId);
|
||||||
|
const schema = features.cache.getSchema();
|
||||||
|
let total = 0;
|
||||||
|
const accounts = uniq(['wpAccount', 'offlineAccount'].concat(entities || [])).map((entity) => {
|
||||||
|
const projection = {
|
||||||
|
id: 1,
|
||||||
|
$$createAt$$: 1,
|
||||||
|
$$updateAt$$: 1,
|
||||||
|
};
|
||||||
|
Object.keys(schema[entity].attributes).forEach(ele => {
|
||||||
|
if (!ele.startsWith('$$')) {
|
||||||
|
projection[ele] = 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const [data] = this.features.cache.get(entity, {
|
||||||
|
data: projection,
|
||||||
|
filter: {
|
||||||
|
systemId,
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
const { price, id } = data;
|
||||||
|
total += price;
|
||||||
|
return {
|
||||||
|
entity,
|
||||||
|
id,
|
||||||
|
price,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
total,
|
||||||
|
accounts,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { EntityDict } from "../../../oak-app-domain";
|
||||||
|
import { WebComponentProps } from "oak-frontend-base";
|
||||||
|
import React from 'react';
|
||||||
|
export default function render(props: WebComponentProps<EntityDict, 'offlineAccount', false, {
|
||||||
|
total?: number;
|
||||||
|
accounts?: Array<{
|
||||||
|
id: string;
|
||||||
|
entity: string;
|
||||||
|
data: any;
|
||||||
|
price: number;
|
||||||
|
}>;
|
||||||
|
}>): React.JSX.Element | null;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Styles from './web.pc.module.less';
|
||||||
|
export default function render(props) {
|
||||||
|
const { accounts, total } = props.data;
|
||||||
|
if (accounts) {
|
||||||
|
return (<div className={Styles.container}>
|
||||||
|
{total}
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
@ -34,8 +34,8 @@ export default OakComponent({
|
||||||
return {
|
return {
|
||||||
withdrawCreate: withdrawData && {
|
withdrawCreate: withdrawData && {
|
||||||
...withdrawData,
|
...withdrawData,
|
||||||
refund$entity: withdrawData.refund$entity.map((ele) => ele.data),
|
refund$entity: withdrawData.refund$entity?.map((ele) => ele.data),
|
||||||
withdrawTransfer$withdraw: withdrawData.withdrawTransfer$withdraw.map((ele) => ele.data),
|
withdrawTransfer$withdraw: withdrawData.withdrawTransfer$withdraw?.map((ele) => ele.data),
|
||||||
},
|
},
|
||||||
withdrawable,
|
withdrawable,
|
||||||
withdrawLossText,
|
withdrawLossText,
|
||||||
|
|
@ -81,6 +81,9 @@ export default OakComponent({
|
||||||
chooseWa: false,
|
chooseWa: false,
|
||||||
withdrawAccountId: '',
|
withdrawAccountId: '',
|
||||||
waFilter: undefined,
|
waFilter: undefined,
|
||||||
|
pickWithdrawChannelMp(id) {
|
||||||
|
this.pickWithdrawChannel(id);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setValue(valueYuan) {
|
setValue(valueYuan) {
|
||||||
|
|
@ -108,19 +111,21 @@ export default OakComponent({
|
||||||
},
|
},
|
||||||
async createWithdrawData() {
|
async createWithdrawData() {
|
||||||
const { value, refundAmount, avail, withdrawAccountId } = this.state;
|
const { value, refundAmount, avail, withdrawAccountId } = this.state;
|
||||||
if (value > avail) {
|
if (value) {
|
||||||
this.setMessage({
|
if (value > avail) {
|
||||||
type: 'error',
|
this.setMessage({
|
||||||
content: this.t('error::withdraw.overflow'),
|
type: 'error',
|
||||||
});
|
content: this.t('error::withdraw.overflow'),
|
||||||
}
|
});
|
||||||
else if (value <= refundAmount) {
|
}
|
||||||
this.resetCreateData();
|
else if (value <= refundAmount) {
|
||||||
}
|
this.resetCreateData();
|
||||||
else if (!withdrawAccountId) {
|
}
|
||||||
this.setState({
|
else if (!withdrawAccountId) {
|
||||||
chooseWa: true,
|
this.setState({
|
||||||
});
|
chooseWa: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async resetCreateData() {
|
async resetCreateData() {
|
||||||
|
|
@ -208,6 +213,10 @@ export default OakComponent({
|
||||||
},
|
},
|
||||||
goBack() {
|
goBack() {
|
||||||
this.navigateBack();
|
this.navigateBack();
|
||||||
|
},
|
||||||
|
onGoToHistoryMp() {
|
||||||
|
const { onGoToHistory } = this.props;
|
||||||
|
onGoToHistory && onGoToHistory();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,17 @@
|
||||||
@import '../../../config/styles/mp/mixins.less';
|
@import '../../../config/styles/mp/mixins.less';
|
||||||
@import '../../../config/styles/mp/index.less';
|
@import '../../../config/styles/mp/index.less';
|
||||||
|
|
||||||
|
|
||||||
|
.errorContainer {
|
||||||
|
padding: 48rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
@ -93,6 +104,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gotoHistory {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: @oak-color-primary;
|
||||||
|
margin-top: 56rpx;
|
||||||
|
text-decoration: underline;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,21 @@
|
||||||
<block wx:if="{{withdrawCreate}}">
|
<block wx:if="{{!withdrawable}}">
|
||||||
|
<view class="errorContainer">
|
||||||
|
<oak-icon name="delete_fill" size="48" color="#FF3141" />
|
||||||
|
<view>{{t('notSetYet')}}</view>
|
||||||
|
<l-button bind:lintap="goBack">{{t('common::back')}}</l-button>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<block wx:elif="{{chooseWa && waFilter}}">
|
||||||
|
<withdrawAccount-picker
|
||||||
|
oakPath="$$opb-withdraw-create-wapicker"
|
||||||
|
oakFilters="{{[waFilter]}}"
|
||||||
|
onPicker="{{pickWithdrawChannelMp}}"
|
||||||
|
onCancel="{{restartAll}}"
|
||||||
|
entity="user"
|
||||||
|
entityId="{{userId}}"
|
||||||
|
/>
|
||||||
|
</block>
|
||||||
|
<block wx:elif="{{withdrawCreate}}">
|
||||||
<view class="container">
|
<view class="container">
|
||||||
<withdraw-display
|
<withdraw-display
|
||||||
withdraw="{{withdrawCreate}}"
|
withdraw="{{withdrawCreate}}"
|
||||||
|
|
@ -10,7 +27,7 @@
|
||||||
size="long"
|
size="long"
|
||||||
plain="true"
|
plain="true"
|
||||||
shape="square"
|
shape="square"
|
||||||
bind:lintap="clearWithdrawData"
|
bind:lintap="restartAll"
|
||||||
l-class="cancelBtn"
|
l-class="cancelBtn"
|
||||||
>
|
>
|
||||||
{{t('common::action.cancel')}}
|
{{t('common::action.cancel')}}
|
||||||
|
|
@ -25,12 +42,13 @@
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</block>
|
</block>
|
||||||
<block wx:elif="{{account && avail > 0}}">
|
<block wx:elif="{{account}}">
|
||||||
<view class="main">
|
<view class="main">
|
||||||
<view class="label">{{t('label')}}</view>
|
<view class="label">{{t('label')}}</view>
|
||||||
<view class="input">
|
<view class="input">
|
||||||
<span class="symbol">{{t('common::pay.symbol')}}</span>
|
<span class="symbol">{{t('common::pay.symbol')}}</span>
|
||||||
<l-input
|
<l-input
|
||||||
|
focus="{{true}}"
|
||||||
hide-label="{{true}}"
|
hide-label="{{true}}"
|
||||||
showRow="{{false}}"
|
showRow="{{false}}"
|
||||||
type="number"
|
type="number"
|
||||||
|
|
@ -38,16 +56,21 @@
|
||||||
value="{{valueYuan ? valueYuan : undefind}}"
|
value="{{valueYuan ? valueYuan : undefind}}"
|
||||||
l-input-class="my-input-class"
|
l-input-class="my-input-class"
|
||||||
bind:lininput="InputValueMp"
|
bind:lininput="InputValueMp"
|
||||||
|
bind:linconfirm="createWithdrawData"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
<view class="tips">
|
<view class="tips">
|
||||||
<view class="tipLine">
|
<view class="tipLine">
|
||||||
<span>{{t('tips.1-1')}}</span>
|
<span>{{t('tips.1-1')}}</span>
|
||||||
<span class="value">{{availYuan}}</span>
|
<block wx:if="{{avail>0}}">
|
||||||
<span>{{t('tips.1-2')}}</span>
|
<span class="value" style="text-decoration: underline; margin-left: 16rpx;" bindtap="setValueMp" data-value="{{availYuan}}">
|
||||||
<block wx:if="{{avail > 0}}">
|
<span class="value">{{availYuan}}</span>
|
||||||
<span class="value" style="text-decoration: underline; margin-left: 16rpx;" bindtap="setValueMp" data-value="{{availYuan}}">{{t('tips.fill')}}</span>
|
</span>
|
||||||
</block>
|
</block>
|
||||||
|
<block wx:else>
|
||||||
|
<span class="value">{{availYuan}}</span>
|
||||||
|
</block>
|
||||||
|
<span>{{t('tips.1-2')}}</span>
|
||||||
</view>
|
</view>
|
||||||
<view wx:if="{{refundAmount > 0}}" class="tipLine">
|
<view wx:if="{{refundAmount > 0}}" class="tipLine">
|
||||||
<span>{{t('tips.2-1')}}</span>
|
<span>{{t('tips.2-1')}}</span>
|
||||||
|
|
@ -56,7 +79,7 @@
|
||||||
</view>
|
</view>
|
||||||
<view wx:if="{{manualAmount > 0}}" class="tipLine">
|
<view wx:if="{{manualAmount > 0}}" class="tipLine">
|
||||||
<span>{{t('tips.3-1')}}</span>
|
<span>{{t('tips.3-1')}}</span>
|
||||||
<span class="value">{{manualAmountYuan}}</span>
|
<span class="value">{{manualAmountYuan}}</span>
|
||||||
<span>{{t('tips.3-2')}}</span>
|
<span>{{t('tips.3-2')}}</span>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -72,7 +95,11 @@
|
||||||
<oak-icon wx:else name="unfold" size="18" color="skyblue"/>
|
<oak-icon wx:else name="unfold" size="18" color="skyblue"/>
|
||||||
<span style="margin-left: 16rpx;color:{{showLossHelp ? 'blue' : 'skyblue'}};">{{t('helps.label.loss')}}</span>
|
<span style="margin-left: 16rpx;color:{{showLossHelp ? 'blue' : 'skyblue'}};">{{t('helps.label.loss')}}</span>
|
||||||
</view>
|
</view>
|
||||||
<view wx:if="{{showLossHelp}}" class="content2">{{t('helps.content.loss')}}</view>
|
<view wx:if="{{showLossHelp}}" class="content2">{{withdrawLossText}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="gotoHistory" bindtap="onGoToHistoryMp">
|
||||||
|
<oak-icon name="coupons" size="18" color="@oak-color-primary" style="margin-right:8rpx;"/>
|
||||||
|
<span>{{t('gotoHistory')}}</span>
|
||||||
</view>
|
</view>
|
||||||
<view class="footer">
|
<view class="footer">
|
||||||
<l-button
|
<l-button
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export default function render(props) {
|
||||||
</div>
|
</div>
|
||||||
<div className={Styles.input}>
|
<div className={Styles.input}>
|
||||||
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
|
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
|
||||||
<Input autoFocus type="number" min={0} max={availYuan} placeholder={t('placeholder')} value={valueYuan ? `${valueYuan}` : undefined} onChange={(value) => setValue(value)} style={{ '--font-size': '28px' }}/>
|
<Input autoFocus type="number" min={0} max={availYuan} placeholder={t('placeholder')} value={valueYuan ? `${valueYuan}` : undefined} onChange={(value) => setValue(value)} style={{ '--font-size': '28px' }} onEnterPress={() => createWithdrawData()}/>
|
||||||
</div>
|
</div>
|
||||||
<div className={Styles.tips}>
|
<div className={Styles.tips}>
|
||||||
<div className={Styles.tipLine}>
|
<div className={Styles.tipLine}>
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,6 @@ export default OakComponent({
|
||||||
dealLoss: 1,
|
dealLoss: 1,
|
||||||
dealPrice: 1,
|
dealPrice: 1,
|
||||||
iState: 1,
|
iState: 1,
|
||||||
withdrawAccount: {
|
|
||||||
id: 1,
|
|
||||||
name: 1,
|
|
||||||
},
|
|
||||||
reason: 1,
|
reason: 1,
|
||||||
meta: 1,
|
meta: 1,
|
||||||
refund$entity: {
|
refund$entity: {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export default OakComponent({
|
||||||
formData({ features }) {
|
formData({ features }) {
|
||||||
const { withdraw, create } = this.props;
|
const { withdraw, create } = this.props;
|
||||||
const { refund$entity: refundData, withdrawTransfer$withdraw: transferData } = withdraw;
|
const { refund$entity: refundData, withdrawTransfer$withdraw: transferData } = withdraw;
|
||||||
const refundData2 = (refundData).map((refund) => {
|
const refundData2 = (refundData)?.map((refund) => {
|
||||||
const { meta, price, loss, iState, $$updateAt$$, reason } = refund;
|
const { meta, price, loss, iState, $$updateAt$$, reason } = refund;
|
||||||
const { lossExplanation, channel } = meta;
|
const { lossExplanation, channel } = meta;
|
||||||
return {
|
return {
|
||||||
|
|
@ -24,8 +24,8 @@ export default OakComponent({
|
||||||
updateAt: !create && dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
|
updateAt: !create && dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
|
||||||
reason,
|
reason,
|
||||||
};
|
};
|
||||||
});
|
}) || [];
|
||||||
const transferData2 = transferData.map((transfer) => {
|
const transferData2 = transferData?.map((transfer) => {
|
||||||
const { price, loss, iState, meta, withdrawAccountId, withdrawAccount, $$updateAt$$, reason } = transfer;
|
const { price, loss, iState, meta, withdrawAccountId, withdrawAccount, $$updateAt$$, reason } = transfer;
|
||||||
let withdrawChannel = withdrawAccount?.channel;
|
let withdrawChannel = withdrawAccount?.channel;
|
||||||
if (!withdrawChannel && withdrawAccountId) {
|
if (!withdrawChannel && withdrawAccountId) {
|
||||||
|
|
@ -65,7 +65,7 @@ export default OakComponent({
|
||||||
updateAt: !create && dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
|
updateAt: !create && dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
|
||||||
reason,
|
reason,
|
||||||
};
|
};
|
||||||
});
|
}) || [];
|
||||||
const withdrawExactPrice = ['successful', 'partiallySuccessful', 'failed'].includes(withdraw.iState) ? withdraw.dealPrice - withdraw.dealLoss : withdraw.price - withdraw.loss;
|
const withdrawExactPrice = ['successful', 'partiallySuccessful', 'failed'].includes(withdraw.iState) ? withdraw.dealPrice - withdraw.dealLoss : withdraw.price - withdraw.loss;
|
||||||
return {
|
return {
|
||||||
createAtStr: dayJs(withdraw.$$createAt$$).format('YYYY-MM-DD HH:mm'),
|
createAtStr: dayJs(withdraw.$$createAt$$).format('YYYY-MM-DD HH:mm'),
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ export default function render(props) {
|
||||||
</div>
|
</div>
|
||||||
{itemData && itemData.map((data, idx) => (<div className={Styles.refundItem} key={idx}>
|
{itemData && itemData.map((data, idx) => (<div className={Styles.refundItem} key={idx}>
|
||||||
<div className={Styles.header2}>
|
<div className={Styles.header2}>
|
||||||
<Tag color={data.typeColor}>{data.type}</Tag>
|
<Tag fill="outline">
|
||||||
|
{data.type}
|
||||||
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
{data.iState && <div className={Styles.item}>
|
{data.iState && <div className={Styles.item}>
|
||||||
<span className={Styles.label}>{t('refund:attr.iState')}</span>
|
<span className={Styles.label}>{t('refund:attr.iState')}</span>
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,9 @@ export default function render(props) {
|
||||||
{itemData && <div className={Styles.refunds}>
|
{itemData && <div className={Styles.refunds}>
|
||||||
{itemData.map((data, idx) => (<div className={Styles.refundItem} key={idx}>
|
{itemData.map((data, idx) => (<div className={Styles.refundItem} key={idx}>
|
||||||
<div className={Styles.header2}>
|
<div className={Styles.header2}>
|
||||||
<Tag color={data.typeColor}>{data.type}</Tag>
|
<Tag>
|
||||||
|
{data.type}
|
||||||
|
</Tag>
|
||||||
</div>
|
</div>
|
||||||
{data.iState && <div className={Styles.item}>
|
{data.iState && <div className={Styles.item}>
|
||||||
<span className={Styles.label}>{t('refund:attr.iState')}</span>
|
<span className={Styles.label}>{t('refund:attr.iState')}</span>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ export default OakComponent({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
withdrawTransfer$withdraw: {
|
withdrawTransfer$withdraw$$aggr: {
|
||||||
$entity: 'withdrawTransfer',
|
$entity: 'withdrawTransfer',
|
||||||
data: {
|
data: {
|
||||||
'#count-1': {
|
'#count-1': {
|
||||||
|
|
@ -60,5 +60,10 @@ export default OakComponent({
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
goBack() {
|
||||||
|
this.navigateBack();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"loss": "预计手续费%{value}%元",
|
"loss": "预计手续费%{value}元",
|
||||||
"dealLoss": "手续费%{value}%元",
|
"dealLoss": "手续费%{value}元",
|
||||||
"count": "将分%{value}笔提现到您账户"
|
"count": "将分%{value}笔提现到您账户",
|
||||||
|
"noData": "您尚无提现记录"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { EntityDict } from "../../../oak-app-domain";
|
||||||
|
import { WebComponentProps } from "oak-frontend-base";
|
||||||
|
export default function render(props: WebComponentProps<EntityDict, 'withdraw', false, {
|
||||||
|
gotoDetail: (id: string) => void;
|
||||||
|
withdraws?: ({
|
||||||
|
id: string;
|
||||||
|
iState: string;
|
||||||
|
iStateColor: string;
|
||||||
|
price: string;
|
||||||
|
lossDescription: string;
|
||||||
|
countDescription: number;
|
||||||
|
createAt: string;
|
||||||
|
})[];
|
||||||
|
}, {
|
||||||
|
goBack: () => void;
|
||||||
|
}>): React.JSX.Element;
|
||||||
|
|
@ -1 +1,20 @@
|
||||||
"use strict";
|
import React from 'react';
|
||||||
|
import { List, Tag, Result, Button } from 'antd-mobile';
|
||||||
|
import { HandPayCircleOutline } from 'antd-mobile-icons';
|
||||||
|
export default function render(props) {
|
||||||
|
const { withdraws, gotoDetail } = props.data;
|
||||||
|
const { t, goBack } = props.methods;
|
||||||
|
if (withdraws?.length) {
|
||||||
|
return (<List>
|
||||||
|
{withdraws.map((ele) => (<List.Item prefix={<HandPayCircleOutline fontSize={38}/>} extra={<Tag color={ele.iStateColor}>{ele.iState}</Tag>} title={ele.lossDescription} description={ele.createAt} onClick={() => gotoDetail(ele.id)}>
|
||||||
|
<>
|
||||||
|
<span style={{ marginRight: 3 }}>{t('common::pay.symbol')}</span>
|
||||||
|
{ele.price}
|
||||||
|
</>
|
||||||
|
</List.Item>))}
|
||||||
|
</List>);
|
||||||
|
}
|
||||||
|
return (<Result status="info" title={t('noData')} description={<Button onClick={goBack}>
|
||||||
|
{t('common::back')}
|
||||||
|
</Button>}/>);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,4 +12,6 @@ export default function render(props: WebComponentProps<EntityDict, 'withdraw',
|
||||||
countDescription: number;
|
countDescription: number;
|
||||||
createAt: string;
|
createAt: string;
|
||||||
})[];
|
})[];
|
||||||
}>): React.JSX.Element | null;
|
}, {
|
||||||
|
goBack: () => void;
|
||||||
|
}>): React.JSX.Element;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { List, Avatar, Button } from 'antd';
|
import { List, Avatar, Result, Button } from 'antd';
|
||||||
import { CalendarOutlined } from '@ant-design/icons';
|
import { CalendarOutlined, NodeExpandOutlined } from '@ant-design/icons';
|
||||||
import Styles from './web.pc.module.less';
|
import Styles from './web.pc.module.less';
|
||||||
export default function render(props) {
|
export default function render(props) {
|
||||||
const { withdraws, gotoDetail } = props.data;
|
const { withdraws, gotoDetail } = props.data;
|
||||||
const { t } = props.methods;
|
const { t, goBack } = props.methods;
|
||||||
if (withdraws?.length) {
|
if (withdraws?.length) {
|
||||||
return (<List itemLayout="horizontal" dataSource={withdraws} renderItem={(item, index) => (<List.Item key={index} actions={[
|
return (<List itemLayout="horizontal" dataSource={withdraws} renderItem={(item, index) => (<List.Item key={index} actions={[
|
||||||
<Button onClick={() => gotoDetail(item.id)}>
|
<Button onClick={() => gotoDetail(item.id)}>
|
||||||
{t('common::detail')}
|
{t('common::action.detail')}
|
||||||
</Button>
|
</Button>
|
||||||
]}>
|
]}>
|
||||||
<List.Item.Meta avatar={<Avatar size={50} style={{
|
<List.Item.Meta avatar={<Avatar size={50} style={{
|
||||||
|
|
@ -25,13 +25,18 @@ export default function render(props) {
|
||||||
<span>{item.lossDescription}</span>
|
<span>{item.lossDescription}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>} description={<div className={Styles.description}>
|
</div>} description={<div className={Styles.description}>
|
||||||
<div className={Styles.count}>{item.countDescription}</div>
|
<div className={Styles.count}>
|
||||||
|
<NodeExpandOutlined />
|
||||||
|
<span className={Styles.data}>{item.countDescription}</span>
|
||||||
|
</div>
|
||||||
<div className={Styles.createAt}>
|
<div className={Styles.createAt}>
|
||||||
<CalendarOutlined />
|
<CalendarOutlined />
|
||||||
<span className={Styles.date}>{item.createAt}</span>
|
<span className={Styles.data}>{item.createAt}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>}/>
|
</div>}/>
|
||||||
</List.Item>)}/>);
|
</List.Item>)}/>);
|
||||||
}
|
}
|
||||||
return null;
|
return (<Result title={t('noData')} extra={<Button onClick={goBack}>
|
||||||
|
{t('common::back')}
|
||||||
|
</Button>}/>);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,7 @@
|
||||||
.description {
|
.description {
|
||||||
padding: auto;
|
padding: auto;
|
||||||
|
|
||||||
.createAt {
|
.data {
|
||||||
.date {
|
margin-left: 4px;
|
||||||
margin-left: 4px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +63,7 @@ export default OakComponent({
|
||||||
return {
|
return {
|
||||||
entity,
|
entity,
|
||||||
entityId,
|
entityId,
|
||||||
|
enabled: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -87,19 +88,37 @@ export default OakComponent({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async removeAccount(id) {
|
async removeAccount(id) {
|
||||||
return this.execute(undefined, undefined, undefined, [
|
const row = this.state.withdrawAccounts.find(ele => ele.id === id);
|
||||||
{
|
if (row['#oakLegalActions']?.includes('remove')) {
|
||||||
entity: 'withdrawAccount',
|
return this.execute(undefined, undefined, undefined, [
|
||||||
operation: {
|
{
|
||||||
id: await generateNewIdAsync(),
|
entity: 'withdrawAccount',
|
||||||
action: 'remove',
|
operation: {
|
||||||
data: {},
|
id: await generateNewIdAsync(),
|
||||||
filter: {
|
action: 'remove',
|
||||||
id,
|
data: {},
|
||||||
},
|
filter: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
]);
|
||||||
]);
|
}
|
||||||
|
else {
|
||||||
|
return this.execute(undefined, undefined, undefined, [
|
||||||
|
{
|
||||||
|
entity: 'withdrawAccount',
|
||||||
|
operation: {
|
||||||
|
id: await generateNewIdAsync(),
|
||||||
|
action: 'disable',
|
||||||
|
data: {},
|
||||||
|
filter: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
resetAll() {
|
resetAll() {
|
||||||
this.clean();
|
this.clean();
|
||||||
|
|
@ -111,6 +130,11 @@ export default OakComponent({
|
||||||
await this.execute();
|
await this.execute();
|
||||||
this.resetAll();
|
this.resetAll();
|
||||||
},
|
},
|
||||||
|
switchDefault(id) {
|
||||||
|
const row = this.state.withdrawAccounts.find(ele => ele.id === id);
|
||||||
|
this.clean();
|
||||||
|
this.updateItem({ isDefault: !row.isDefault }, row.id);
|
||||||
|
},
|
||||||
pickOne(id) {
|
pickOne(id) {
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedId: id,
|
selectedId: id,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"noData": "您还没有配置过提现账号",
|
"noData": "您还没有配置过提现账号",
|
||||||
"confirmDelete": "确定删除",
|
"confirmDelete": "确定删除",
|
||||||
"areYouSure": "确认删除本账号吗?"
|
"areYouSure": "确认删除本账号吗?",
|
||||||
|
"default": "默认"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { EntityDict } from "../../../oak-app-domain";
|
||||||
|
import { RowWithActions, WebComponentProps } from "oak-frontend-base";
|
||||||
|
export default function render(props: WebComponentProps<EntityDict, 'withdrawAccount', false, {
|
||||||
|
withdrawAccounts?: (RowWithActions<EntityDict, 'withdrawAccount'> & {
|
||||||
|
label: string;
|
||||||
|
symbol: string;
|
||||||
|
allowUpdate?: boolean;
|
||||||
|
allowRemove?: boolean;
|
||||||
|
})[];
|
||||||
|
upsertId: string;
|
||||||
|
entity: string;
|
||||||
|
entityId: string;
|
||||||
|
isCreate?: boolean;
|
||||||
|
asPicker?: boolean;
|
||||||
|
allowCreate?: boolean;
|
||||||
|
selectedId?: string;
|
||||||
|
onCancel?: () => void;
|
||||||
|
}, {
|
||||||
|
setUpsertId: (id: string) => void;
|
||||||
|
doUpdate: () => Promise<void>;
|
||||||
|
resetAll: () => void;
|
||||||
|
updateAccount: (id: string) => void;
|
||||||
|
newAccount: () => void;
|
||||||
|
removeAccount: (id: string) => Promise<void>;
|
||||||
|
switchDefault: (id: string) => void;
|
||||||
|
pickOne: (id: string) => void;
|
||||||
|
confirmPick: () => void;
|
||||||
|
}>): React.JSX.Element;
|
||||||
|
|
@ -1 +1,87 @@
|
||||||
"use strict";
|
import React from 'react';
|
||||||
|
import { Popup, SwipeAction, List, Button, Result, Checkbox, Switch, Modal } from 'antd-mobile';
|
||||||
|
import Styles from './web.module.less';
|
||||||
|
import WdaUpsert from '../upsert';
|
||||||
|
export default function render(props) {
|
||||||
|
const { isCreate, withdrawAccounts, upsertId, oakFullpath, entity, entityId, asPicker, allowCreate, selectedId, onCancel, oakExecutable } = props.data;
|
||||||
|
const { t, setUpsertId, doUpdate, resetAll, updateAccount, newAccount, pickOne, confirmPick, removeAccount, switchDefault } = props.methods;
|
||||||
|
const U = upsertId && (<Popup visible={!!upsertId} destroyOnClose onMaskClick={() => resetAll()} onClose={() => resetAll()}>
|
||||||
|
<WdaUpsert oakPath={`${oakFullpath}.${upsertId}`} oakId={upsertId} entity={entity} entityId={entityId}/>
|
||||||
|
<div className={Styles.btns}>
|
||||||
|
<Button block onClick={() => resetAll()}>
|
||||||
|
{t('common::action.cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button color="primary" block disabled={oakExecutable !== true} onClick={() => doUpdate()}>
|
||||||
|
{t('common::confirm')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Popup>);
|
||||||
|
if (!withdrawAccounts?.length) {
|
||||||
|
return (<div className={Styles.container}>
|
||||||
|
{U}
|
||||||
|
<Result status="warning" title={t('noData')} description={<Button color="primary" onClick={() => newAccount()}>
|
||||||
|
{t('common::action.create')}
|
||||||
|
</Button>}/>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
const getItem = (ele, index) => (<List.Item key={index} prefix={<div className={Styles.avatar}>
|
||||||
|
{ele.symbol}
|
||||||
|
</div>} title={ele.name} description={ele.code} extra={asPicker ? <Checkbox checked={ele.id === selectedId} onChange={(checked) => {
|
||||||
|
if (checked) {
|
||||||
|
pickOne(ele.id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pickOne('');
|
||||||
|
}
|
||||||
|
}}/> : <Switch style={{ '--width': '72px' }} checked={ele.isDefault} checkedText={t('default')} onChange={() => switchDefault(ele.id)}/>}>
|
||||||
|
{ele.label}
|
||||||
|
</List.Item>);
|
||||||
|
return (<div className={Styles.container2}>
|
||||||
|
{U}
|
||||||
|
<div className={Styles.list}>
|
||||||
|
<List>
|
||||||
|
{withdrawAccounts.map((ele, idx) => {
|
||||||
|
const Item = getItem(ele, idx);
|
||||||
|
if (asPicker) {
|
||||||
|
return Item;
|
||||||
|
}
|
||||||
|
return (<SwipeAction key={idx} rightActions={[
|
||||||
|
{
|
||||||
|
key: 'delete',
|
||||||
|
text: t('common::action.remove'),
|
||||||
|
color: 'danger',
|
||||||
|
onClick: () => Modal.confirm({
|
||||||
|
title: t('confirmDelete'),
|
||||||
|
content: t('areYouSure'),
|
||||||
|
onConfirm: () => removeAccount(ele.id),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
]}>
|
||||||
|
{Item}
|
||||||
|
</SwipeAction>);
|
||||||
|
})}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
<div className={Styles.btns}>
|
||||||
|
{asPicker ? (<>
|
||||||
|
<Button block onClick={() => onCancel()} style={{ marginRight: 6 }}>
|
||||||
|
{t('common::action.cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button block color="primary" disabled={!selectedId} onClick={() => confirmPick()}>
|
||||||
|
{t('common::confirm')}
|
||||||
|
</Button>
|
||||||
|
</>) : (oakExecutable === true ?
|
||||||
|
<>
|
||||||
|
<Button block onClick={() => resetAll()}>
|
||||||
|
{t('common::reset')}
|
||||||
|
</Button>
|
||||||
|
<Button block color="primary" onClick={() => doUpdate()}>
|
||||||
|
{t('common::action.update')}
|
||||||
|
</Button>
|
||||||
|
</> :
|
||||||
|
allowCreate && <Button block color="primary" onClick={() => newAccount()}>
|
||||||
|
{t('common::action.create')}
|
||||||
|
</Button>)}
|
||||||
|
</div>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,41 @@
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.container2 {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
.list {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: bold;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--oak-color-primary);
|
||||||
|
background-color: silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
width: 72px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btns {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ export default function render(props: WebComponentProps<EntityDict, 'withdrawAcc
|
||||||
updateAccount: (id: string) => void;
|
updateAccount: (id: string) => void;
|
||||||
newAccount: () => void;
|
newAccount: () => void;
|
||||||
removeAccount: (id: string) => Promise<void>;
|
removeAccount: (id: string) => Promise<void>;
|
||||||
|
switchDefault: (id: string) => void;
|
||||||
pickOne: (id: string) => void;
|
pickOne: (id: string) => void;
|
||||||
confirmPick: () => void;
|
confirmPick: () => void;
|
||||||
}>): React.JSX.Element;
|
}>): React.JSX.Element;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Modal, Avatar, List, Button, Result, Checkbox } from 'antd';
|
import { Modal, Switch, Avatar, List, Button, Result, Checkbox } from 'antd';
|
||||||
import Styles from './web.pc.module.less';
|
import Styles from './web.pc.module.less';
|
||||||
import WdaUpsert from '../upsert';
|
import WdaUpsert from '../upsert';
|
||||||
export default function render(props) {
|
export default function render(props) {
|
||||||
const { isCreate, withdrawAccounts, upsertId, oakFullpath, entity, entityId, asPicker, allowCreate, selectedId, onCancel } = props.data;
|
const { isCreate, withdrawAccounts, upsertId, oakFullpath, entity, entityId, asPicker, allowCreate, selectedId, onCancel, oakExecutable } = props.data;
|
||||||
const { t, setUpsertId, doUpdate, resetAll, updateAccount, newAccount, pickOne, confirmPick, removeAccount } = props.methods;
|
const { t, setUpsertId, doUpdate, resetAll, updateAccount, newAccount, pickOne, confirmPick, removeAccount, switchDefault } = props.methods;
|
||||||
const U = upsertId && (<Modal open={!!upsertId} destroyOnClose title={`${isCreate ? t('common::action.create') : t('common::action.update')}${t('withdrawAccount:name')}`} onCancel={() => resetAll()} closeIcon={null} onOk={() => doUpdate()} okText={t('common::confirm')} cancelText={t('common::action.cancel')}>
|
const U = upsertId && (<Modal open={!!upsertId} destroyOnClose title={`${isCreate ? t('common::action.create') : t('common::action.update')}${t('withdrawAccount:name')}`} onCancel={() => resetAll()} closeIcon={null} onOk={() => doUpdate()} okText={t('common::confirm')} cancelText={t('common::action.cancel')}>
|
||||||
<WdaUpsert oakPath={`${oakFullpath}.${upsertId}`} oakId={upsertId} entity={entity} entityId={entityId}/>
|
<WdaUpsert oakPath={`${oakFullpath}.${upsertId}`} oakId={upsertId} entity={entity} entityId={entityId}/>
|
||||||
</Modal>);
|
</Modal>);
|
||||||
|
|
@ -19,7 +19,7 @@ export default function render(props) {
|
||||||
return (<div className={Styles.container2}>
|
return (<div className={Styles.container2}>
|
||||||
{U}
|
{U}
|
||||||
<div className={Styles.list}>
|
<div className={Styles.list}>
|
||||||
<List itemLayout="horizontal" dataSource={withdrawAccounts} renderItem={(item, index) => (<List.Item actions={asPicker ? [<Checkbox checked={item.id === selectedId} onChange={({ target }) => {
|
<List itemLayout="horizontal" dataSource={withdrawAccounts} renderItem={(item, index) => (<List.Item key={index} actions={asPicker ? [<Checkbox checked={item.id === selectedId} onChange={({ target }) => {
|
||||||
const { checked } = target;
|
const { checked } = target;
|
||||||
if (checked) {
|
if (checked) {
|
||||||
pickOne(item.id);
|
pickOne(item.id);
|
||||||
|
|
@ -28,10 +28,9 @@ export default function render(props) {
|
||||||
pickOne('');
|
pickOne('');
|
||||||
}
|
}
|
||||||
}}/>] : [
|
}}/>] : [
|
||||||
item.allowUpdate && <Button size="small" onClick={() => updateAccount(item.id)}>
|
item.allowUpdate &&
|
||||||
{t('common::action.update')}
|
<Switch checkedChildren={t('default')} value={item.isDefault} onChange={(value) => switchDefault(item.id)}/>,
|
||||||
</Button>,
|
<Button size="small" danger onClick={() => Modal.confirm({
|
||||||
item.allowRemove && <Button size="small" danger onClick={() => Modal.confirm({
|
|
||||||
title: t('confirmDelete'),
|
title: t('confirmDelete'),
|
||||||
content: t('areYouSure'),
|
content: t('areYouSure'),
|
||||||
okText: t('common::confirm'),
|
okText: t('common::confirm'),
|
||||||
|
|
@ -48,17 +47,25 @@ export default function render(props) {
|
||||||
</List.Item>)}/>
|
</List.Item>)}/>
|
||||||
</div>
|
</div>
|
||||||
<div className={Styles.btns}>
|
<div className={Styles.btns}>
|
||||||
{!asPicker && allowCreate && <Button type="primary" onClick={() => newAccount()}>
|
{asPicker ? (<>
|
||||||
{t('common::action.create')}
|
<Button onClick={() => onCancel()} style={{ marginRight: 6 }}>
|
||||||
</Button>}
|
{t('common::action.cancel')}
|
||||||
{asPicker && <>
|
</Button>
|
||||||
<Button onClick={() => onCancel()} style={{ marginRight: 6 }}>
|
<Button type="primary" disabled={!selectedId} onClick={() => confirmPick()}>
|
||||||
{t('common::action.cancel')}
|
{t('common::confirm')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="primary" disabled={!selectedId} onClick={() => confirmPick()}>
|
</>) : (oakExecutable === true ?
|
||||||
{t('common::confirm')}
|
<>
|
||||||
</Button>
|
<Button onClick={() => resetAll()}>
|
||||||
</>}
|
{t('common::reset')}
|
||||||
|
</Button>
|
||||||
|
<Button type="primary" onClick={() => doUpdate()}>
|
||||||
|
{t('common::action.update')}
|
||||||
|
</Button>
|
||||||
|
</> :
|
||||||
|
allowCreate && <Button type="primary" onClick={() => newAccount()}>
|
||||||
|
{t('common::action.create')}
|
||||||
|
</Button>)}
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { EntityDict } from "../../../oak-app-domain";
|
||||||
|
import { RowWithActions, WebComponentProps } from "oak-frontend-base";
|
||||||
|
export default function render(props: WebComponentProps<EntityDict, 'withdrawAccount', false, {
|
||||||
|
withdrawAccount?: RowWithActions<EntityDict, 'withdrawAccount'>;
|
||||||
|
channels?: {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
channel?: EntityDict['withdrawChannel']['Schema'];
|
||||||
|
isBank?: boolean;
|
||||||
|
isOffline?: boolean;
|
||||||
|
}, {
|
||||||
|
onSetChannelId: (id: string) => void;
|
||||||
|
onUpdate: <T extends keyof EntityDict['withdrawAccount']['OpSchema']>(attr: T, value: EntityDict['withdrawAccount']['OpSchema'][T] | null) => void;
|
||||||
|
}>): React.JSX.Element | undefined;
|
||||||
|
|
@ -1 +1,34 @@
|
||||||
"use strict";
|
import React from 'react';
|
||||||
|
import { Form, Switch, Input, Selector } from 'antd-mobile';
|
||||||
|
export default function render(props) {
|
||||||
|
const { withdrawAccount, channels, channel, isBank } = props.data;
|
||||||
|
const { t, onSetChannelId, onUpdate } = props.methods;
|
||||||
|
if (withdrawAccount) {
|
||||||
|
return (<Form layout="horizontal">
|
||||||
|
{channels && <Form.Item label={t('withdrawAccount:attr.channel')}>
|
||||||
|
<Selector disabled={!channels} options={channels} value={channel ? [channel.id] : undefined} onChange={(ids) => {
|
||||||
|
onSetChannelId(ids[0]);
|
||||||
|
}}/>
|
||||||
|
</Form.Item>}
|
||||||
|
{isBank &&
|
||||||
|
<Form.Item label={t('label.bank.org')}>
|
||||||
|
<Input value={withdrawAccount.org} onChange={(value) => {
|
||||||
|
onUpdate('org', value);
|
||||||
|
}}/>
|
||||||
|
</Form.Item>}
|
||||||
|
<Form.Item label={isBank ? t('label.bank.name') : t('label.others.name')}>
|
||||||
|
<Input value={withdrawAccount.name} onChange={(value) => {
|
||||||
|
onUpdate('name', value);
|
||||||
|
}}/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={t('withdrawAccount:attr.code')}>
|
||||||
|
<Input value={withdrawAccount.code} onChange={(value) => {
|
||||||
|
onUpdate('code', value);
|
||||||
|
}}/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={t('withdrawAccount:attr.isDefault')}>
|
||||||
|
<Switch checked={withdrawAccount.isDefault} onChange={(value) => onUpdate('isDefault', value)}/>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ export const authDeduceRelationMap = {};
|
||||||
export const selectFreeEntities = [
|
export const selectFreeEntities = [
|
||||||
'offlineAccount',
|
'offlineAccount',
|
||||||
'wpProduct',
|
'wpProduct',
|
||||||
|
'withdrawChannel',
|
||||||
|
'wpAccount',
|
||||||
];
|
];
|
||||||
export const updateFreeDict = {};
|
export const updateFreeDict = {};
|
||||||
export default {
|
export default {
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,41 @@ const actionAuths = [
|
||||||
id: 'user-account-withdraw',
|
id: 'user-account-withdraw',
|
||||||
pathId: 'user-account-withdraw',
|
pathId: 'user-account-withdraw',
|
||||||
deActions: ['select'],
|
deActions: ['select'],
|
||||||
|
},
|
||||||
|
//account
|
||||||
|
{
|
||||||
|
id: 'account-user',
|
||||||
|
pathId: 'user-acc',
|
||||||
|
deActions: ['select', 'deposit', 'withdraw', 'consume', 'loan'],
|
||||||
|
},
|
||||||
|
//deposit
|
||||||
|
{
|
||||||
|
id: 'deposit-creator',
|
||||||
|
pathId: 'creator-deposit',
|
||||||
|
deActions: ['create'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'deposit-account-user',
|
||||||
|
pathId: 'user-account-deposit',
|
||||||
|
deActions: ['fail'],
|
||||||
|
},
|
||||||
|
// accountOper
|
||||||
|
{
|
||||||
|
id: 'user-acc-oper',
|
||||||
|
pathId: 'user-acc-oper',
|
||||||
|
deActions: ['select', 'create'],
|
||||||
|
},
|
||||||
|
// withdrawAccount
|
||||||
|
{
|
||||||
|
id: 'user-withdrawAccount',
|
||||||
|
pathId: 'user-withdrawAccount',
|
||||||
|
deActions: ['select', 'create', 'remove', 'disable', 'update'],
|
||||||
|
},
|
||||||
|
// withdrawTransfer
|
||||||
|
{
|
||||||
|
id: 'user-acc-wdtransfer',
|
||||||
|
pathId: 'user-acc-wdtransfer',
|
||||||
|
deActions: ['select', 'create'],
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
export default actionAuths;
|
export default actionAuths;
|
||||||
|
|
|
||||||
|
|
@ -457,9 +457,10 @@ const i18ns = [
|
||||||
module: "oak-pay-business",
|
module: "oak-pay-business",
|
||||||
position: "src/components/withdraw/list",
|
position: "src/components/withdraw/list",
|
||||||
data: {
|
data: {
|
||||||
"loss": "预计手续费%{value}%元",
|
"loss": "预计手续费%{value}元",
|
||||||
"dealLoss": "手续费%{value}%元",
|
"dealLoss": "手续费%{value}元",
|
||||||
"count": "将分%{value}笔提现到您账户"
|
"count": "将分%{value}笔提现到您账户",
|
||||||
|
"noData": "您尚无提现记录"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -471,7 +472,8 @@ const i18ns = [
|
||||||
data: {
|
data: {
|
||||||
"noData": "您还没有配置过提现账号",
|
"noData": "您还没有配置过提现账号",
|
||||||
"confirmDelete": "确定删除",
|
"confirmDelete": "确定删除",
|
||||||
"areYouSure": "确认删除本账号吗?"
|
"areYouSure": "确认删除本账号吗?",
|
||||||
|
"default": "默认"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,48 @@ const paths = [
|
||||||
destEntity: 'withdraw',
|
destEntity: 'withdraw',
|
||||||
value: 'account.user',
|
value: 'account.user',
|
||||||
recursive: false,
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-acc',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'account',
|
||||||
|
value: 'user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-acc-oper',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'accountOper',
|
||||||
|
value: 'account.user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'creator-deposit',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'deposit',
|
||||||
|
value: 'creator',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-account-deposit',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'deposit',
|
||||||
|
value: 'account.user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-withdrawAccount',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'withdrawAccount',
|
||||||
|
value: 'user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-acc-wdtransfer',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'withdrawTransfer',
|
||||||
|
value: 'withdraw.account.user',
|
||||||
|
recursive: false,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
export default paths;
|
export default paths;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { getPayClazzAccountEntities } from '../utils/payClazz';
|
|
||||||
// 这里一定要注意两者的先后顺序,如果有注入更多的payEntity的话
|
// 这里一定要注意两者的先后顺序,如果有注入更多的payEntity的话
|
||||||
const entities = getPayClazzAccountEntities();
|
import { accountEntities } from '../checkers/abstractChecker';
|
||||||
const triggers = [
|
const triggers = [
|
||||||
...entities.filter(ele => !!ele).map((entity) => [
|
...accountEntities.filter(ele => !!ele).map((entity) => [
|
||||||
{
|
{
|
||||||
name: `当${entity}的帐户生成时,则生成对应的withDrawAccount`,
|
name: `当${entity}的帐户生成时,则生成对应的withDrawAccount`,
|
||||||
entity,
|
entity,
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ const triggers = [
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
action: 'create',
|
action: 'create',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { data } = operation;
|
const { data } = operation;
|
||||||
assert(!(data instanceof Array));
|
assert(!(data instanceof Array));
|
||||||
|
|
@ -171,6 +172,7 @@ const triggers = [
|
||||||
action: ['startPaying', 'succeedPaying', 'continuePaying', 'startClosing', 'succeedClosing', 'startRefunding',
|
action: ['startPaying', 'succeedPaying', 'continuePaying', 'startClosing', 'succeedClosing', 'startRefunding',
|
||||||
'refundAll', 'refundPartially'],
|
'refundAll', 'refundPartially'],
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { data, filter, action, id } = operation;
|
const { data, filter, action, id } = operation;
|
||||||
assert(typeof filter.id === 'string');
|
assert(typeof filter.id === 'string');
|
||||||
|
|
@ -286,6 +288,7 @@ const triggers = [
|
||||||
action: 'close',
|
action: 'close',
|
||||||
when: 'before',
|
when: 'before',
|
||||||
priority: 99,
|
priority: 99,
|
||||||
|
asRoot: true,
|
||||||
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', {
|
||||||
|
|
@ -372,6 +375,7 @@ const triggers = [
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
action: 'succeedPaying',
|
action: 'succeedPaying',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { data, filter } = operation;
|
const { data, filter } = operation;
|
||||||
const projection = {
|
const projection = {
|
||||||
|
|
@ -441,6 +445,7 @@ const triggers = [
|
||||||
{
|
{
|
||||||
name: '当account类型的pay的paid达到price,改为支付成功',
|
name: '当account类型的pay的paid达到price,改为支付成功',
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
|
asRoot: true,
|
||||||
action: ['startPaying', 'continuePaying'],
|
action: ['startPaying', 'continuePaying'],
|
||||||
check(operation) {
|
check(operation) {
|
||||||
return (!!operation.data.paid) && operation.data.paid > 0;
|
return (!!operation.data.paid) && operation.data.paid > 0;
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ const triggers = [
|
||||||
entity: 'refund',
|
entity: 'refund',
|
||||||
action: 'succeedRefunding',
|
action: 'succeedRefunding',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
name: '退款成功时,更新对应的pay状态以及对应的withdraw状态',
|
name: '退款成功时,更新对应的pay状态以及对应的withdraw状态',
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { filter } = operation;
|
const { filter } = operation;
|
||||||
|
|
@ -210,6 +211,7 @@ const triggers = [
|
||||||
entity: 'refund',
|
entity: 'refund',
|
||||||
action: 'failRefunding',
|
action: 'failRefunding',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
name: '退款失败时,更新对应的pay状态以及对应的withdraw状态',
|
name: '退款失败时,更新对应的pay状态以及对应的withdraw状态',
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { filter } = operation;
|
const { filter } = operation;
|
||||||
|
|
@ -252,6 +254,7 @@ const triggers = [
|
||||||
entity: 'refund',
|
entity: 'refund',
|
||||||
name: '当发起退款时,将对应的pay置退款中状态',
|
name: '当发起退款时,将对应的pay置退款中状态',
|
||||||
action: 'create',
|
action: 'create',
|
||||||
|
asRoot: true,
|
||||||
when: 'before',
|
when: 'before',
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { data } = operation;
|
const { data } = operation;
|
||||||
|
|
|
||||||
|
|
@ -1,76 +1,2 @@
|
||||||
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
const triggers = [];
|
||||||
import assert from 'assert';
|
|
||||||
const triggers = [
|
|
||||||
{
|
|
||||||
name: '当withdrawAccount帐户被设置为default时,将其它的default设为false',
|
|
||||||
entity: 'withdrawAccount',
|
|
||||||
action: 'update',
|
|
||||||
check(operation) {
|
|
||||||
return operation.data.isDefault === true;
|
|
||||||
},
|
|
||||||
when: 'after',
|
|
||||||
fn: async ({ operation }, context, option) => {
|
|
||||||
const { filter } = operation;
|
|
||||||
const accounts = await context.select('withdrawAccount', {
|
|
||||||
data: {
|
|
||||||
id: 1,
|
|
||||||
entity: 1,
|
|
||||||
entityId: 1,
|
|
||||||
},
|
|
||||||
filter,
|
|
||||||
}, {});
|
|
||||||
assert(accounts.length === 1);
|
|
||||||
for (const account of accounts) {
|
|
||||||
const { entity, entityId, id } = account;
|
|
||||||
await context.operate('withdrawAccount', {
|
|
||||||
id: await generateNewIdAsync(),
|
|
||||||
action: 'update',
|
|
||||||
data: {
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
entity,
|
|
||||||
entityId,
|
|
||||||
isDefault: true,
|
|
||||||
id: {
|
|
||||||
$ne: id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '当withdrawAccount帐户创建为default时,将其它的default设为false',
|
|
||||||
entity: 'withdrawAccount',
|
|
||||||
action: 'create',
|
|
||||||
when: 'after',
|
|
||||||
fn: async ({ operation }, context, option) => {
|
|
||||||
const { data } = operation;
|
|
||||||
assert(!(data instanceof Array));
|
|
||||||
const { id, entity, entityId, isDefault } = data;
|
|
||||||
assert(entity && entityId);
|
|
||||||
if (isDefault) {
|
|
||||||
await context.operate('withdrawAccount', {
|
|
||||||
id: await generateNewIdAsync(),
|
|
||||||
action: 'update',
|
|
||||||
data: {
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
entity,
|
|
||||||
entityId,
|
|
||||||
isDefault: true,
|
|
||||||
id: {
|
|
||||||
$ne: id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}, {});
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
];
|
|
||||||
export default triggers;
|
export default triggers;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ import { EntityDict } from '../../oak-app-domain';
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
||||||
import PayClazz from '../../types/PayClazz';
|
import PayClazz from '../../types/PayClazz';
|
||||||
import { BRC } from '../../types/RuntimeCxt';
|
import { BRC } from '../../types/RuntimeCxt';
|
||||||
|
import { StorageSchema } from 'oak-domain/lib/types/Storage';
|
||||||
type PayClazzConstructor = (applicationId: string, entityId: string, context: BRC) => Promise<PayClazz>;
|
type PayClazzConstructor = (applicationId: string, entityId: string, context: BRC) => Promise<PayClazz>;
|
||||||
export declare function registerPayClazzEntity<ED extends EntityDict & BaseEntityDict>(entity: keyof ED, def: {
|
export declare function registerPayClazzEntity<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(entity: T, def: {
|
||||||
clazzConstructor: PayClazzConstructor;
|
clazzConstructor: PayClazzConstructor;
|
||||||
accountEntity: keyof ED;
|
accountEntity: keyof ED;
|
||||||
}): void;
|
}, schema: StorageSchema<ED>): void;
|
||||||
export declare function getPayClazzAccountEntities<ED extends EntityDict & BaseEntityDict>(): (keyof ED)[];
|
|
||||||
export declare function getPayClazz(applicationId: string, entity: EntityDict['pay']['OpSchema']['entity'], entityId: string, context: BRC): Promise<PayClazz>;
|
export declare function getPayClazz(applicationId: string, entity: EntityDict['pay']['OpSchema']['entity'], entityId: string, context: BRC): Promise<PayClazz>;
|
||||||
export {};
|
export {};
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import assert from 'assert';
|
||||||
import Offline from './Offline';
|
import Offline from './Offline';
|
||||||
import Account from './Account';
|
import Account from './Account';
|
||||||
import WechatPay from './WechatPay';
|
import WechatPay from './WechatPay';
|
||||||
|
import { registerAccountEntity } from '../../checkers/abstractChecker';
|
||||||
const PayChannelDict = {};
|
const PayChannelDict = {};
|
||||||
const PayClazzEntityDict = {
|
const PayClazzEntityDict = {
|
||||||
'account': {
|
'account': {
|
||||||
|
|
@ -106,19 +107,27 @@ const PayClazzEntityDict = {
|
||||||
// 这里用一个flag来表达先后顺序,如果有registerPayClazzEntity,框架应保证register在get之前
|
// 这里用一个flag来表达先后顺序,如果有registerPayClazzEntity,框架应保证register在get之前
|
||||||
// 目前因为没有registerPayClazzEntity,所以没测,可能不对。by Xc 20240608
|
// 目前因为没有registerPayClazzEntity,所以没测,可能不对。by Xc 20240608
|
||||||
let MODULE_USED = false;
|
let MODULE_USED = false;
|
||||||
export function registerPayClazzEntity(entity, def) {
|
export function registerPayClazzEntity(entity, def, schema) {
|
||||||
assert(!MODULE_USED);
|
if (!MODULE_USED) {
|
||||||
|
assert(!MODULE_USED);
|
||||||
|
}
|
||||||
PayClazzEntityDict[entity] = {
|
PayClazzEntityDict[entity] = {
|
||||||
accountEntity: def.accountEntity,
|
accountEntity: def.accountEntity,
|
||||||
clazzConstructor: def.clazzConstructor,
|
clazzConstructor: def.clazzConstructor,
|
||||||
};
|
};
|
||||||
}
|
// 检查此entity是否符合注册要求
|
||||||
export function getPayClazzAccountEntities() {
|
const { attributes } = schema[entity];
|
||||||
MODULE_USED = true;
|
const { attributes: payAttr } = schema.pay;
|
||||||
return Object.keys(PayClazzEntityDict).map(ele => PayClazzEntityDict[ele].accountEntity);
|
const { attributes: accountAttr } = schema[def.accountEntity];
|
||||||
|
assert(payAttr.entity.enumeration?.includes(entity));
|
||||||
|
assert(accountAttr.price && accountAttr.price.type === 'decimal');
|
||||||
|
assert(accountAttr.systemId && accountAttr.systemId.type === 'ref' && accountAttr.systemId.ref === 'system');
|
||||||
|
registerAccountEntity(def.accountEntity);
|
||||||
}
|
}
|
||||||
export async function getPayClazz(applicationId, entity, entityId, context) {
|
export async function getPayClazz(applicationId, entity, entityId, context) {
|
||||||
MODULE_USED = true;
|
if (!MODULE_USED) {
|
||||||
|
assert(!MODULE_USED);
|
||||||
|
}
|
||||||
const key = entity === 'account' ? entity : `${entity}.${entityId}`;
|
const key = entity === 'account' ? entity : `${entity}.${entityId}`;
|
||||||
if (PayChannelDict.hasOwnProperty(key)) {
|
if (PayChannelDict.hasOwnProperty(key)) {
|
||||||
return PayChannelDict[key];
|
return PayChannelDict[key];
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,9 @@ async function getWithdrawCreateData(params, context) {
|
||||||
data: ele,
|
data: ele,
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
data.refund$entity = [];
|
||||||
|
}
|
||||||
if (totalPrice > price2) {
|
if (totalPrice > price2) {
|
||||||
// 如果还有要退的部分,就从withdrawAccount来进行转账
|
// 如果还有要退的部分,就从withdrawAccount来进行转账
|
||||||
const rest = totalPrice - price2;
|
const rest = totalPrice - price2;
|
||||||
|
|
@ -200,6 +203,10 @@ async function getWithdrawCreateData(params, context) {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// 保持结构完整,让上层可以和withdraw$detail同构渲染
|
||||||
|
data.withdrawTransfer$withdraw = [];
|
||||||
|
}
|
||||||
data.loss = totalLoss;
|
data.loss = totalLoss;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
import { RuntimeCxt } from '../types/RuntimeCxt';
|
import { RuntimeCxt } from '../types/RuntimeCxt';
|
||||||
import { Checker } from 'oak-domain/lib/types/Auth';
|
import { Checker } from 'oak-domain/lib/types/Auth';
|
||||||
|
export declare function registerAccountEntity<ED extends EntityDict>(entity: keyof ED): void;
|
||||||
|
export declare const accountEntities: string[];
|
||||||
declare const triggers: Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
|
declare const triggers: Checker<EntityDict, keyof EntityDict, RuntimeCxt>[];
|
||||||
export default triggers;
|
export default triggers;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.accountEntities = exports.registerAccountEntity = void 0;
|
||||||
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
||||||
const payClazz_1 = require("../utils/payClazz");
|
// 当注入一个新的account entity时,将withdrawChannel的删除与之相关联
|
||||||
// 当注入一个新的pay entity时,将account的删除与之相关联
|
function registerAccountEntity(entity) {
|
||||||
const entities = (0, payClazz_1.getPayClazzAccountEntities)();
|
exports.accountEntities.push(entity);
|
||||||
|
}
|
||||||
|
exports.registerAccountEntity = registerAccountEntity;
|
||||||
|
exports.accountEntities = ['wpAccount', 'offlineAccount'];
|
||||||
const triggers = [
|
const triggers = [
|
||||||
...entities.filter(ele => !!ele).map((entity) => [
|
...exports.accountEntities.filter(ele => !!ele).map((entity) => [
|
||||||
{
|
{
|
||||||
entity,
|
entity,
|
||||||
action: 'remove',
|
action: 'remove',
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ const application_1 = tslib_1.__importDefault(require("./application"));
|
||||||
const offlineAccount_1 = tslib_1.__importDefault(require("./offlineAccount"));
|
const offlineAccount_1 = tslib_1.__importDefault(require("./offlineAccount"));
|
||||||
const wpProduct_1 = tslib_1.__importDefault(require("./wpProduct"));
|
const wpProduct_1 = tslib_1.__importDefault(require("./wpProduct"));
|
||||||
const abstractChecker_1 = tslib_1.__importDefault(require("./abstractChecker"));
|
const abstractChecker_1 = tslib_1.__importDefault(require("./abstractChecker"));
|
||||||
|
const withdrawAccount_1 = tslib_1.__importDefault(require("./withdrawAccount"));
|
||||||
const checkers = [
|
const checkers = [
|
||||||
|
...withdrawAccount_1.default,
|
||||||
...abstractChecker_1.default,
|
...abstractChecker_1.default,
|
||||||
...accountOper_1.default,
|
...accountOper_1.default,
|
||||||
...pay_1.default,
|
...pay_1.default,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { Checker } from 'oak-domain/lib/types/Auth';
|
||||||
|
import { EntityDict } from '../oak-app-domain';
|
||||||
|
import { RuntimeCxt } from '../types/RuntimeCxt';
|
||||||
|
declare const checkers: Checker<EntityDict, 'withdrawAccount', RuntimeCxt>[];
|
||||||
|
export default checkers;
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const tslib_1 = require("tslib");
|
||||||
|
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
||||||
|
const executor_1 = require("oak-domain/lib/utils/executor");
|
||||||
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||||||
|
const checkers = [
|
||||||
|
{
|
||||||
|
entity: 'withdrawAccount',
|
||||||
|
type: 'logical',
|
||||||
|
action: 'create',
|
||||||
|
checker(operation, context, option) {
|
||||||
|
const { data } = operation;
|
||||||
|
if (data) {
|
||||||
|
const { id, entity, entityId, isDefault } = data;
|
||||||
|
if (entity && entityId && isDefault) {
|
||||||
|
return context.operate('withdrawAccount', {
|
||||||
|
id: (0, uuid_1.generateNewId)(),
|
||||||
|
action: 'update',
|
||||||
|
data: {
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
entity,
|
||||||
|
entityId,
|
||||||
|
isDefault: true,
|
||||||
|
id: {
|
||||||
|
$ne: id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entity: 'withdrawAccount',
|
||||||
|
type: 'logical',
|
||||||
|
action: 'update',
|
||||||
|
checker(operation, context, option) {
|
||||||
|
const { data, filter } = operation;
|
||||||
|
if (data?.isDefault) {
|
||||||
|
return (0, executor_1.pipeline)(() => context.select('withdrawAccount', {
|
||||||
|
data: {
|
||||||
|
id: 1,
|
||||||
|
entity: 1,
|
||||||
|
entityId: 1,
|
||||||
|
},
|
||||||
|
filter,
|
||||||
|
}, {}), (accounts) => {
|
||||||
|
(0, assert_1.default)(accounts.length === 1);
|
||||||
|
const [account] = accounts;
|
||||||
|
const { entity, entityId, id } = account;
|
||||||
|
return context.operate('withdrawAccount', {
|
||||||
|
id: (0, uuid_1.generateNewId)(),
|
||||||
|
action: 'update',
|
||||||
|
data: {
|
||||||
|
isDefault: false,
|
||||||
|
},
|
||||||
|
filter: {
|
||||||
|
entity,
|
||||||
|
entityId,
|
||||||
|
isDefault: true,
|
||||||
|
id: {
|
||||||
|
$ne: id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, option);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
exports.default = checkers;
|
||||||
|
|
@ -6,6 +6,8 @@ exports.authDeduceRelationMap = {};
|
||||||
exports.selectFreeEntities = [
|
exports.selectFreeEntities = [
|
||||||
'offlineAccount',
|
'offlineAccount',
|
||||||
'wpProduct',
|
'wpProduct',
|
||||||
|
'withdrawChannel',
|
||||||
|
'wpAccount',
|
||||||
];
|
];
|
||||||
exports.updateFreeDict = {};
|
exports.updateFreeDict = {};
|
||||||
exports.default = {
|
exports.default = {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,41 @@ const actionAuths = [
|
||||||
id: 'user-account-withdraw',
|
id: 'user-account-withdraw',
|
||||||
pathId: 'user-account-withdraw',
|
pathId: 'user-account-withdraw',
|
||||||
deActions: ['select'],
|
deActions: ['select'],
|
||||||
|
},
|
||||||
|
//account
|
||||||
|
{
|
||||||
|
id: 'account-user',
|
||||||
|
pathId: 'user-acc',
|
||||||
|
deActions: ['select', 'deposit', 'withdraw', 'consume', 'loan'],
|
||||||
|
},
|
||||||
|
//deposit
|
||||||
|
{
|
||||||
|
id: 'deposit-creator',
|
||||||
|
pathId: 'creator-deposit',
|
||||||
|
deActions: ['create'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'deposit-account-user',
|
||||||
|
pathId: 'user-account-deposit',
|
||||||
|
deActions: ['fail'],
|
||||||
|
},
|
||||||
|
// accountOper
|
||||||
|
{
|
||||||
|
id: 'user-acc-oper',
|
||||||
|
pathId: 'user-acc-oper',
|
||||||
|
deActions: ['select', 'create'],
|
||||||
|
},
|
||||||
|
// withdrawAccount
|
||||||
|
{
|
||||||
|
id: 'user-withdrawAccount',
|
||||||
|
pathId: 'user-withdrawAccount',
|
||||||
|
deActions: ['select', 'create', 'remove', 'disable', 'update'],
|
||||||
|
},
|
||||||
|
// withdrawTransfer
|
||||||
|
{
|
||||||
|
id: 'user-acc-wdtransfer',
|
||||||
|
pathId: 'user-acc-wdtransfer',
|
||||||
|
deActions: ['select', 'create'],
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
exports.default = actionAuths;
|
exports.default = actionAuths;
|
||||||
|
|
|
||||||
|
|
@ -459,9 +459,10 @@ const i18ns = [
|
||||||
module: "oak-pay-business",
|
module: "oak-pay-business",
|
||||||
position: "src/components/withdraw/list",
|
position: "src/components/withdraw/list",
|
||||||
data: {
|
data: {
|
||||||
"loss": "预计手续费%{value}%元",
|
"loss": "预计手续费%{value}元",
|
||||||
"dealLoss": "手续费%{value}%元",
|
"dealLoss": "手续费%{value}元",
|
||||||
"count": "将分%{value}笔提现到您账户"
|
"count": "将分%{value}笔提现到您账户",
|
||||||
|
"noData": "您尚无提现记录"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -473,7 +474,8 @@ const i18ns = [
|
||||||
data: {
|
data: {
|
||||||
"noData": "您还没有配置过提现账号",
|
"noData": "您还没有配置过提现账号",
|
||||||
"confirmDelete": "确定删除",
|
"confirmDelete": "确定删除",
|
||||||
"areYouSure": "确认删除本账号吗?"
|
"areYouSure": "确认删除本账号吗?",
|
||||||
|
"default": "默认"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,48 @@ const paths = [
|
||||||
destEntity: 'withdraw',
|
destEntity: 'withdraw',
|
||||||
value: 'account.user',
|
value: 'account.user',
|
||||||
recursive: false,
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-acc',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'account',
|
||||||
|
value: 'user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-acc-oper',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'accountOper',
|
||||||
|
value: 'account.user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'creator-deposit',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'deposit',
|
||||||
|
value: 'creator',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-account-deposit',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'deposit',
|
||||||
|
value: 'account.user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-withdrawAccount',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'withdrawAccount',
|
||||||
|
value: 'user',
|
||||||
|
recursive: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'user-acc-wdtransfer',
|
||||||
|
sourceEntity: 'user',
|
||||||
|
destEntity: 'withdrawTransfer',
|
||||||
|
value: 'withdraw.account.user',
|
||||||
|
recursive: false,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
exports.default = paths;
|
exports.default = paths;
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const tslib_1 = require("tslib");
|
const tslib_1 = require("tslib");
|
||||||
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
||||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
||||||
const payClazz_1 = require("../utils/payClazz");
|
|
||||||
// 这里一定要注意两者的先后顺序,如果有注入更多的payEntity的话
|
// 这里一定要注意两者的先后顺序,如果有注入更多的payEntity的话
|
||||||
const entities = (0, payClazz_1.getPayClazzAccountEntities)();
|
const abstractChecker_1 = require("../checkers/abstractChecker");
|
||||||
const triggers = [
|
const triggers = [
|
||||||
...entities.filter(ele => !!ele).map((entity) => [
|
...abstractChecker_1.accountEntities.filter(ele => !!ele).map((entity) => [
|
||||||
{
|
{
|
||||||
name: `当${entity}的帐户生成时,则生成对应的withDrawAccount`,
|
name: `当${entity}的帐户生成时,则生成对应的withDrawAccount`,
|
||||||
entity,
|
entity,
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,7 @@ const triggers = [
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
action: 'create',
|
action: 'create',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { data } = operation;
|
const { data } = operation;
|
||||||
(0, assert_1.default)(!(data instanceof Array));
|
(0, assert_1.default)(!(data instanceof Array));
|
||||||
|
|
@ -174,6 +175,7 @@ const triggers = [
|
||||||
action: ['startPaying', 'succeedPaying', 'continuePaying', 'startClosing', 'succeedClosing', 'startRefunding',
|
action: ['startPaying', 'succeedPaying', 'continuePaying', 'startClosing', 'succeedClosing', 'startRefunding',
|
||||||
'refundAll', 'refundPartially'],
|
'refundAll', 'refundPartially'],
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
fn: async ({ operation }, context, option) => {
|
fn: async ({ operation }, context, option) => {
|
||||||
const { data, filter, action, id } = operation;
|
const { data, filter, action, id } = operation;
|
||||||
(0, assert_1.default)(typeof filter.id === 'string');
|
(0, assert_1.default)(typeof filter.id === 'string');
|
||||||
|
|
@ -289,6 +291,7 @@ const triggers = [
|
||||||
action: 'close',
|
action: 'close',
|
||||||
when: 'before',
|
when: 'before',
|
||||||
priority: 99,
|
priority: 99,
|
||||||
|
asRoot: true,
|
||||||
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', {
|
||||||
|
|
@ -375,6 +378,7 @@ const triggers = [
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
action: 'succeedPaying',
|
action: 'succeedPaying',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { data, filter } = operation;
|
const { data, filter } = operation;
|
||||||
const projection = {
|
const projection = {
|
||||||
|
|
@ -444,6 +448,7 @@ const triggers = [
|
||||||
{
|
{
|
||||||
name: '当account类型的pay的paid达到price,改为支付成功',
|
name: '当account类型的pay的paid达到price,改为支付成功',
|
||||||
entity: 'pay',
|
entity: 'pay',
|
||||||
|
asRoot: true,
|
||||||
action: ['startPaying', 'continuePaying'],
|
action: ['startPaying', 'continuePaying'],
|
||||||
check(operation) {
|
check(operation) {
|
||||||
return (!!operation.data.paid) && operation.data.paid > 0;
|
return (!!operation.data.paid) && operation.data.paid > 0;
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ const triggers = [
|
||||||
entity: 'refund',
|
entity: 'refund',
|
||||||
action: 'succeedRefunding',
|
action: 'succeedRefunding',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
name: '退款成功时,更新对应的pay状态以及对应的withdraw状态',
|
name: '退款成功时,更新对应的pay状态以及对应的withdraw状态',
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { filter } = operation;
|
const { filter } = operation;
|
||||||
|
|
@ -213,6 +214,7 @@ const triggers = [
|
||||||
entity: 'refund',
|
entity: 'refund',
|
||||||
action: 'failRefunding',
|
action: 'failRefunding',
|
||||||
when: 'after',
|
when: 'after',
|
||||||
|
asRoot: true,
|
||||||
name: '退款失败时,更新对应的pay状态以及对应的withdraw状态',
|
name: '退款失败时,更新对应的pay状态以及对应的withdraw状态',
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { filter } = operation;
|
const { filter } = operation;
|
||||||
|
|
@ -255,6 +257,7 @@ const triggers = [
|
||||||
entity: 'refund',
|
entity: 'refund',
|
||||||
name: '当发起退款时,将对应的pay置退款中状态',
|
name: '当发起退款时,将对应的pay置退款中状态',
|
||||||
action: 'create',
|
action: 'create',
|
||||||
|
asRoot: true,
|
||||||
when: 'before',
|
when: 'before',
|
||||||
fn: async ({ operation }, context) => {
|
fn: async ({ operation }, context) => {
|
||||||
const { data } = operation;
|
const { data } = operation;
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,4 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const tslib_1 = require("tslib");
|
const triggers = [];
|
||||||
const uuid_1 = require("oak-domain/lib/utils/uuid");
|
|
||||||
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
||||||
const triggers = [
|
|
||||||
{
|
|
||||||
name: '当withdrawAccount帐户被设置为default时,将其它的default设为false',
|
|
||||||
entity: 'withdrawAccount',
|
|
||||||
action: 'update',
|
|
||||||
check(operation) {
|
|
||||||
return operation.data.isDefault === true;
|
|
||||||
},
|
|
||||||
when: 'after',
|
|
||||||
fn: async ({ operation }, context, option) => {
|
|
||||||
const { filter } = operation;
|
|
||||||
const accounts = await context.select('withdrawAccount', {
|
|
||||||
data: {
|
|
||||||
id: 1,
|
|
||||||
entity: 1,
|
|
||||||
entityId: 1,
|
|
||||||
},
|
|
||||||
filter,
|
|
||||||
}, {});
|
|
||||||
(0, assert_1.default)(accounts.length === 1);
|
|
||||||
for (const account of accounts) {
|
|
||||||
const { entity, entityId, id } = account;
|
|
||||||
await context.operate('withdrawAccount', {
|
|
||||||
id: await (0, uuid_1.generateNewIdAsync)(),
|
|
||||||
action: 'update',
|
|
||||||
data: {
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
entity,
|
|
||||||
entityId,
|
|
||||||
isDefault: true,
|
|
||||||
id: {
|
|
||||||
$ne: id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '当withdrawAccount帐户创建为default时,将其它的default设为false',
|
|
||||||
entity: 'withdrawAccount',
|
|
||||||
action: 'create',
|
|
||||||
when: 'after',
|
|
||||||
fn: async ({ operation }, context, option) => {
|
|
||||||
const { data } = operation;
|
|
||||||
(0, assert_1.default)(!(data instanceof Array));
|
|
||||||
const { id, entity, entityId, isDefault } = data;
|
|
||||||
(0, assert_1.default)(entity && entityId);
|
|
||||||
if (isDefault) {
|
|
||||||
await context.operate('withdrawAccount', {
|
|
||||||
id: await (0, uuid_1.generateNewIdAsync)(),
|
|
||||||
action: 'update',
|
|
||||||
data: {
|
|
||||||
isDefault: false,
|
|
||||||
},
|
|
||||||
filter: {
|
|
||||||
entity,
|
|
||||||
entityId,
|
|
||||||
isDefault: true,
|
|
||||||
id: {
|
|
||||||
$ne: id,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}, {});
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
];
|
|
||||||
exports.default = triggers;
|
exports.default = triggers;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ import { EntityDict } from '../../oak-app-domain';
|
||||||
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
import { EntityDict as BaseEntityDict } from 'oak-domain/lib/types/Entity';
|
||||||
import PayClazz from '../../types/PayClazz';
|
import PayClazz from '../../types/PayClazz';
|
||||||
import { BRC } from '../../types/RuntimeCxt';
|
import { BRC } from '../../types/RuntimeCxt';
|
||||||
|
import { StorageSchema } from 'oak-domain/lib/types/Storage';
|
||||||
type PayClazzConstructor = (applicationId: string, entityId: string, context: BRC) => Promise<PayClazz>;
|
type PayClazzConstructor = (applicationId: string, entityId: string, context: BRC) => Promise<PayClazz>;
|
||||||
export declare function registerPayClazzEntity<ED extends EntityDict & BaseEntityDict>(entity: keyof ED, def: {
|
export declare function registerPayClazzEntity<ED extends EntityDict & BaseEntityDict, T extends keyof ED>(entity: T, def: {
|
||||||
clazzConstructor: PayClazzConstructor;
|
clazzConstructor: PayClazzConstructor;
|
||||||
accountEntity: keyof ED;
|
accountEntity: keyof ED;
|
||||||
}): void;
|
}, schema: StorageSchema<ED>): void;
|
||||||
export declare function getPayClazzAccountEntities<ED extends EntityDict & BaseEntityDict>(): (keyof ED)[];
|
|
||||||
export declare function getPayClazz(applicationId: string, entity: EntityDict['pay']['OpSchema']['entity'], entityId: string, context: BRC): Promise<PayClazz>;
|
export declare function getPayClazz(applicationId: string, entity: EntityDict['pay']['OpSchema']['entity'], entityId: string, context: BRC): Promise<PayClazz>;
|
||||||
export {};
|
export {};
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.getPayClazz = exports.getPayClazzAccountEntities = exports.registerPayClazzEntity = void 0;
|
exports.getPayClazz = exports.registerPayClazzEntity = void 0;
|
||||||
const tslib_1 = require("tslib");
|
const tslib_1 = require("tslib");
|
||||||
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 Offline_1 = tslib_1.__importDefault(require("./Offline"));
|
||||||
const Account_1 = tslib_1.__importDefault(require("./Account"));
|
const Account_1 = tslib_1.__importDefault(require("./Account"));
|
||||||
const WechatPay_1 = tslib_1.__importDefault(require("./WechatPay"));
|
const WechatPay_1 = tslib_1.__importDefault(require("./WechatPay"));
|
||||||
|
const abstractChecker_1 = require("../../checkers/abstractChecker");
|
||||||
const PayChannelDict = {};
|
const PayChannelDict = {};
|
||||||
const PayClazzEntityDict = {
|
const PayClazzEntityDict = {
|
||||||
'account': {
|
'account': {
|
||||||
|
|
@ -110,21 +111,28 @@ const PayClazzEntityDict = {
|
||||||
// 这里用一个flag来表达先后顺序,如果有registerPayClazzEntity,框架应保证register在get之前
|
// 这里用一个flag来表达先后顺序,如果有registerPayClazzEntity,框架应保证register在get之前
|
||||||
// 目前因为没有registerPayClazzEntity,所以没测,可能不对。by Xc 20240608
|
// 目前因为没有registerPayClazzEntity,所以没测,可能不对。by Xc 20240608
|
||||||
let MODULE_USED = false;
|
let MODULE_USED = false;
|
||||||
function registerPayClazzEntity(entity, def) {
|
function registerPayClazzEntity(entity, def, schema) {
|
||||||
(0, assert_1.default)(!MODULE_USED);
|
if (!MODULE_USED) {
|
||||||
|
(0, assert_1.default)(!MODULE_USED);
|
||||||
|
}
|
||||||
PayClazzEntityDict[entity] = {
|
PayClazzEntityDict[entity] = {
|
||||||
accountEntity: def.accountEntity,
|
accountEntity: def.accountEntity,
|
||||||
clazzConstructor: def.clazzConstructor,
|
clazzConstructor: def.clazzConstructor,
|
||||||
};
|
};
|
||||||
|
// 检查此entity是否符合注册要求
|
||||||
|
const { attributes } = schema[entity];
|
||||||
|
const { attributes: payAttr } = schema.pay;
|
||||||
|
const { attributes: accountAttr } = schema[def.accountEntity];
|
||||||
|
(0, assert_1.default)(payAttr.entity.enumeration?.includes(entity));
|
||||||
|
(0, assert_1.default)(accountAttr.price && accountAttr.price.type === 'decimal');
|
||||||
|
(0, assert_1.default)(accountAttr.systemId && accountAttr.systemId.type === 'ref' && accountAttr.systemId.ref === 'system');
|
||||||
|
(0, abstractChecker_1.registerAccountEntity)(def.accountEntity);
|
||||||
}
|
}
|
||||||
exports.registerPayClazzEntity = registerPayClazzEntity;
|
exports.registerPayClazzEntity = registerPayClazzEntity;
|
||||||
function getPayClazzAccountEntities() {
|
|
||||||
MODULE_USED = true;
|
|
||||||
return Object.keys(PayClazzEntityDict).map(ele => PayClazzEntityDict[ele].accountEntity);
|
|
||||||
}
|
|
||||||
exports.getPayClazzAccountEntities = getPayClazzAccountEntities;
|
|
||||||
async function getPayClazz(applicationId, entity, entityId, context) {
|
async function getPayClazz(applicationId, entity, entityId, context) {
|
||||||
MODULE_USED = true;
|
if (!MODULE_USED) {
|
||||||
|
(0, assert_1.default)(!MODULE_USED);
|
||||||
|
}
|
||||||
const key = entity === 'account' ? entity : `${entity}.${entityId}`;
|
const key = entity === 'account' ? entity : `${entity}.${entityId}`;
|
||||||
if (PayChannelDict.hasOwnProperty(key)) {
|
if (PayChannelDict.hasOwnProperty(key)) {
|
||||||
return PayChannelDict[key];
|
return PayChannelDict[key];
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
import { generateNewId } from 'oak-domain/lib/utils/uuid';
|
import { generateNewId } from 'oak-domain/lib/utils/uuid';
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
import { BRC, RuntimeCxt } from '../types/RuntimeCxt';
|
import { BRC, RuntimeCxt } from '../types/RuntimeCxt';
|
||||||
import assert from 'assert';
|
|
||||||
import { getPayClazzAccountEntities } from '../utils/payClazz';
|
|
||||||
import { Checker, LogicalChecker } from 'oak-domain/lib/types/Auth';
|
import { Checker, LogicalChecker } from 'oak-domain/lib/types/Auth';
|
||||||
|
|
||||||
// 当注入一个新的pay entity时,将account的删除与之相关联
|
// 当注入一个新的account entity时,将withdrawChannel的删除与之相关联
|
||||||
const entities = getPayClazzAccountEntities<EntityDict>();
|
export function registerAccountEntity<ED extends EntityDict>(entity: keyof ED) {
|
||||||
|
accountEntities.push(entity as string);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const accountEntities = ['wpAccount', 'offlineAccount'];
|
||||||
|
|
||||||
const triggers: Checker<EntityDict, keyof EntityDict, RuntimeCxt>[] = [
|
const triggers: Checker<EntityDict, keyof EntityDict, RuntimeCxt>[] = [
|
||||||
...entities.filter(ele => !!ele).map(
|
...accountEntities.filter(ele => !!ele).map(
|
||||||
(entity) => [
|
(entity) => [
|
||||||
{
|
{
|
||||||
entity,
|
entity,
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,25 @@ export default OakComponent({
|
||||||
systemId: 1,
|
systemId: 1,
|
||||||
price: 1,
|
price: 1,
|
||||||
enabled: 1,
|
enabled: 1,
|
||||||
|
taxLossRatio: 1,
|
||||||
|
refundCompensateRatio: 1,
|
||||||
|
refundGapDays: 1,
|
||||||
|
allowWithdrawTransfer: 1,
|
||||||
|
withdrawTransferLossRatio: 1,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
systemId: '',
|
systemId: '',
|
||||||
},
|
},
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
filter() {
|
||||||
|
const { systemId } = this.props;
|
||||||
|
return {
|
||||||
|
systemId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
formData({ data, legalActions }) {
|
formData({ data, legalActions }) {
|
||||||
return {
|
return {
|
||||||
accounts: data.map(
|
accounts: data.map(
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: flex-start;
|
align-items: stretch;
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
border: 0.1px solid silver;
|
border: 0.1px solid silver;
|
||||||
|
|
|
||||||
|
|
@ -8,31 +8,33 @@ import Styles from './web.pc.module.less';
|
||||||
import Upsert from '../upsert';
|
import Upsert from '../upsert';
|
||||||
import { OakAttrNotNullException, OakException } from 'oak-domain/lib/types';
|
import { OakAttrNotNullException, OakException } from 'oak-domain/lib/types';
|
||||||
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
||||||
|
import { ToYuan } from 'oak-domain/lib/utils/money';
|
||||||
|
|
||||||
function OfflineAccount(props: {
|
export function OfflineAccount(props: {
|
||||||
account: RowWithActions<EntityDict, 'offlineAccount'> & { color: string };
|
data: RowWithActions<EntityDict, 'offlineAccount'> & { color: string };
|
||||||
t: (k: string, param?: any) => string;
|
t: (k: string, param?: any) => string;
|
||||||
onUpdate: () => void;
|
onUpdate?: () => void;
|
||||||
onRemove: () => void;
|
onRemove?: () => void;
|
||||||
onQrCodeClick: () => void;
|
onQrCodeClick?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { account, t, onUpdate, onRemove, onQrCodeClick } = props;
|
const { data: account, t, onUpdate, onRemove, onQrCodeClick } = props;
|
||||||
const { type, channel, name, qrCode, allowDeposit, allowPay, color, enabled, price } = account;
|
const { type, channel, name, qrCode, allowDeposit, allowPay, color, enabled, price,
|
||||||
const legalActions = account['#oakLegalActions'];
|
taxLossRatio, refundCompensateRatio, refundGapDays, allowWithdrawTransfer, withdrawTransferLossRatio
|
||||||
|
} = account;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Descriptions
|
<Descriptions
|
||||||
style={{ width: 340, height: 435 }}
|
style={{ width: 380 }}
|
||||||
title={t(`offlineAccount:v.type.${type}`)}
|
title={t(`offlineAccount:v.type.${type}`)}
|
||||||
extra={<>
|
extra={<>
|
||||||
{legalActions.includes('update') && <Button
|
{onUpdate && <Button
|
||||||
style={{ marginRight: 4 }}
|
style={{ marginRight: 4 }}
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => onUpdate()}
|
onClick={() => onUpdate()}
|
||||||
>
|
>
|
||||||
{t('common::action.update')}
|
{t('common::action.update')}
|
||||||
</Button>}
|
</Button>}
|
||||||
{legalActions.includes('remove') && <Button
|
{onRemove && <Button
|
||||||
danger
|
danger
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => onRemove()}
|
onClick={() => onRemove()}
|
||||||
|
|
@ -43,7 +45,7 @@ function OfflineAccount(props: {
|
||||||
column={1}
|
column={1}
|
||||||
bordered
|
bordered
|
||||||
size="small"
|
size="small"
|
||||||
labelStyle={{ width: 98 }}
|
labelStyle={{ width: 198 }}
|
||||||
>
|
>
|
||||||
<Descriptions.Item label={t('offlineAccount:attr.type')}>{t(`offlineAccount:v.type.${type}`)}</Descriptions.Item>
|
<Descriptions.Item label={t('offlineAccount:attr.type')}>{t(`offlineAccount:v.type.${type}`)}</Descriptions.Item>
|
||||||
{channel && <Descriptions.Item label={t(`offlineAccount::label.channel.${type}`)}>{channel}</Descriptions.Item>}
|
{channel && <Descriptions.Item label={t(`offlineAccount::label.channel.${type}`)}>{channel}</Descriptions.Item>}
|
||||||
|
|
@ -51,10 +53,15 @@ function OfflineAccount(props: {
|
||||||
{qrCode && <Descriptions.Item label={t(`offlineAccount::label.qrCode.${type}`)}>
|
{qrCode && <Descriptions.Item label={t(`offlineAccount::label.qrCode.${type}`)}>
|
||||||
{type === 'bank' ? qrCode : <span className={Styles.qrCode} onClick={onQrCodeClick}><QRCode value={qrCode} size={name ? 80 : 128} color={color} /></span>}
|
{type === 'bank' ? qrCode : <span className={Styles.qrCode} onClick={onQrCodeClick}><QRCode value={qrCode} size={name ? 80 : 128} color={color} /></span>}
|
||||||
</Descriptions.Item>}
|
</Descriptions.Item>}
|
||||||
<Descriptions.Item label={t('offlineAccount:attr.price')}>{price}</Descriptions.Item>
|
<Descriptions.Item label={t('offlineAccount:attr.price')}>{ToYuan(price!)}{t('common::pay.scale')}</Descriptions.Item>
|
||||||
<Descriptions.Item label={t('offlineAccount:attr.allowDeposit')}>{t(`common::${allowDeposit}`)}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label={t('offlineAccount:attr.allowPay')}>{t(`common::${allowPay}`)}</Descriptions.Item>
|
<Descriptions.Item label={t('offlineAccount:attr.allowPay')}>{t(`common::${allowPay}`)}</Descriptions.Item>
|
||||||
<Descriptions.Item label={t('offlineAccount:attr.enabled')}>{t(`common::${enabled}`)}</Descriptions.Item>
|
<Descriptions.Item label={t('offlineAccount:attr.enabled')}>{t(`common::${enabled}`)}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t('offlineAccount:attr.taxLossRatio')}>{taxLossRatio}%</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t('offlineAccount:attr.refundCompensateRatio')}>{refundCompensateRatio}%</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t('offlineAccount:attr.refundGapDays')}>{refundGapDays}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t('offlineAccount:attr.taxLossRatio')}>{taxLossRatio}%</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t('offlineAccount:attr.allowWithdrawTransfer')}>{t(`common::${allowWithdrawTransfer}`)}</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t('offlineAccount:attr.withdrawTransferLossRatio')}>{withdrawTransferLossRatio}%</Descriptions.Item>
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -129,9 +136,9 @@ export default function render(props: WebComponentProps<EntityDict, 'offlineAcco
|
||||||
accounts.filter(ele => ele.$$createAt$$ as number > 1).map(
|
accounts.filter(ele => ele.$$createAt$$ as number > 1).map(
|
||||||
(ele, idx) => <div className={Styles.item} key={idx}>
|
(ele, idx) => <div className={Styles.item} key={idx}>
|
||||||
<OfflineAccount
|
<OfflineAccount
|
||||||
account={ele}
|
data={ele}
|
||||||
t={t}
|
t={t}
|
||||||
onRemove={() => {
|
onRemove={ele['#oakLegalActions']?.includes('remove') ? () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: t('confirmDelete'),
|
title: t('confirmDelete'),
|
||||||
content: t('areYouSure'),
|
content: t('areYouSure'),
|
||||||
|
|
@ -149,8 +156,8 @@ export default function render(props: WebComponentProps<EntityDict, 'offlineAcco
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
})
|
})
|
||||||
}}
|
} : undefined}
|
||||||
onUpdate={() => setUpsertId(ele.id!)}
|
onUpdate={ele['#oakLegalActions']?.includes('update') ? () => setUpsertId(ele.id!) : undefined}
|
||||||
onQrCodeClick={() => setShowQrCodeId(ele.id!)}
|
onQrCodeClick={() => setShowQrCodeId(ele.id!)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ export default OakComponent({
|
||||||
return {
|
return {
|
||||||
operation: operation && operation[0].operation,
|
operation: operation && operation[0].operation,
|
||||||
system: data,
|
system: data,
|
||||||
|
canUpdate: !!data?.['#oakLegalActions']?.includes('update'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
actions: ['update'],
|
||||||
});
|
});
|
||||||
|
|
@ -30,7 +30,7 @@ export function registerPayChannelComponent<ED extends EntityDict & BaseEntityDi
|
||||||
|
|
||||||
function PayConfig(props: {
|
function PayConfig(props: {
|
||||||
payConfig: EntityDict['system']['OpSchema']['payConfig'];
|
payConfig: EntityDict['system']['OpSchema']['payConfig'];
|
||||||
update: (config: EntityDict['system']['OpSchema']['payConfig']) => void;
|
update?: (config: EntityDict['system']['OpSchema']['payConfig']) => void;
|
||||||
t: (key: string) => string;
|
t: (key: string) => string;
|
||||||
}) {
|
}) {
|
||||||
const { payConfig, update, t } = props;
|
const { payConfig, update, t } = props;
|
||||||
|
|
@ -38,7 +38,7 @@ function PayConfig(props: {
|
||||||
const depositLoss = payConfig?.depositLoss;
|
const depositLoss = payConfig?.depositLoss;
|
||||||
|
|
||||||
const updateDepositLoss = (data: Partial<NonNullable<EntityDict['system']['OpSchema']['payConfig']>['depositLoss']>) => {
|
const updateDepositLoss = (data: Partial<NonNullable<EntityDict['system']['OpSchema']['payConfig']>['depositLoss']>) => {
|
||||||
update({
|
update && update({
|
||||||
depositLoss: {
|
depositLoss: {
|
||||||
...depositLoss,
|
...depositLoss,
|
||||||
...data,
|
...data,
|
||||||
|
|
@ -49,7 +49,7 @@ function PayConfig(props: {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const updateWithdrawLoss = (data: Partial<NonNullable<EntityDict['system']['OpSchema']['payConfig']>['withdrawLoss']>) => {
|
const updateWithdrawLoss = (data: Partial<NonNullable<EntityDict['system']['OpSchema']['payConfig']>['withdrawLoss']>) => {
|
||||||
update({
|
update && update({
|
||||||
depositLoss: depositLoss || {},
|
depositLoss: depositLoss || {},
|
||||||
withdrawLoss: {
|
withdrawLoss: {
|
||||||
conservative: !!(withdrawLoss?.conservative),
|
conservative: !!(withdrawLoss?.conservative),
|
||||||
|
|
@ -84,6 +84,7 @@ function PayConfig(props: {
|
||||||
addonAfter={"%"}
|
addonAfter={"%"}
|
||||||
step={0.01}
|
step={0.01}
|
||||||
precision={2}
|
precision={2}
|
||||||
|
disabled={!update}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const ratio = value;
|
const ratio = value;
|
||||||
updateDepositLoss({
|
updateDepositLoss({
|
||||||
|
|
@ -99,6 +100,7 @@ function PayConfig(props: {
|
||||||
value={depositLoss?.highest}
|
value={depositLoss?.highest}
|
||||||
min={0}
|
min={0}
|
||||||
step={1}
|
step={1}
|
||||||
|
disabled={!update}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const highest = value;
|
const highest = value;
|
||||||
updateDepositLoss({
|
updateDepositLoss({
|
||||||
|
|
@ -115,6 +117,7 @@ function PayConfig(props: {
|
||||||
value={depositLoss?.lowest}
|
value={depositLoss?.lowest}
|
||||||
min={0}
|
min={0}
|
||||||
step={1}
|
step={1}
|
||||||
|
disabled={!update}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const lowest = value;
|
const lowest = value;
|
||||||
updateDepositLoss({
|
updateDepositLoss({
|
||||||
|
|
@ -144,6 +147,7 @@ function PayConfig(props: {
|
||||||
label={t('payConfig.label.conservative')}
|
label={t('payConfig.label.conservative')}
|
||||||
>
|
>
|
||||||
<Switch
|
<Switch
|
||||||
|
disabled={!update}
|
||||||
value={withdrawLoss?.conservative}
|
value={withdrawLoss?.conservative}
|
||||||
onChange={(conservative) => {
|
onChange={(conservative) => {
|
||||||
updateWithdrawLoss({ conservative });
|
updateWithdrawLoss({ conservative });
|
||||||
|
|
@ -154,7 +158,7 @@ function PayConfig(props: {
|
||||||
label={t('payConfig.label.ratio')}
|
label={t('payConfig.label.ratio')}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
disabled={!!withdrawLoss?.conservative}
|
disabled={!!withdrawLoss?.conservative || !update}
|
||||||
value={withdrawLoss?.ratio}
|
value={withdrawLoss?.ratio}
|
||||||
max={20}
|
max={20}
|
||||||
min={0.01}
|
min={0.01}
|
||||||
|
|
@ -173,7 +177,7 @@ function PayConfig(props: {
|
||||||
label={t('payConfig.label.highest')}
|
label={t('payConfig.label.highest')}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
disabled={!!withdrawLoss?.conservative}
|
disabled={!!withdrawLoss?.conservative || !update}
|
||||||
value={withdrawLoss?.highest}
|
value={withdrawLoss?.highest}
|
||||||
min={0}
|
min={0}
|
||||||
step={1}
|
step={1}
|
||||||
|
|
@ -190,7 +194,7 @@ function PayConfig(props: {
|
||||||
label={t('payConfig.label.lowest')}
|
label={t('payConfig.label.lowest')}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
disabled={!!withdrawLoss?.conservative}
|
disabled={!!withdrawLoss?.conservative || !update}
|
||||||
value={withdrawLoss?.lowest}
|
value={withdrawLoss?.lowest}
|
||||||
min={0}
|
min={0}
|
||||||
step={1}
|
step={1}
|
||||||
|
|
@ -207,7 +211,7 @@ function PayConfig(props: {
|
||||||
label={t('payConfig.label.trim')}
|
label={t('payConfig.label.trim')}
|
||||||
>
|
>
|
||||||
<Radio.Group
|
<Radio.Group
|
||||||
disabled={!!withdrawLoss?.conservative}
|
disabled={!!withdrawLoss?.conservative || !update}
|
||||||
options={[
|
options={[
|
||||||
{
|
{
|
||||||
label: t('payConfig.label.jiao'),
|
label: t('payConfig.label.jiao'),
|
||||||
|
|
@ -238,8 +242,9 @@ export default function render(props: WebComponentProps<EntityDict, 'system', fa
|
||||||
system: RowWithActions<EntityDict, 'system'>;
|
system: RowWithActions<EntityDict, 'system'>;
|
||||||
operation?: EntityDict['system']['Update'];
|
operation?: EntityDict['system']['Update'];
|
||||||
serverUrl?: string;
|
serverUrl?: string;
|
||||||
|
canUpdate?: boolean;
|
||||||
}>) {
|
}>) {
|
||||||
const { system, oakFullpath, operation, oakDirty, serverUrl, oakExecutable } = props.data;
|
const { system, oakFullpath, operation, oakDirty, serverUrl, oakExecutable, canUpdate } = props.data;
|
||||||
const { t, update, clean, execute } = props.methods;
|
const { t, update, clean, execute } = props.methods;
|
||||||
|
|
||||||
if (system && oakFullpath) {
|
if (system && oakFullpath) {
|
||||||
|
|
@ -262,7 +267,7 @@ export default function render(props: WebComponentProps<EntityDict, 'system', fa
|
||||||
>
|
>
|
||||||
<PayConfig
|
<PayConfig
|
||||||
payConfig={system.payConfig}
|
payConfig={system.payConfig}
|
||||||
update={(payConfig) => update({ payConfig })}
|
update={canUpdate ? (payConfig) => update({ payConfig }) : undefined}
|
||||||
t={t}
|
t={t}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
import assert from 'assert';
|
||||||
|
import { EntityDict } from "../../../oak-app-domain";
|
||||||
|
import { uniq } from "oak-domain/lib/utils/lodash";
|
||||||
|
|
||||||
|
export default OakComponent({
|
||||||
|
properties: {
|
||||||
|
entities: [] as string[],
|
||||||
|
systemId: '',
|
||||||
|
},
|
||||||
|
lifetimes: {
|
||||||
|
ready() {
|
||||||
|
this.refreshData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
refreshData() {
|
||||||
|
const { entities, systemId } = this.props;
|
||||||
|
const schema = this.features.cache.getSchema();
|
||||||
|
|
||||||
|
uniq(['wpAccount', 'offlineAccount'].concat(entities || [])).forEach(
|
||||||
|
(entity) => {
|
||||||
|
const projection: EntityDict['offlineAccount']['Selection']['data'] = {
|
||||||
|
id: 1,
|
||||||
|
$$createAt$$: 1,
|
||||||
|
$$updateAt$$: 1,
|
||||||
|
};
|
||||||
|
Object.keys(schema[entity as keyof EntityDict].attributes!).forEach(
|
||||||
|
ele => {
|
||||||
|
if (!ele.startsWith('$$')) {
|
||||||
|
projection[ele] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.features.cache.refresh(entity as 'offlineAccount', {
|
||||||
|
data: projection,
|
||||||
|
filter: {
|
||||||
|
systemId,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
formData({ features }) {
|
||||||
|
const { entities, systemId } = this.props;
|
||||||
|
assert(systemId);
|
||||||
|
const schema = features.cache.getSchema();
|
||||||
|
let total = 0;
|
||||||
|
const accounts = uniq(['wpAccount', 'offlineAccount'].concat(entities || [])).map(
|
||||||
|
(entity) => {
|
||||||
|
const projection: EntityDict['offlineAccount']['Selection']['data'] = {
|
||||||
|
id: 1,
|
||||||
|
$$createAt$$: 1,
|
||||||
|
$$updateAt$$: 1,
|
||||||
|
};
|
||||||
|
Object.keys(schema[entity as keyof EntityDict].attributes!).forEach(
|
||||||
|
ele => {
|
||||||
|
if (!ele.startsWith('$$')) {
|
||||||
|
projection[ele] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const data = this.features.cache.get(entity as 'offlineAccount', {
|
||||||
|
data: projection,
|
||||||
|
filter: {
|
||||||
|
systemId,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
data.forEach(
|
||||||
|
ele => total += ele.price || 0,
|
||||||
|
);
|
||||||
|
return data.map(
|
||||||
|
(ele) => {
|
||||||
|
return {
|
||||||
|
entity,
|
||||||
|
data: {
|
||||||
|
...ele,
|
||||||
|
color: entity === 'offlineAccount' && features.style.getColor('offlineAccount', 'type', ele.type!),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
).flat();
|
||||||
|
|
||||||
|
return {
|
||||||
|
total,
|
||||||
|
accounts,
|
||||||
|
systemId,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
features: ['cache'],
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"sysAccount": "系统账户统计",
|
||||||
|
"total": "总余额",
|
||||||
|
"count": "账户个数",
|
||||||
|
"qrCode": "二维码收款",
|
||||||
|
"noDetailRender": "没有注入相应的详情渲染组件"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
.total {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--oak-color-primary);
|
||||||
|
|
||||||
|
.symbol {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sysAccounts {
|
||||||
|
display: flex;
|
||||||
|
padding: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 12px;
|
||||||
|
|
||||||
|
.sysAccount {
|
||||||
|
width: 244px;
|
||||||
|
height: 284px;
|
||||||
|
border: solid 0.1px silver;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 14px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
.top {
|
||||||
|
height: 90px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: larger;
|
||||||
|
font-weight: bold;
|
||||||
|
font-family: 黑体;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
color: var(--oak-text-color-disabled);
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.middle {
|
||||||
|
flex: 1;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--oak-color-primary);
|
||||||
|
font-size: large;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,232 @@
|
||||||
|
import { EntityDict } from "../../../oak-app-domain";
|
||||||
|
import { RowWithActions, WebComponentProps } from "oak-frontend-base";
|
||||||
|
import React from 'react';
|
||||||
|
import { Descriptions, Tag, Form, Switch, Modal, Input, Select, Flex, Button } from 'antd';
|
||||||
|
import { AlipayOutlined, WechatOutlined } from '@ant-design/icons';
|
||||||
|
import Styles from './web.pc.module.less';
|
||||||
|
import { ThousandCont, ToYuan } from "oak-domain/lib/utils/money";
|
||||||
|
import { OfflineAccount as OADetail } from '../../offlineAccount/config/web.pc';
|
||||||
|
import { WpAccount as WADetail } from '../../wpAccount/config/web.pc';
|
||||||
|
|
||||||
|
function OfflineAccount(props: {
|
||||||
|
data: EntityDict['offlineAccount']['OpSchema'] & { color?: string };
|
||||||
|
t: (key: string) => string;
|
||||||
|
}) {
|
||||||
|
const { data, t } = props;
|
||||||
|
const { type, channel, color, name } = data;
|
||||||
|
switch (type) {
|
||||||
|
case 'bank': {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
vertical
|
||||||
|
gap="small"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<Tag>{t('offlineAccount:name')}</Tag>
|
||||||
|
<div className={Styles.title}>{t(`offlineAccount:v.type.${type}`)}</div>
|
||||||
|
<div className={Styles.subtitle}>{channel}</div>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'alipay': {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
vertical
|
||||||
|
gap="small"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<Tag>{t('offlineAccount:name')}</Tag>
|
||||||
|
<AlipayOutlined style={{ color, fontSize: 18 }} />
|
||||||
|
<div className={Styles.subtitle}>{name || t('qrCode')}</div>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'wechat': {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
vertical
|
||||||
|
gap="small"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<Tag>{t('offlineAccount:name')}</Tag>
|
||||||
|
<WechatOutlined style={{ color, fontSize: 18 }} />
|
||||||
|
<div className={Styles.subtitle}>{name || t('qrCode')}</div>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case 'shouqianba':
|
||||||
|
case 'others': {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
vertical
|
||||||
|
gap="small"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<Tag>{t('offlineAccount:name')}</Tag>
|
||||||
|
<div className={Styles.title}>{t(`offlineAccount:v.type.${type}`)}</div>
|
||||||
|
<div className={Styles.subtitle}>{name || t('qrCode')}</div>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function WpAccount(props: {
|
||||||
|
data: EntityDict['offlineAccount']['OpSchema'] & { color?: string };
|
||||||
|
t: (key: string) => string;
|
||||||
|
}) {
|
||||||
|
const { data, t } = props;
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
vertical
|
||||||
|
gap="middle"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<Tag>{t('wpAccount:name')}</Tag>
|
||||||
|
<WechatOutlined style={{ color: 'green', fontSize: 34 }} />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function GeneralAccount(props: {
|
||||||
|
entity: string;
|
||||||
|
t: (key: string) => string;
|
||||||
|
}) {
|
||||||
|
const { entity, t } = props;
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
style={{ height: '100%' }}
|
||||||
|
vertical
|
||||||
|
gap="small"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<Tag>{t(`${entity}:name`)}</Tag>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const RenderSysAccountCardTopDict: Record<string, (props: {
|
||||||
|
data: any,
|
||||||
|
t: (k: string) => string
|
||||||
|
}) => JSX.Element> = {
|
||||||
|
'offlineAccount': OfflineAccount,
|
||||||
|
'wpAccount': WpAccount,
|
||||||
|
}
|
||||||
|
|
||||||
|
const RenderSysAccountDetailDict: Record<string, (props: {
|
||||||
|
data: any,
|
||||||
|
t: (k: string) => string
|
||||||
|
systemId: string,
|
||||||
|
}) => JSX.Element> = {
|
||||||
|
'offlineAccount': OADetail,
|
||||||
|
'wpAccount': WADetail,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function render(props: WebComponentProps<EntityDict, 'offlineAccount', false, {
|
||||||
|
total?: number;
|
||||||
|
accounts?: Array<{
|
||||||
|
entity: string;
|
||||||
|
data: any;
|
||||||
|
price: number
|
||||||
|
}>;
|
||||||
|
systemId?: string;
|
||||||
|
}>) {
|
||||||
|
const { accounts, total, systemId } = props.data;
|
||||||
|
const { t, setMessage } = props.methods;
|
||||||
|
|
||||||
|
if (accounts && systemId) {
|
||||||
|
return (
|
||||||
|
<div className={Styles.container}>
|
||||||
|
<Descriptions
|
||||||
|
title={t('sysAccount')}
|
||||||
|
bordered
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
label: t('total'),
|
||||||
|
children: <div className={Styles.total}>
|
||||||
|
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
|
||||||
|
<span className={Styles.value}>{ThousandCont(ToYuan(total || 0), 2)}</span>
|
||||||
|
</div>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('count'),
|
||||||
|
children: accounts.length,
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
column={2}
|
||||||
|
/>
|
||||||
|
<div className={Styles.sysAccounts}>
|
||||||
|
{
|
||||||
|
accounts.map(
|
||||||
|
({ entity, data }) => {
|
||||||
|
const TopRender = RenderSysAccountCardTopDict[entity];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={Styles.sysAccount}>
|
||||||
|
<div className={Styles.top}>
|
||||||
|
{
|
||||||
|
TopRender ? <TopRender
|
||||||
|
data={data}
|
||||||
|
t={t}
|
||||||
|
/> : <GeneralAccount
|
||||||
|
entity={entity}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className={Styles.middle}>
|
||||||
|
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
|
||||||
|
<span className={Styles.value}>{ThousandCont(ToYuan(data.price || 0), 2)}</span>
|
||||||
|
</div>
|
||||||
|
<div className={Styles.bottom}>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
const DetailRender = RenderSysAccountDetailDict[entity];
|
||||||
|
if (DetailRender) {
|
||||||
|
Modal.info({
|
||||||
|
width: 560,
|
||||||
|
title: `${t(`${entity}:name`)}${t('common::action.detail')}`,
|
||||||
|
content: (
|
||||||
|
<DetailRender
|
||||||
|
data={data}
|
||||||
|
systemId={systemId}
|
||||||
|
t={t}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
onOk() { },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setMessage({
|
||||||
|
title: t('noDetailRender'),
|
||||||
|
type: 'error',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('common::action.detail')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -5,14 +5,30 @@ export default OakComponent({
|
||||||
id: 1,
|
id: 1,
|
||||||
price: 1,
|
price: 1,
|
||||||
mchId: 1,
|
mchId: 1,
|
||||||
refundGapDays: 1,
|
|
||||||
taxLossRatio: 1,
|
|
||||||
enabled: 1,
|
enabled: 1,
|
||||||
|
taxLossRatio: 1,
|
||||||
|
refundCompensateRatio: 1,
|
||||||
|
refundGapDays: 1,
|
||||||
|
allowWithdrawTransfer: 1,
|
||||||
|
withdrawTransferLossRatio: 1,
|
||||||
},
|
},
|
||||||
|
properties: {
|
||||||
|
systemId: '',
|
||||||
|
},
|
||||||
|
filters: [
|
||||||
|
{
|
||||||
|
filter() {
|
||||||
|
const { systemId } = this.props;
|
||||||
|
return {
|
||||||
|
systemId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
formData({ data, legalActions }) {
|
formData({ data, legalActions }) {
|
||||||
return {
|
return {
|
||||||
accounts: data,
|
accounts: data,
|
||||||
canCreate: legalActions?.includes('create'),
|
canCreate: legalActions?.includes('create') && !data?.find(ele => ele.enabled),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
actions: ['create', 'update', 'remove'],
|
actions: ['create', 'update', 'remove'],
|
||||||
|
|
|
||||||
|
|
@ -9,77 +9,88 @@ import Upsert from '../upsert';
|
||||||
import WpProductConfig from '../../wpProduct/config';
|
import WpProductConfig from '../../wpProduct/config';
|
||||||
import { OakAttrNotNullException, OakException } from 'oak-domain/lib/types';
|
import { OakAttrNotNullException, OakException } from 'oak-domain/lib/types';
|
||||||
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
||||||
|
import { ToYuan } from 'oak-domain/lib/utils/money';
|
||||||
|
|
||||||
function WpAccount(props: {
|
export function WpAccount(props: {
|
||||||
account: RowWithActions<EntityDict, 'wpAccount'>,
|
data: RowWithActions<EntityDict, 'wpAccount'>,
|
||||||
oakFullpath: string;
|
|
||||||
systemId: string;
|
systemId: string;
|
||||||
t: (k: string, param?: any) => string;
|
t: (k: string, param?: any) => string;
|
||||||
onUpdate: () => void;
|
onUpdate?: () => void;
|
||||||
onRemove: () => void;
|
onRemove?: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { account, t, onUpdate, onRemove, oakFullpath, systemId } = props;
|
const { data: account, t, onUpdate, onRemove, systemId } = props;
|
||||||
const { refundGapDays, mchId, enabled, price, taxLossRatio } = account;
|
const { refundGapDays, mchId, enabled, price, taxLossRatio,
|
||||||
const legalActions = account['#oakLegalActions'];
|
refundCompensateRatio, allowWithdrawTransfer, withdrawTransferLossRatio
|
||||||
|
} = account;
|
||||||
|
|
||||||
const [activeKey, setActiveKey] = useState("1");
|
const [activeKey, setActiveKey] = useState("1");
|
||||||
return (
|
const D = (
|
||||||
<Tabs
|
<Descriptions
|
||||||
activeKey={activeKey}
|
column={1}
|
||||||
onTabClick={(activeKey) => {
|
bordered
|
||||||
setActiveKey(activeKey)
|
title={t('wpAccount:name')}
|
||||||
}}
|
size="small"
|
||||||
tabBarExtraContent={
|
>
|
||||||
activeKey === "1" && <>
|
<Descriptions.Item label={t('wpAccount:attr.mchId')}>{mchId}</Descriptions.Item>
|
||||||
{legalActions.includes('update') && <Button
|
<Descriptions.Item label={t('wpAccount:attr.price')}>{ToYuan(price!)}{t('common::pay.scale')}</Descriptions.Item>
|
||||||
style={{ marginRight: 4 }}
|
<Descriptions.Item label={t('wpAccount:attr.taxLossRatio')}>{taxLossRatio}%</Descriptions.Item>
|
||||||
size="small"
|
<Descriptions.Item label={t('wpAccount:attr.refundCompensateRatio')}>{refundCompensateRatio}%</Descriptions.Item>
|
||||||
onClick={() => onUpdate()}
|
<Descriptions.Item label={t('wpAccount:attr.refundGapDays')}>{refundGapDays}</Descriptions.Item>
|
||||||
>
|
<Descriptions.Item label={t('wpAccount:attr.taxLossRatio')}>{taxLossRatio}%</Descriptions.Item>
|
||||||
{t('common::action.update')}
|
<Descriptions.Item label={t('wpAccount:attr.allowWithdrawTransfer')}>{t(`common::${allowWithdrawTransfer}`)}</Descriptions.Item>
|
||||||
</Button>}
|
<Descriptions.Item label={t('wpAccount:attr.withdrawTransferLossRatio')}>{withdrawTransferLossRatio}%</Descriptions.Item>
|
||||||
{legalActions.includes('remove') && <Button
|
<Descriptions.Item label={t('wpAccount:attr.enabled')}>{t(`common::${enabled}`)}</Descriptions.Item>
|
||||||
danger
|
</Descriptions>
|
||||||
size="small"
|
|
||||||
onClick={() => onRemove()}
|
|
||||||
>
|
|
||||||
{t('common::action.remove')}
|
|
||||||
</Button>}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
style={{ width: 380, height: 520 }}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
label: t('common::action.detail'),
|
|
||||||
children: (
|
|
||||||
<Descriptions
|
|
||||||
column={1}
|
|
||||||
bordered
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<Descriptions.Item label={t('wpAccount:attr.mchId')}>{mchId}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label={t('wpAccount:attr.price')}>{price}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label={t('wpAccount:attr.refundGapDays')}>{refundGapDays}</Descriptions.Item>
|
|
||||||
<Descriptions.Item label={t('wpAccount:attr.taxLossRatio')}>{taxLossRatio}%</Descriptions.Item>
|
|
||||||
<Descriptions.Item label={t('wpAccount:attr.enabled')}>{t(`common::${enabled}`)}</Descriptions.Item>
|
|
||||||
</Descriptions>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '2',
|
|
||||||
label: t('wpProduct:name'),
|
|
||||||
children: (
|
|
||||||
<WpProductConfig
|
|
||||||
oakPath={`$$wpProduct-${account.id!}`}
|
|
||||||
systemId={systemId}
|
|
||||||
wpAccountId={account.id!}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
if (onUpdate) {
|
||||||
|
return (
|
||||||
|
<Tabs
|
||||||
|
activeKey={activeKey}
|
||||||
|
onTabClick={(activeKey) => {
|
||||||
|
setActiveKey(activeKey)
|
||||||
|
}}
|
||||||
|
tabBarExtraContent={
|
||||||
|
activeKey === "1" && <>
|
||||||
|
{onUpdate && <Button
|
||||||
|
style={{ marginRight: 4 }}
|
||||||
|
size="small"
|
||||||
|
onClick={() => onUpdate()}
|
||||||
|
>
|
||||||
|
{t('common::action.update')}
|
||||||
|
</Button>}
|
||||||
|
{onRemove && <Button
|
||||||
|
danger
|
||||||
|
size="small"
|
||||||
|
onClick={() => onRemove()}
|
||||||
|
>
|
||||||
|
{t('common::action.remove')}
|
||||||
|
</Button>}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
style={{ width: 380, height: 520 }}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: t('common::action.detail'),
|
||||||
|
children: D,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
label: t('wpProduct:name'),
|
||||||
|
children: (
|
||||||
|
<WpProductConfig
|
||||||
|
oakPath={`$$wpProduct-${account.id!}`}
|
||||||
|
systemId={systemId}
|
||||||
|
wpAccountId={account.id!}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return D;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function render(props: WebComponentProps<EntityDict, 'wpAccount', true, {
|
export default function render(props: WebComponentProps<EntityDict, 'wpAccount', true, {
|
||||||
|
|
@ -143,11 +154,10 @@ export default function render(props: WebComponentProps<EntityDict, 'wpAccount',
|
||||||
accounts.filter(ele => ele.$$createAt$$ as number > 1).map(
|
accounts.filter(ele => ele.$$createAt$$ as number > 1).map(
|
||||||
(ele, idx) => <div className={Styles.item} key={idx}>
|
(ele, idx) => <div className={Styles.item} key={idx}>
|
||||||
<WpAccount
|
<WpAccount
|
||||||
oakFullpath={oakFullpath}
|
|
||||||
systemId={systemId}
|
systemId={systemId}
|
||||||
account={ele}
|
data={ele}
|
||||||
t={t}
|
t={t}
|
||||||
onRemove={() => {
|
onRemove={ele['#oakLegalActions']?.includes('remove') ? () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: t('confirmDelete'),
|
title: t('confirmDelete'),
|
||||||
content: t('areYouSure'),
|
content: t('areYouSure'),
|
||||||
|
|
@ -165,8 +175,8 @@ export default function render(props: WebComponentProps<EntityDict, 'wpAccount',
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
})
|
})
|
||||||
}}
|
} : undefined}
|
||||||
onUpdate={() => setUpsertId(ele.id!)}
|
onUpdate={ele['#oakLegalActions']?.includes('update') ? () => setUpsertId(ele.id!) : undefined}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ export default OakComponent({
|
||||||
price: 0,
|
price: 0,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
taxLossRatio: 0.6,
|
taxLossRatio: 0.6,
|
||||||
|
refundCompensateRatio: 100,
|
||||||
|
allowWithdrawTransfer: false,
|
||||||
});
|
});
|
||||||
const { systemId } = this.props;
|
const { systemId } = this.props;
|
||||||
const { data: [ wechatPay ]} = await this.features.cache.refresh('wechatPay', {
|
const { data: [ wechatPay ]} = await this.features.cache.refresh('wechatPay', {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
"refundNotifyUrl": "endpoint",
|
"refundNotifyUrl": "endpoint",
|
||||||
"apiV3Key": "需要登录商户后台获取",
|
"apiV3Key": "需要登录商户后台获取",
|
||||||
"refundGapDays": "超过这个天数后无法退款",
|
"refundGapDays": "超过这个天数后无法退款",
|
||||||
"allowWithdrawTransfer": "开启转账允许后,提现时用户即可选择从此商户号提现到微信零钱,帐户需要开启此项能力",
|
"allowWithdrawTransfer": "开启转账允许后,提现时用户即可选择从此商户号提现到微信零钱,微信商户必须要开启此项能力(当前尚未实现)",
|
||||||
"withdrawTransferLossRatio": "渠道转账(提现)时收取的手续费百分比,0.6代表千分之六"
|
"withdrawTransferLossRatio": "渠道转账(提现)时收取的手续费百分比,0.6代表千分之六"
|
||||||
},
|
},
|
||||||
"wechatPayIsShared": "以上配置是全局的,请谨慎修改"
|
"wechatPayIsShared": "以上配置是全局的,请谨慎修改"
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,19 @@ const i18ns: I18n[] = [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "c014581e9b3508d49c8dc75b2c7f5730",
|
||||||
|
namespace: "oak-pay-business-c-sysAccount-survey",
|
||||||
|
language: "zh-CN",
|
||||||
|
module: "oak-pay-business",
|
||||||
|
position: "src/components/sysAccount/survey",
|
||||||
|
data: {
|
||||||
|
"sysAccount": "系统账户统计",
|
||||||
|
"total": "总余额",
|
||||||
|
"count": "账户个数",
|
||||||
|
"qrCode": "二维码收款"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "79255be8c093dfef9765b3f367cab553",
|
id: "79255be8c093dfef9765b3f367cab553",
|
||||||
namespace: "oak-pay-business-c-wechatPay-upsert",
|
namespace: "oak-pay-business-c-wechatPay-upsert",
|
||||||
|
|
@ -527,7 +540,7 @@ const i18ns: I18n[] = [
|
||||||
"refundNotifyUrl": "endpoint",
|
"refundNotifyUrl": "endpoint",
|
||||||
"apiV3Key": "需要登录商户后台获取",
|
"apiV3Key": "需要登录商户后台获取",
|
||||||
"refundGapDays": "超过这个天数后无法退款",
|
"refundGapDays": "超过这个天数后无法退款",
|
||||||
"allowWithdrawTransfer": "开启转账允许后,提现时用户即可选择从此商户号提现到微信零钱,帐户需要开启此项能力",
|
"allowWithdrawTransfer": "开启转账允许后,提现时用户即可选择从此商户号提现到微信零钱,微信商户必须要开启此项能力(当前尚未实现)",
|
||||||
"withdrawTransferLossRatio": "渠道转账(提现)时收取的手续费百分比,0.6代表千分之六"
|
"withdrawTransferLossRatio": "渠道转账(提现)时收取的手续费百分比,0.6代表千分之六"
|
||||||
},
|
},
|
||||||
"wechatPayIsShared": "以上配置是全局的,请谨慎修改"
|
"wechatPayIsShared": "以上配置是全局的,请谨慎修改"
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,12 @@ import { CreateTriggerInTxn, RemoveTriggerInTxn, Trigger, UpdateTriggerInTxn } f
|
||||||
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
|
||||||
import { EntityDict } from '../oak-app-domain';
|
import { EntityDict } from '../oak-app-domain';
|
||||||
import { BRC } from '../types/RuntimeCxt';
|
import { BRC } from '../types/RuntimeCxt';
|
||||||
import { DATA_SUBSCRIBER_KEYS } from '../config/constants';
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { getPayClazzAccountEntities } from '../utils/payClazz';
|
|
||||||
|
|
||||||
// 这里一定要注意两者的先后顺序,如果有注入更多的payEntity的话
|
// 这里一定要注意两者的先后顺序,如果有注入更多的payEntity的话
|
||||||
const entities = getPayClazzAccountEntities<EntityDict>();
|
import { accountEntities } from '../checkers/abstractChecker';
|
||||||
|
|
||||||
const triggers: Trigger<EntityDict, keyof EntityDict, BRC>[] = [
|
const triggers: Trigger<EntityDict, keyof EntityDict, BRC>[] = [
|
||||||
...entities.filter(ele => !!ele).map(
|
...accountEntities.filter(ele => !!ele).map(
|
||||||
(entity) => [
|
(entity) => [
|
||||||
{
|
{
|
||||||
name: `当${entity}的帐户生成时,则生成对应的withDrawAccount`,
|
name: `当${entity}的帐户生成时,则生成对应的withDrawAccount`,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import Account from './Account';
|
||||||
import { WebConfig, WechatMpConfig, WechatPublicConfig } from 'oak-general-business/lib/entities/Application';
|
import { WebConfig, WechatMpConfig, WechatPublicConfig } from 'oak-general-business/lib/entities/Application';
|
||||||
import WechatPay from './WechatPay';
|
import WechatPay from './WechatPay';
|
||||||
import { StorageSchema } from 'oak-domain/lib/types/Storage';
|
import { StorageSchema } from 'oak-domain/lib/types/Storage';
|
||||||
|
import { registerAccountEntity } from '../../checkers/abstractChecker';
|
||||||
|
|
||||||
|
|
||||||
type PayClazzConstructor = (applicationId: string, entityId: string, context: BRC) => Promise<PayClazz>;
|
type PayClazzConstructor = (applicationId: string, entityId: string, context: BRC) => Promise<PayClazz>;
|
||||||
|
|
@ -141,13 +142,9 @@ export function registerPayClazzEntity<ED extends EntityDict & BaseEntityDict, T
|
||||||
|
|
||||||
assert(payAttr.entity.enumeration?.includes(entity as string));
|
assert(payAttr.entity.enumeration?.includes(entity as string));
|
||||||
assert(accountAttr.price && accountAttr.price.type === 'decimal');
|
assert(accountAttr.price && accountAttr.price.type === 'decimal');
|
||||||
}
|
assert(accountAttr.systemId && accountAttr.systemId.type === 'ref' && accountAttr.systemId.ref === 'system');
|
||||||
|
|
||||||
export function getPayClazzAccountEntities<ED extends EntityDict & BaseEntityDict>() {
|
registerAccountEntity(def.accountEntity);
|
||||||
MODULE_USED = true;
|
|
||||||
return Object.keys(PayClazzEntityDict).map(
|
|
||||||
ele => PayClazzEntityDict[ele].accountEntity as keyof ED
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue