oak-pay-business/src/components/offlineAccount/config/web.pc.tsx

207 lines
9.5 KiB
TypeScript

import React, { useState } from 'react';
import { Button, Modal, Alert, Descriptions, QRCode } from 'antd';
import { PlusCircleOutlined } from '@ant-design/icons';
import { EntityDict } from "../../../oak-app-domain";
import { RowWithActions, WebComponentProps } from "oak-frontend-base";
import { Detail } from '../../../components/AbstractComponents';
import Styles from './web.pc.module.less';
import Upsert from '../upsert';
import { OakAttrNotNullException, OakException } from 'oak-domain/lib/types';
import { generateNewIdAsync } from 'oak-domain/lib/utils/uuid';
import { ToYuan } from 'oak-domain/lib/utils/money';
export function OfflineAccount(props: {
data: RowWithActions<EntityDict, 'offlineAccount'> & { color: string };
t: (k: string, param?: any) => string;
onUpdate?: () => void;
onRemove?: () => void;
onQrCodeClick?: () => void;
}) {
const { data: account, t, onUpdate, onRemove, onQrCodeClick } = props;
const { type, channel, name, qrCode, allowDeposit, allowPay, color, enabled, price,
taxLossRatio, refundCompensateRatio, refundGapDays, allowWithdrawTransfer, withdrawTransferLossRatio
} = account;
return (
<Descriptions
style={{ width: 380 }}
title={t(`offlineAccount:v.type.${type}`)}
extra={<>
{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>}
</>}
column={1}
bordered
size="small"
labelStyle={{ width: 198 }}
>
<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>}
{name && <Descriptions.Item label={t(`offlineAccount::label.name.${type}`)}>{name}</Descriptions.Item>}
{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>}
</Descriptions.Item>}
<Descriptions.Item label={t('offlineAccount:attr.price')}>{ToYuan(price!)}{t('common::pay.scale')}</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.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>
);
}
export default function render(props: WebComponentProps<EntityDict, 'offlineAccount', true, {
accounts?: (RowWithActions<EntityDict, 'offlineAccount'> & { color: string })[];
systemId: string;
canCreate?: boolean;
}>) {
const { accounts, oakFullpath, oakExecutable, systemId, canCreate } = props.data;
const { t, addItem, execute, clean } = props.methods;
const [upsertId, setUpsertId] = useState('');
const getNotNullMessage = (attr: keyof EntityDict['offlineAccount']['OpSchema']) => {
if (['channel', 'name', 'qrCode'].includes(attr)) {
const upsertRow = accounts?.find(ele => ele.id === upsertId)!;
return t('notnull', { value: t(`offlineAccount::label.${attr}.${upsertRow!.type}`) });
}
return t('notnull', { value: t(`offlineAccount:attr.${attr}`) });
};
const errMsg = oakExecutable instanceof OakException && (
oakExecutable instanceof OakAttrNotNullException ? getNotNullMessage(oakExecutable.getAttributes()[0] as keyof EntityDict['offlineAccount']['OpSchema']) : t(oakExecutable.message)
);
const U = (
<Modal
destroyOnClose
width={920}
title={`${t('offlineAccount:name')}${t('common::action.add')}`}
open={!!upsertId}
onCancel={() => {
clean();
setUpsertId('');
}}
closeIcon={null}
onOk={async () => {
await execute();
setUpsertId('');
}}
okButtonProps={{
disabled: oakExecutable !== true,
}}
okText={t('common::confirm')}
cancelText={(t('common::action.cancel'))}
>
<div style={{ padding: 10 }}>
{
errMsg && <Alert
type="error"
message={errMsg}
style={{ marginBottom: 20 }}
/>
}
<Upsert
oakPath={`${oakFullpath}.${upsertId}`}
systemId={systemId}
/>
</div>
</Modal>
);
const [showQrCodeId, setShowQrCodeId] = useState('');
const showQrCodeRow = showQrCodeId ? accounts!.find(ele => ele.id === showQrCodeId) : undefined;
if (accounts && accounts.length > 0) {
return (
<div className={Styles.container}>
<Alert type='info' message={t('tips')} />
{U}
<div className={Styles.list}>
{
accounts.filter(ele => ele.$$createAt$$ as number > 1).map(
(ele, idx) => <div className={Styles.item} key={idx}>
<OfflineAccount
data={ele}
t={t}
onRemove={ele['#oakLegalActions']?.includes('remove') ? () => {
Modal.confirm({
title: t('confirmDelete'),
content: t('areYouSure'),
onOk: async () => execute(undefined, undefined, undefined, [
{
entity: 'offlineAccount',
operation: {
id: await generateNewIdAsync(),
action: 'remove',
data: {},
filter: {
id: ele.id!,
},
}
}
]),
})
} : undefined}
onUpdate={ele['#oakLegalActions']?.includes('update') ? () => setUpsertId(ele.id!) : undefined}
onQrCodeClick={() => setShowQrCodeId(ele.id!)}
/>
</div>
)
}
</div>
<div className={Styles.btnBar}>
{canCreate && <Button
type="primary"
onClick={() => {
const id = addItem({ systemId });
setUpsertId(id);
}}
>
{t('common::action.add')}
</Button>}
</div>
{ showQrCodeRow && <Modal
open={!!showQrCodeId}
closeIcon={null}
footer={null}
onCancel={() => setShowQrCodeId('')}
>
<QRCode value={showQrCodeRow!.qrCode!} size={480} color={showQrCodeRow!.color!}/>
</Modal>}
</div>
);
}
return (
<div className={Styles.container2}>
<Alert type='info' message={t('tips')} />
{U}
<div className={Styles.body}>
{ canCreate ? <PlusCircleOutlined
className={Styles.add}
shape="circle"
style={{ fontSize: 50 }}
onClick={() => {
const id = addItem({ systemId });
setUpsertId(id);
}}
/> : t('noData') }
</div>
</div>
)
}