fix(web): Phase 3 前端 UX/i18n 修复 — 名称解析/确认对话框/日历切换/删除替换
- ConsultationList: 批量解析患者/医生名称替代截断 UUID - PointsOrderList: 使用 product_name + 批量解析患者/核销人名称 - AppointmentList: 破坏性状态变更添加 Modal.confirm + 取消原因收集 - CalendarView: 添加 onPanelChange 回调支持月份切换 - DoctorSchedule: 日历视图切换月份自动刷新数据 - PointsRuleList: 移除无效删除按钮,Switch 添加启用/停用文字 - PointsProductList: 删除按钮替换为上架/下架 Switch - PatientSelect: 性别显示中文化 (male→男, female→女) - VitalSignsChart: API 失败时显示 Alert 错误提示 - PointsOrder 类型: 添加 product_name 字段
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
pointsApi,
|
||||
type PointsOrder,
|
||||
} from '../../api/health/points';
|
||||
import { patientApi } from '../../api/health/patients';
|
||||
|
||||
/** 订单状态映射 */
|
||||
const STATUS_MAP: Record<string, { text: string; color: string }> = {
|
||||
@@ -54,6 +55,9 @@ export default function PointsOrderList() {
|
||||
const [verifyForm] = Form.useForm();
|
||||
const [verifying, setVerifying] = useState(false);
|
||||
|
||||
// 名称缓存
|
||||
const [nameCache, setNameCache] = useState<Record<string, string>>({});
|
||||
|
||||
// ---- 数据获取 ----
|
||||
const fetchData = useCallback(async (p = page, ps = pageSize) => {
|
||||
setLoading(true);
|
||||
@@ -65,12 +69,30 @@ export default function PointsOrderList() {
|
||||
});
|
||||
setData(result.data);
|
||||
setTotal(result.total);
|
||||
|
||||
// 批量解析患者名称
|
||||
const patientIds = [...new Set(result.data.map((o) => o.patient_id))];
|
||||
const missingIds = patientIds.filter((id) => !nameCache[id]);
|
||||
if (missingIds.length > 0) {
|
||||
const newNames: Record<string, string> = {};
|
||||
await Promise.all(
|
||||
missingIds.map(async (id) => {
|
||||
try {
|
||||
const detail = await patientApi.get(id);
|
||||
newNames[id] = detail.name;
|
||||
} catch {
|
||||
newNames[id] = id.slice(0, 8);
|
||||
}
|
||||
}),
|
||||
);
|
||||
setNameCache((prev) => ({ ...prev, ...newNames }));
|
||||
}
|
||||
} catch {
|
||||
message.error('加载订单列表失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [page, pageSize, statusFilter]);
|
||||
}, [page, pageSize, statusFilter, nameCache]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
@@ -109,22 +131,19 @@ export default function PointsOrderList() {
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '患者ID',
|
||||
title: '患者',
|
||||
dataIndex: 'patient_id',
|
||||
key: 'patient_id',
|
||||
width: 140,
|
||||
render: (val: string) => (
|
||||
<span style={{ fontFamily: 'monospace', fontSize: 12 }}>{truncateId(val)}</span>
|
||||
),
|
||||
width: 100,
|
||||
render: (id: string) => nameCache[id] || id.slice(0, 8),
|
||||
},
|
||||
{
|
||||
title: '商品ID',
|
||||
dataIndex: 'product_id',
|
||||
key: 'product_id',
|
||||
title: '商品',
|
||||
dataIndex: 'product_name',
|
||||
key: 'product_name',
|
||||
width: 140,
|
||||
render: (val: string) => (
|
||||
<span style={{ fontFamily: 'monospace', fontSize: 12 }}>{truncateId(val)}</span>
|
||||
),
|
||||
render: (name: string | null, record: PointsOrder) =>
|
||||
name || truncateId(record.product_id),
|
||||
},
|
||||
{
|
||||
title: '积分',
|
||||
@@ -161,8 +180,8 @@ export default function PointsOrderList() {
|
||||
title: '核销人',
|
||||
dataIndex: 'verified_by',
|
||||
key: 'verified_by',
|
||||
width: 140,
|
||||
render: (val: string | null) => val ? <Tag color="blue">{truncateId(val)}</Tag> : '-',
|
||||
width: 100,
|
||||
render: (val: string | null) => val ? <Tag color="blue">{nameCache[val] || val.slice(0, 8)}</Tag> : '-',
|
||||
},
|
||||
{
|
||||
title: '过期时间',
|
||||
|
||||
Reference in New Issue
Block a user