feat(weibo): 区分充值资金来源并完善协作单记录

This commit is contained in:
yml
2026-11-13 21:07:50 +08:00
parent f0abca3d58
commit 76b344eb83
11 changed files with 740 additions and 10 deletions
+23
View File
@@ -79,6 +79,24 @@ export interface WeiboCollabAccountOption {
ck_check_status: string;
}
export interface WeiboRechargeRecord {
id: number;
order_id: string;
pay_id: string;
amount_yuan: number;
single_reward: number;
status: string;
status_label: string;
sub_status: string;
is_paid: boolean;
paid_at: string | null;
status_checked_at: string | null;
created_by: number | null;
created_by_name: string;
created_at: string | null;
updated_at: string | null;
}
export interface WeiboCollabOrder {
id: number;
order_no: string;
@@ -103,6 +121,10 @@ export interface WeiboCollabOrder {
remark: string;
status: WeiboCollabStatus;
status_label: string;
funding_source: string;
funding_source_label: string;
funding_source_detail: string;
funding_recharge_record_id: number | null;
next_status: WeiboCollabStatus | null;
missing_fields: string[];
weidou_balance: number | null;
@@ -147,6 +169,7 @@ export interface WeiboCollabOrder {
} | null;
last_metric_at: string | null;
last_metric_message: string;
recharge_records: WeiboRechargeRecord[];
}
export interface WeiboCollabOrderList {
+175 -5
View File
@@ -71,7 +71,7 @@ const { TextArea } = Input;
const STATUS_META: Record<WeiboCollabStatus, { label: string; color: string }> = {
incomplete: { label: '待补资料', color: 'default' },
to_recharge: { label: '待充值', color: 'blue' },
recharged: { label: '已充值', color: 'cyan' },
recharged: { label: '余额已核账', color: 'cyan' },
scripted: { label: '已上脚本', color: 'purple' },
done: { label: '兑换成功', color: 'success' },
weidou_error: { label: '微豆异常', color: 'orange' },
@@ -241,6 +241,13 @@ function balanceMeta(reason: string) {
return { label: '未核账', color: 'default' };
}
function fundingSourceColor(source: string) {
if (source === 'web_recharge') return 'success';
if (source === 'legacy_web_recharge') return 'warning';
if (source === 'unknown') return 'default';
return 'blue';
}
interface OrderFormValues {
order_no: string;
shop?: string;
@@ -307,6 +314,9 @@ export default function WeiboCollabPage() {
const [statusRollback, setStatusRollback] = useState(false);
const [statusIds, setStatusIds] = useState<number[]>([]);
const [statusSaving, setStatusSaving] = useState(false);
const [noteTarget, setNoteTarget] = useState<WeiboCollabOrder | null>(null);
const [noteValue, setNoteValue] = useState('');
const [noteSaving, setNoteSaving] = useState(false);
const [shopOpen, setShopOpen] = useState(false);
const [goodsOpen, setGoodsOpen] = useState(false);
@@ -534,6 +544,33 @@ export default function WeiboCollabPage() {
setEditOpen(true);
};
const openNote = (order: WeiboCollabOrder) => {
setNoteTarget(order);
setNoteValue(order.remark || '');
};
const saveNote = async () => {
if (!noteTarget || !canEdit) return;
setNoteSaving(true);
try {
const saved = await weiboCollabApi.updateOrder(noteTarget.id, {
remark: noteValue.trim(),
expected_version: noteTarget.version,
});
setOrders((current) => current.map((row) => (
row.id === saved.id ? saved : row
)));
setDetail((current) => (current?.id === saved.id ? saved : current));
setNoteTarget(null);
setNoteValue('');
message.success(noteValue.trim() ? '备注已保存' : '备注已清空');
} catch (error) {
message.error(getErrorMessage(error));
} finally {
setNoteSaving(false);
}
};
const handleGoodsChange = (value: string) => {
const selected = goodsOptions.find((item) => item.value === value);
if (!selected) return;
@@ -980,11 +1017,40 @@ export default function WeiboCollabPage() {
{
title: '状态',
dataIndex: 'status',
width: 130,
width: 190,
render: (value: WeiboCollabStatus, row) => (
<Space size={4} wrap>
<Tag color={STATUS_META[value]?.color}>{row.status_label || value}</Tag>
{row.exchange_verdict === 'unknown' && <Tag color="warning">待确认</Tag>}
<Space orientation="vertical" size={2} style={{ width: '100%' }}>
<Space size={4} wrap>
<Tag color={STATUS_META[value]?.color}>{row.status_label || value}</Tag>
{row.exchange_verdict === 'unknown' && <Tag color="warning">待确认</Tag>}
{row.funding_source_label && (
<Tag color={fundingSourceColor(row.funding_source)}>
{row.funding_source_label}
</Tag>
)}
</Space>
<div
role={canEdit && !row.is_archived ? 'button' : undefined}
tabIndex={canEdit && !row.is_archived ? 0 : undefined}
title={row.remark || (canEdit && !row.is_archived ? '点击添加备注' : undefined)}
onClick={() => {
if (canEdit && !row.is_archived) openNote(row);
}}
onKeyDown={(event) => {
if (canEdit && !row.is_archived && (event.key === 'Enter' || event.key === ' ')) {
event.preventDefault();
openNote(row);
}
}}
style={{
cursor: canEdit && !row.is_archived ? 'text' : 'default',
minHeight: 22,
wordBreak: 'break-word',
lineHeight: 1.35,
}}
>
{row.remark || <Text type="secondary">+ 备注</Text>}
</div>
</Space>
),
},
@@ -1569,6 +1635,29 @@ export default function WeiboCollabPage() {
</Form>
</Modal>
<Modal
title="订单备注"
open={noteTarget !== null}
confirmLoading={noteSaving}
okText="保存备注"
cancelText="取消"
onOk={() => void saveNote()}
onCancel={() => {
setNoteTarget(null);
setNoteValue('');
}}
destroyOnHidden
>
<TextArea
rows={5}
maxLength={512}
showCount
value={noteValue}
onChange={(event) => setNoteValue(event.target.value)}
placeholder="填写订单备注,保存后会记录到审计日志"
/>
</Modal>
<Modal
title={`修改状态${statusIds.length > 1 ? `(${statusIds.length} 单)` : ''}`}
open={statusOpen}
@@ -1751,6 +1840,23 @@ export default function WeiboCollabPage() {
label: '最近核账',
children: formatTime(detail.weidou_checked_at),
},
{
key: 'funding_source',
label: '余额来源',
children: detail.funding_source_label ? (
<Tag color={fundingSourceColor(detail.funding_source)}>
{detail.funding_source_label}
</Tag>
) : (
'未识别'
),
},
{
key: 'funding_detail',
label: '来源依据',
span: 2,
children: detail.funding_source_detail || '暂无来源依据',
},
{
key: 'scripted',
label: '上脚本时间',
@@ -1809,6 +1915,70 @@ export default function WeiboCollabPage() {
))}
</Space>
)}
<Title level={5}>Web 充值记录</Title>
<Table
rowKey="id"
size="small"
pagination={false}
locale={{ emptyText: '该账号暂无系统 Web 充值下单记录' }}
dataSource={detail.recharge_records}
rowClassName={(row) => (
row.id === detail.funding_recharge_record_id ? 'ant-table-row-selected' : ''
)}
columns={[
{
title: '创建时间',
dataIndex: 'created_at',
width: 170,
render: formatTime,
},
{
title: '充值单号',
dataIndex: 'order_id',
render: (value: string) => (
<Text code copyable={{ text: value }}>
{value}
</Text>
),
},
{
title: '金额',
dataIndex: 'amount_yuan',
width: 90,
align: 'right',
render: (value: number) => `${value} 元`,
},
{
title: '赠送微豆',
dataIndex: 'single_reward',
width: 110,
align: 'right',
render: (value: number) => value.toLocaleString(),
},
{
title: '支付状态',
dataIndex: 'status',
width: 110,
render: (value: string, row) => (
<Tag color={value === 'paid' ? 'success' : value === 'failed' ? 'error' : 'default'}>
{row.status_label || value}
</Tag>
),
},
{
title: '支付时间',
dataIndex: 'paid_at',
width: 170,
render: formatTime,
},
{
title: '操作人',
dataIndex: 'created_by_name',
width: 110,
render: (value: string) => value || '-',
},
]}
/>
<Space wrap>
{canEdit && !detail.is_archived && (
<>