提现中的各种细节和逻辑

This commit is contained in:
Xu Chang 2024-05-30 13:21:28 +08:00
parent 5b5a7f1b70
commit 507c43d87f
35 changed files with 308 additions and 196 deletions

View File

@ -42,18 +42,19 @@ export default OakComponent({
priceYuan: ThousandCont(ToYuan(price), 2),
lossYuan: ThousandCont(ToYuan(loss), 2),
finalYuan: ThousandCont(ToYuan(price - loss), 2),
successAt: iState === 'refunded' && dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
updateAt: dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
reason,
};
});
const withdrawExactPrice = ThousandCont(ToYuan(data ? data.price - data.loss : 0), 2);
const withdrawExactPrice = data ? ['successful', 'partiallySuccessful', 'failed'].includes(data.iState) ? data.dealPrice - data.dealLoss : data.price - data.loss : 0;
return {
createAtStr: data && dayJs(data.$$createAt$$).format('YYYY-MM-DD HH:mm'),
withdrawExactPrice,
withdrawExactPrice: ThousandCont(ToYuan(withdrawExactPrice), 2),
refundData,
withdrawMethod: refundData && refundData.length ? 'refund' : undefined,
step: data?.iState === 'withdrawing' ? 1 : 2,
failed: data?.iState === 'failed',
// failed: data?.iState === 'failed',
iState: data?.iState,
};
}
});

View File

@ -15,5 +15,5 @@ export default function render(props: WebComponentProps<EntityDict, 'withdraw',
})[];
withdrawExactPrice: string;
step: 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}>): React.JSX.Element | null;

View File

@ -2,11 +2,11 @@ import React from 'react';
import WithdrawDetail from '../dry/Detail.mobile';
import Styles from './web.module.less';
export default function render(props) {
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, failed } = props.data;
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, iState } = props.data;
const { t } = props.methods;
if (refundData) {
return (<div className={Styles.container}>
<WithdrawDetail withdrawExactPrice={withdrawExactPrice} withdrawMethod={withdrawMethod} refundData={refundData} t={t} step={step} createAt={createAtStr} failed={failed}/>
<WithdrawDetail withdrawExactPrice={withdrawExactPrice} withdrawMethod={withdrawMethod} refundData={refundData} t={t} step={step} createAt={createAtStr} iState={iState}/>
</div>);
}
return null;

View File

@ -15,5 +15,5 @@ export default function render(props: WebComponentProps<EntityDict, 'withdraw',
})[];
withdrawExactPrice: string;
step: 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}>): React.JSX.Element | null;

View File

@ -2,11 +2,11 @@ import React from 'react';
import WithdrawDetail from '../dry/Detail.pc';
import Styles from './web.pc.module.less';
export default function render(props) {
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, failed } = props.data;
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, iState } = props.data;
const { t } = props.methods;
if (refundData) {
return (<div className={Styles.container}>
<WithdrawDetail withdrawExactPrice={withdrawExactPrice} withdrawMethod={withdrawMethod} refundData={refundData} t={t} step={step} createAt={createAtStr} failed={failed}/>
<WithdrawDetail withdrawExactPrice={withdrawExactPrice} withdrawMethod={withdrawMethod} refundData={refundData} t={t} step={step} createAt={createAtStr} iState={iState}/>
</div>);
}
return null;

View File

@ -11,11 +11,11 @@ export default function Detail(props: {
finalYuan: string;
iState?: EntityDict['refund']['OpSchema']['iState'];
iStateColor?: string;
successAt?: string;
updateAt?: string;
reason?: string;
})[];
withdrawExactPrice: string;
t: (k: string, p?: any) => string;
step: 0 | 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}): import("react").JSX.Element;

View File

@ -2,11 +2,11 @@ import { Tag, Steps } from 'antd-mobile';
import Styles from './Detail.module.less';
import classNames from 'classnames';
export default function Detail(props) {
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, failed } = props;
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, iState } = props;
return (<>
<div className={Styles.header}>
<div className={Styles.label}>
{t('header.label')}
{['successful', 'partiallySuccessful', 'failed'].includes(iState) ? t('header.label.end') : t('header.label.ing')}
</div>
<div className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
@ -18,7 +18,7 @@ export default function Detail(props) {
<Steps current={step}>
<Steps.Step title={<span className={step >= 0 ? classNames(Styles.label, Styles.active) : Styles.label}>{t('steps.1.title')}</span>} description={<span className={step >= 0 ? classNames(Styles.label, Styles.active) : Styles.label}>{createAt}</span>} key="1"/>
<Steps.Step title={<span className={step >= 1 ? classNames(Styles.label, Styles.active) : Styles.label}>{t('steps.2.title')}</span>} description={<span className={step >= 1 ? classNames(Styles.label, Styles.active) : Styles.label}>{t(`method.v.${withdrawMethod}`)}</span>} key="2"/>
<Steps.Step title={<span className={step >= 2 ? classNames(Styles.label, failed ? Styles.failed : Styles.success) : Styles.label}>{failed ? t('steps.3.failed') : t('steps.3.title')}</span>} key="3"/>
<Steps.Step title={<span className={step >= 2 ? classNames(Styles.label, iState === 'failed' ? Styles.failed : Styles.success) : Styles.label}>{iState === 'failed' ? t('steps.3.failed') : (iState === 'partiallySuccess' ? t('steps.3.partiallySuccess') : t('steps.3.success'))}</span>} key="3"/>
</Steps>
</div>
{refundData.map((data, idx) => (<div className={Styles.refundItem} key={idx}>
@ -37,35 +37,37 @@ export default function Detail(props) {
{data.priceYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.1')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.finalYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
{!!data.successAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.successAt')}</span>
<span className={Styles.value}>{data.successAt}</span>
</div>}
{iState !== 'failed' && <>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.1')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.finalYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
</>}
{!!data.reason && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.reason')}</span>
<span className={Styles.value}>{data.reason}</span>
<span className={classNames(Styles.value, Styles.reason)}>{data.reason}</span>
</div>}
{!!data.updateAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.updateAt')}</span>
<span className={Styles.value}>{data.updateAt}</span>
</div>}
</div>))}
</div>

View File

@ -61,7 +61,7 @@
margin-top: 4px;
display: flex;
flex-direction: row;
align-items: center;
// align-items: center;
justify-content: space-between;
.label {
@ -69,11 +69,16 @@
}
.value {
max-width: 180px;
color: var(--oak-text-color-primary);
.symbol {
margin-right: 4px;
}
}
.reason {
color: var(--oak-color-error);
}
}
}

View File

@ -11,11 +11,11 @@ export default function Detail(props: {
finalYuan: string;
iState?: EntityDict['refund']['OpSchema']['iState'];
iStateColor?: string;
successAt?: string;
updateAt?: string;
reason?: string;
})[];
withdrawExactPrice: string;
t: (k: string, p?: any) => string;
step: 0 | 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}): import("react").JSX.Element;

View File

@ -1,12 +1,13 @@
import { Steps, Tag } from 'antd';
import { CloseCircleOutlined, FileAddOutlined, FieldTimeOutlined, CheckCircleOutlined } from '@ant-design/icons';
import Styles from './Detail.pc.module.less';
import classNames from 'classnames';
export default function Detail(props) {
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, failed } = props;
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, iState } = props;
const H = (<>
<div className={Styles.header}>
<div className={Styles.label}>
{t('header.label')}
{['successful', 'partiallySuccessful', 'failed'].includes(iState) ? t('header.label.end') : t('header.label.ing')}
</div>
<div className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
@ -26,8 +27,16 @@ export default function Detail(props) {
description: t(`method.v.${withdrawMethod}`)
},
{
title: failed ? <span style={{ color: 'red' }}>{t('steps.3.failed')}</span> : <span style={{ color: 'green' }}>{t('steps.3.title')}</span>,
icon: failed ? <CloseCircleOutlined style={{ color: 'red' }}/> : <CheckCircleOutlined style={{ color: 'green' }}/>
title: step === 2
? (iState === 'failed'
? <span style={{ color: 'red' }}>{t('steps.3.failed')}</span>
: (iState === 'partiallySuccessful'
? <span style={{ color: 'green' }}>{t('steps.3.partiallySuccess')}</span>
: <span style={{ color: 'green' }}>{t('steps.3.success')}</span>))
: t('steps.3.success'),
icon: step === 2 ?
(iState === 'failed' ? <CloseCircleOutlined style={{ color: 'red' }}/> : <CheckCircleOutlined style={{ color: 'green' }}/>)
: <CheckCircleOutlined />
}
]}/>
</div>
@ -60,28 +69,30 @@ export default function Detail(props) {
{data.finalYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
{!!data.successAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.successAt')}</span>
<span className={Styles.value}>{data.successAt}</span>
</div>}
{data.iState !== 'failed' && <>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
</>}
{!!data.reason && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.reason')}</span>
<span className={Styles.value}>{data.reason}</span>
<span className={classNames(Styles.value, Styles.reason)}>{data.reason}</span>
</div>}
{!!data.updateAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.updateAt')}</span>
<span className={Styles.value}>{data.updateAt}</span>
</div>}
</div>))}
</div>

View File

@ -33,10 +33,6 @@
font-size: small;
}
.active {
// color: var(--oak-color-primary);
}
:global {
.ant-steps-item-content {
margin-top: 0px !important;
@ -51,7 +47,7 @@
}
.refundItem {
width: 188px;
width: 223px;
margin: 12px;
padding: 8px;
font-size: small;
@ -62,7 +58,7 @@
margin-top: 4px;
display: flex;
flex-direction: row;
align-items: center;
// align-items: center;
justify-content: space-between;
.label {
@ -70,11 +66,16 @@
}
.value {
max-width: 130px;
color: var(--oak-text-color-primary);
.symbol {
margin-right: 4px;
}
}
.reason {
color: var(--oak-color-error);
}
}
}

View File

@ -1,6 +1,9 @@
{
"header": {
"label": "预计到帐金额"
"label": {
"end": "到帐金额",
"ing": "预计到帐金额"
}
},
"steps": {
"1": {
@ -10,7 +13,8 @@
"title": "处理中"
},
"3": {
"title": "到帐成功",
"success": "到帐成功",
"partiallySuccess": "部分成功",
"failed": "提现失败"
}
},
@ -27,8 +31,8 @@
"1": "到帐金额",
"2": "手续费",
"3": "手续费率",
"4": "到帐通道",
"successAt": "到帐时间",
"4": "收款帐户",
"updateAt": "更新时间",
"reason": "异常原因"
}
}

View File

@ -48,6 +48,20 @@ const attrUpdateMatrix = {
reason: {
actions: ['failRefunding', 'makeAbnormal'],
}
},
withdraw: {
dealLoss: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
dealPrice: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
reason: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
meta: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
}
};
export default attrUpdateMatrix;

View File

@ -318,7 +318,10 @@ const i18ns = [
position: "src/components/withdraw/dry",
data: {
"header": {
"label": "预计到帐金额"
"label": {
"end": "到帐金额",
"ing": "预计到帐金额"
}
},
"steps": {
"1": {
@ -328,7 +331,8 @@ const i18ns = [
"title": "处理中"
},
"3": {
"title": "到帐成功",
"success": "到帐成功",
"partiallySuccess": "部分成功",
"failed": "提现失败"
}
},
@ -345,8 +349,8 @@ const i18ns = [
"1": "到帐金额",
"2": "手续费",
"3": "手续费率",
"4": "到帐通道",
"successAt": "到帐时间",
"4": "收款帐户",
"updateAt": "更新时间",
"reason": "异常原因"
}
}

View File

@ -20,9 +20,6 @@ async function changeWithdrawStateByRefunds(context, refunds) {
iState: 1,
loss: 1,
},
filter: {
iState: 'refunded',
},
},
},
filter: {
@ -51,7 +48,7 @@ async function changeWithdrawStateByRefunds(context, refunds) {
if (!allRefundsOver) {
continue;
}
const action = dealPrice === price ? 'succeed' : 'partiallySucceed';
const action = dealPrice === 0 ? 'fail' : (dealPrice === price ? 'succeed' : 'succeedPartially');
await context.operate('withdraw', {
id: await generateNewIdAsync(),
action,

View File

@ -97,6 +97,8 @@ const triggers = [
type: 'withdrawBack',
totalPlus: price,
availPlus: price,
entity: 'withdraw',
entityId: withdraw.id,
},
}, {});
}
@ -133,6 +135,8 @@ const triggers = [
type: 'withdrawBack',
totalPlus: price - dealPrice,
availPlus: price - dealPrice,
entity: 'withdraw',
entityId: withdraw.id,
},
}, {});
}

View File

@ -19,10 +19,12 @@ export default class WechatPay {
}
async getRefundState(refund) {
const r = Math.random();
/* if (r < 0.3) {
return ['refunding', {}];
} */
return ['refunded', {}];
if (r < 0.5) {
return ['refunded', undefined];
}
return ['failed', {
reason: '微信觉得你长得太丑了,就不想给你退款,让你去深圳找马化腾',
}];
}
decodePayNotification(params, body) {
throw new Error("Method not implemented.");

View File

@ -50,6 +50,20 @@ const attrUpdateMatrix = {
reason: {
actions: ['failRefunding', 'makeAbnormal'],
}
},
withdraw: {
dealLoss: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
dealPrice: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
reason: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
meta: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
}
};
exports.default = attrUpdateMatrix;

View File

@ -320,7 +320,10 @@ const i18ns = [
position: "src/components/withdraw/dry",
data: {
"header": {
"label": "预计到帐金额"
"label": {
"end": "到帐金额",
"ing": "预计到帐金额"
}
},
"steps": {
"1": {
@ -330,7 +333,8 @@ const i18ns = [
"title": "处理中"
},
"3": {
"title": "到帐成功",
"success": "到帐成功",
"partiallySuccess": "部分成功",
"failed": "提现失败"
}
},
@ -347,8 +351,8 @@ const i18ns = [
"1": "到帐金额",
"2": "手续费",
"3": "手续费率",
"4": "到帐通道",
"successAt": "到帐时间",
"4": "收款帐户",
"updateAt": "更新时间",
"reason": "异常原因"
}
}

View File

@ -23,9 +23,6 @@ async function changeWithdrawStateByRefunds(context, refunds) {
iState: 1,
loss: 1,
},
filter: {
iState: 'refunded',
},
},
},
filter: {
@ -54,7 +51,7 @@ async function changeWithdrawStateByRefunds(context, refunds) {
if (!allRefundsOver) {
continue;
}
const action = dealPrice === price ? 'succeed' : 'partiallySucceed';
const action = dealPrice === 0 ? 'fail' : (dealPrice === price ? 'succeed' : 'succeedPartially');
await context.operate('withdraw', {
id: await (0, uuid_1.generateNewIdAsync)(),
action,

View File

@ -100,6 +100,8 @@ const triggers = [
type: 'withdrawBack',
totalPlus: price,
availPlus: price,
entity: 'withdraw',
entityId: withdraw.id,
},
}, {});
}
@ -136,6 +138,8 @@ const triggers = [
type: 'withdrawBack',
totalPlus: price - dealPrice,
availPlus: price - dealPrice,
entity: 'withdraw',
entityId: withdraw.id,
},
}, {});
}

View File

@ -23,10 +23,12 @@ class WechatPay {
}
async getRefundState(refund) {
const r = Math.random();
/* if (r < 0.3) {
return ['refunding', {}];
} */
return ['refunded', {}];
if (r < 0.5) {
return ['refunded', undefined];
}
return ['failed', {
reason: '微信觉得你长得太丑了,就不想给你退款,让你去深圳找马化腾',
}];
}
decodePayNotification(params, body) {
throw new Error("Method not implemented.");

View File

@ -46,19 +46,21 @@ export default OakComponent({
priceYuan: ThousandCont(ToYuan(price!), 2),
lossYuan: ThousandCont(ToYuan(loss!), 2),
finalYuan: ThousandCont(ToYuan(price! - loss!), 2),
successAt: iState === 'refunded' && dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
updateAt: dayJs($$updateAt$$).format('YYYY-MM-DD HH:mm'),
reason,
};
}
);
const withdrawExactPrice = ThousandCont(ToYuan(data ? data.price! - data.loss! : 0), 2);
const withdrawExactPrice = data ? ['successful', 'partiallySuccessful', 'failed'].includes(data.iState!) ? data.dealPrice! -data.dealLoss! : data.price! - data.loss! : 0;
return {
createAtStr: data && dayJs(data.$$createAt$$).format('YYYY-MM-DD HH:mm'),
withdrawExactPrice,
withdrawExactPrice: ThousandCont(ToYuan(withdrawExactPrice), 2),
refundData,
withdrawMethod: refundData && refundData.length ? 'refund' : undefined,
step: data?.iState === 'withdrawing' ? 1 : 2,
failed: data?.iState === 'failed',
// failed: data?.iState === 'failed',
iState: data?.iState,
};
}
});

View File

@ -18,9 +18,9 @@ export default function render(props: WebComponentProps<EntityDict, 'withdraw',
})[];
withdrawExactPrice: string;
step: 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}>) {
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, failed } = props.data;
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, iState } = props.data;
const { t } = props.methods;
if (refundData) {
@ -33,7 +33,7 @@ export default function render(props: WebComponentProps<EntityDict, 'withdraw',
t={t}
step={step}
createAt={createAtStr}
failed={failed}
iState={iState}
/>
</div>
);

View File

@ -18,9 +18,9 @@ export default function render(props: WebComponentProps<EntityDict, 'withdraw',
})[];
withdrawExactPrice: string;
step: 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}>) {
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, failed } = props.data;
const { withdrawExactPrice, withdrawMethod, refundData, createAtStr, step, iState } = props.data;
const { t } = props.methods;
if (refundData) {
@ -33,7 +33,7 @@ export default function render(props: WebComponentProps<EntityDict, 'withdraw',
t={t}
step={step}
createAt={createAtStr}
failed={failed}
iState={iState}
/>
</div>
);

View File

@ -15,20 +15,20 @@ export default function Detail(props: {
finalYuan: string;
iState?: EntityDict['refund']['OpSchema']['iState'];
iStateColor?: string;
successAt?: string;
updateAt?: string;
reason?: string;
})[];
withdrawExactPrice: string;
t: (k: string, p?: any) => string;
step: 0 | 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}) {
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, failed } = props;
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, iState } = props;
return (
<>
<div className={Styles.header}>
<div className={Styles.label}>
{t('header.label')}
{['successful', 'partiallySuccessful', 'failed'].includes(iState!) ? t('header.label.end') : t('header.label.ing')}
</div>
<div className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
@ -48,7 +48,7 @@ export default function Detail(props: {
}>{createAt}</span>} key="1" />
<Steps.Step title={
<span className={
step >= 1 ? classNames(Styles.label, Styles.active) : Styles.label
step >= 1 ? classNames(Styles.label, Styles.active) : Styles.label
}>{t('steps.2.title')}</span>
} description={
<span className={
@ -57,8 +57,8 @@ export default function Detail(props: {
} key="2" />
<Steps.Step title={
<span className={
step >= 2 ? classNames(Styles.label, failed ? Styles.failed : Styles.success) : Styles.label
}>{failed ? t('steps.3.failed') :t('steps.3.title')}</span>
step >= 2 ? classNames(Styles.label, iState === 'failed' ? Styles.failed : Styles.success) : Styles.label
}>{iState === 'failed' ? t('steps.3.failed') : (iState === 'partiallySuccessful' ? t('steps.3.partiallySuccess') : t('steps.3.success'))}</span>
} key="3" />
</Steps>
</div>
@ -81,35 +81,37 @@ export default function Detail(props: {
{data.priceYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.1')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.finalYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
{!!data.successAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.successAt')}</span>
<span className={Styles.value}>{data.successAt}</span>
</div>}
{iState !== 'failed' && <>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.1')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.finalYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
</>}
{!!data.reason && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.reason')}</span>
<span className={Styles.value}>{data.reason}</span>
<span className={classNames(Styles.value, Styles.reason)}>{data.reason}</span>
</div>}
{!!data.updateAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.updateAt')}</span>
<span className={Styles.value}>{data.updateAt}</span>
</div>}
</div>
)

View File

@ -61,7 +61,7 @@
margin-top: 4px;
display: flex;
flex-direction: row;
align-items: center;
// align-items: center;
justify-content: space-between;
.label {
@ -69,11 +69,16 @@
}
.value {
max-width: 180px;
color: var(--oak-text-color-primary);
.symbol {
margin-right: 4px;
}
}
.reason {
color: var(--oak-color-error);
}
}
}

View File

@ -33,10 +33,6 @@
font-size: small;
}
.active {
// color: var(--oak-color-primary);
}
:global {
.ant-steps-item-content {
margin-top: 0px !important;
@ -51,7 +47,7 @@
}
.refundItem {
width: 188px;
width: 223px;
margin: 12px;
padding: 8px;
font-size: small;
@ -62,7 +58,7 @@
margin-top: 4px;
display: flex;
flex-direction: row;
align-items: center;
// align-items: center;
justify-content: space-between;
.label {
@ -70,11 +66,16 @@
}
.value {
max-width: 130px;
color: var(--oak-text-color-primary);
.symbol {
margin-right: 4px;
}
}
.reason {
color: var(--oak-color-error);
}
}
}

View File

@ -15,20 +15,20 @@ export default function Detail(props: {
finalYuan: string;
iState?: EntityDict['refund']['OpSchema']['iState'];
iStateColor?: string;
successAt?: string;
updateAt?: string;
reason?: string;
})[];
withdrawExactPrice: string;
t: (k: string, p?: any) => string;
step: 0 | 1 | 2;
failed?: boolean;
iState?: EntityDict['withdraw']['OpSchema']['iState'];
}) {
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, failed } = props;
const { withdrawExactPrice, withdrawMethod, refundData, t, step, createAt, iState } = props;
const H = (
<>
<div className={Styles.header}>
<div className={Styles.label}>
{t('header.label')}
{['successful', 'partiallySuccessful', 'failed'].includes(iState!) ? t('header.label.end') : t('header.label.ing')}
</div>
<div className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
@ -51,8 +51,17 @@ export default function Detail(props: {
description: t(`method.v.${withdrawMethod}`)
},
{
title: failed ? <span style={{ color: 'red' }}>{t('steps.3.failed')}</span> : <span style={{ color: 'green' }}>{t('steps.3.title')}</span>,
icon: failed ? <CloseCircleOutlined style={{ color: 'red' }} /> : <CheckCircleOutlined style={{ color: 'green' }} />
title: step === 2
? (iState === 'failed'
? <span style={{ color: 'red' }}>{t('steps.3.failed')}</span>
: (iState === 'partiallySuccessful'
? <span style={{ color: 'green' }}>{t('steps.3.partiallySuccess')}</span>
: <span style={{ color: 'green' }}>{t('steps.3.success')}</span>)
)
: t('steps.3.success'),
icon: step === 2 ?
(iState === 'failed' ? <CloseCircleOutlined style={{ color: 'red' }} /> : <CheckCircleOutlined style={{ color: 'green' }} />)
: <CheckCircleOutlined />
}
]}
/>
@ -91,28 +100,30 @@ export default function Detail(props: {
{data.finalYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
{!!data.successAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.successAt')}</span>
<span className={Styles.value}>{data.successAt}</span>
</div>}
{data.iState !== 'failed' && <>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.2')}</span>
<span className={Styles.value}>
<span className={Styles.symbol}>{t('common::pay.symbol')}</span>
{data.lossYuan}
</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.3')}</span>
<span className={Styles.value}>{data.lossExp}</span>
</div>
<div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.4')}</span>
<span className={Styles.value}>{data.channel}</span>
</div>
</>}
{!!data.reason && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.reason')}</span>
<span className={Styles.value}>{data.reason}</span>
<span className={classNames(Styles.value, Styles.reason)}>{data.reason}</span>
</div>}
{!!data.updateAt && <div className={Styles.item}>
<span className={Styles.label}>{t('refund.label.updateAt')}</span>
<span className={Styles.value}>{data.updateAt}</span>
</div>}
</div>
)

View File

@ -1,7 +1,10 @@
{
"header": {
"label": "预计到帐金额"
"label": {
"end": "到帐金额",
"ing": "预计到帐金额"
}
},
"steps": {
"1": {
@ -11,7 +14,8 @@
"title": "处理中"
},
"3": {
"title": "到帐成功",
"success": "到帐成功",
"partiallySuccess": "部分成功",
"failed": "提现失败"
}
},
@ -28,8 +32,8 @@
"1": "到帐金额",
"2": "手续费",
"3": "手续费率",
"4": "到帐通道",
"successAt": "到帐时间",
"4": "收款帐户",
"updateAt": "更新时间",
"reason": "异常原因"
}
}

View File

@ -52,6 +52,20 @@ const attrUpdateMatrix: AttrUpdateMatrix<EntityDict> = {
reason: {
actions: ['failRefunding', 'makeAbnormal'],
}
},
withdraw: {
dealLoss: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
dealPrice: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
reason: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
meta: {
actions: ['succeed', 'fail', 'succeedPartially'],
},
}
};

View File

@ -320,7 +320,10 @@ const i18ns: I18n[] = [
position: "src/components/withdraw/dry",
data: {
"header": {
"label": "预计到帐金额"
"label": {
"end": "到帐金额",
"ing": "预计到帐金额"
}
},
"steps": {
"1": {
@ -330,7 +333,8 @@ const i18ns: I18n[] = [
"title": "处理中"
},
"3": {
"title": "到帐成功",
"success": "到帐成功",
"partiallySuccess": "部分成功",
"failed": "提现失败"
}
},
@ -347,8 +351,8 @@ const i18ns: I18n[] = [
"1": "到帐金额",
"2": "手续费",
"3": "手续费率",
"4": "到帐通道",
"successAt": "到帐时间",
"4": "收款帐户",
"updateAt": "更新时间",
"reason": "异常原因"
}
}

View File

@ -24,9 +24,6 @@ async function changeWithdrawStateByRefunds(context: BRC, refunds: Partial<Entit
iState: 1,
loss: 1,
},
filter: {
iState: 'refunded',
},
},
},
filter: {
@ -57,7 +54,7 @@ async function changeWithdrawStateByRefunds(context: BRC, refunds: Partial<Entit
if (!allRefundsOver) {
continue;
}
const action = dealPrice === price ? 'succeed' : 'partiallySucceed';
const action = dealPrice === 0 ? 'fail' :(dealPrice === price ? 'succeed' : 'succeedPartially');
await context.operate('withdraw', {
id: await generateNewIdAsync(),

View File

@ -110,6 +110,8 @@ const triggers: Trigger<EntityDict, 'withdraw', BRC>[] = [
type: 'withdrawBack',
totalPlus: price!,
availPlus: price!,
entity: 'withdraw',
entityId: withdraw.id,
},
}, {});
}
@ -148,6 +150,8 @@ const triggers: Trigger<EntityDict, 'withdraw', BRC>[] = [
type: 'withdrawBack',
totalPlus: price! - dealPrice!,
availPlus: price! - dealPrice!,
entity: 'withdraw',
entityId: withdraw.id,
},
}, {});
}

View File

@ -29,11 +29,13 @@ export default class WechatPay implements PayClazz {
}
async getRefundState(refund: Refund): Promise<[string | null | undefined, PayUpdateData | undefined]> {
const r = Math.random();
/* if (r < 0.3) {
return ['refunding', {}];
} */
if (r < 0.5) {
return ['refunded', undefined];
}
return ['refunded', {}];
return ['failed', {
reason: '微信觉得你长得太丑了,就不想给你退款,让你去深圳找马化腾',
}];
}
decodePayNotification(params: Record<string, any>, body: any): Promise<{ payId: string; iState: string | null | undefined; extra?: PayUpdateData | undefined; }> {
throw new Error("Method not implemented.");