feat(admin): v3.5.18 用户详情明文手机、任务关联版本与核销快链
HQ 后台:用户/核销记录展示完整手机号;任务列表与编辑可关联版本;账单核销单号与券号/用户可快链;门店账单日标明为出账自然日;技术支持操作按钮右对齐。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { Button, Checkbox, Drawer, Form, Input, Select, Table, Tag, Typography } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { REDEEM_CHANNEL_LABELS, type RedeemChannel } from '@dukang/shared-types';
|
||||
@@ -20,17 +20,28 @@ type Row = {
|
||||
channel?: RedeemChannel;
|
||||
createdAt: string;
|
||||
isTest?: boolean;
|
||||
user?: { userNo: string; phone: string | null; nickname?: string | null };
|
||||
user?: {
|
||||
id?: string;
|
||||
userNo: string;
|
||||
phone: string | null;
|
||||
nickname?: string | null;
|
||||
hqRemark?: string | null;
|
||||
};
|
||||
store?: { name: string; cityName: string };
|
||||
coupon?: { couponNo: string };
|
||||
coupon?: { id?: string; couponNo: string };
|
||||
};
|
||||
|
||||
function maskPhone(phone: string | null | undefined) {
|
||||
if (!phone || phone.length < 7) return phone ?? '—';
|
||||
return `${phone.slice(0, 3)}****${phone.slice(-4)}`;
|
||||
function formatNicknameWithRemark(user?: {
|
||||
nickname?: string | null;
|
||||
hqRemark?: string | null;
|
||||
} | null) {
|
||||
const name = user?.nickname?.trim() || '—';
|
||||
const remark = user?.hqRemark?.trim();
|
||||
return remark ? `${name}(${remark})` : name;
|
||||
}
|
||||
|
||||
export default function RedeemRecordsPage() {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const initialRedeemNo = searchParams.get('redeemNo')?.trim() || '';
|
||||
const [form] = Form.useForm();
|
||||
@@ -108,23 +119,60 @@ export default function RedeemRecordsPage() {
|
||||
);
|
||||
},
|
||||
},
|
||||
{ title: '用户编号', dataIndex: ['user', 'userNo'], width: 110 },
|
||||
{ title: '用户编号', dataIndex: ['user', 'userNo'], width: 110, render: (v: string | undefined, row) =>
|
||||
row.user?.id ? (
|
||||
<AdminPrimaryLink
|
||||
onClick={() => navigate('/users', { state: { openUserId: String(row.user!.id) } })}
|
||||
>
|
||||
{v || '—'}
|
||||
</AdminPrimaryLink>
|
||||
) : (
|
||||
v || '—'
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '用户昵称',
|
||||
dataIndex: ['user', 'nickname'],
|
||||
width: 100,
|
||||
render: (v: string | null | undefined) => v || '—',
|
||||
width: 160,
|
||||
render: (_: string | null | undefined, row) =>
|
||||
row.user?.id ? (
|
||||
<AdminPrimaryLink
|
||||
onClick={() => navigate('/users', { state: { openUserId: String(row.user!.id) } })}
|
||||
>
|
||||
{formatNicknameWithRemark(row.user)}
|
||||
</AdminPrimaryLink>
|
||||
) : (
|
||||
formatNicknameWithRemark(row.user)
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '用户手机',
|
||||
dataIndex: ['user', 'phone'],
|
||||
width: 120,
|
||||
render: (v: string | null | undefined) => maskPhone(v),
|
||||
render: (v: string | null | undefined) => v || '—',
|
||||
},
|
||||
{ title: '门店', dataIndex: ['store', 'name'] },
|
||||
{ title: '核销额', dataIndex: 'amount', width: 90, render: (v) => `¥${v}` },
|
||||
{ title: '结算额', dataIndex: 'settleAmount', width: 90, render: (v) => `¥${v}` },
|
||||
{ title: '券号', dataIndex: ['coupon', 'couponNo'], width: 160 },
|
||||
{
|
||||
title: '券号',
|
||||
dataIndex: ['coupon', 'couponNo'],
|
||||
width: 160,
|
||||
render: (v: string | undefined, row) =>
|
||||
v ? (
|
||||
<AdminPrimaryLink
|
||||
onClick={() =>
|
||||
navigate(`/benefit/coupons?couponNo=${encodeURIComponent(v)}`, {
|
||||
state: row.coupon?.id ? { openCouponId: String(row.coupon.id) } : undefined,
|
||||
})
|
||||
}
|
||||
>
|
||||
{v}
|
||||
</AdminPrimaryLink>
|
||||
) : (
|
||||
'—'
|
||||
),
|
||||
},
|
||||
{ title: '时间', dataIndex: 'createdAt', width: 160, render: fmtTime },
|
||||
{
|
||||
title: '操作',
|
||||
|
||||
Reference in New Issue
Block a user