178 lines
5.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useCallback, useEffect, useState } from 'react';
import { Button, Drawer, Empty, List, Popconfirm, Spin, Tag, Tooltip, message } from 'antd';
import { DeleteOutlined, HistoryOutlined, RollbackOutlined } from '@ant-design/icons';
import { deletePricingHistory, fetchPricingHistoryList } from '../../api/pricingCalculator';
const PAGE_SIZE = 10;
const getIsAdmin = () => {
try {
const token = localStorage.getItem('token');
if (!token) return false;
const [, payload] = token.split('.');
if (!payload) return false;
const normalized = payload.replace(/-/g, '+').replace(/_/g, '/');
const padded = normalized.padEnd(normalized.length + ((4 - normalized.length % 4) % 4), '=');
return JSON.parse(window.atob(padded))?.role === 'admin';
} catch {
return false;
}
};
const formatTime = (value) => {
const date = value ? new Date(value) : null;
if (!date || Number.isNaN(date.getTime())) return '-';
const pad = (n) => String(n).padStart(2, '0');
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
};
/**
* 测算历史抽屉:服务端已按当前登录用户过滤,这里看到的全部是自己的记录。
* onRestore(record) 由父组件拉取详情并还原测算状态。
*/
const HistoryDrawer = ({
open,
onClose,
onRestore,
refreshKey,
calculatorType = 'company',
title = '测算历史',
identityLabel = 'SPU',
}) => {
const [loading, setLoading] = useState(false);
const [list, setList] = useState([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [deletingId, setDeletingId] = useState(null);
const [isAdmin] = useState(getIsAdmin);
const load = useCallback(async (nextPage = 1) => {
setLoading(true);
try {
const data = await fetchPricingHistoryList({
page: nextPage,
pageSize: PAGE_SIZE,
calculatorType,
});
setList(data?.list || []);
setTotal(data?.total || 0);
setPage(data?.page || nextPage);
} catch (error) {
message.error(error.message || '查询测算历史失败');
} finally {
setLoading(false);
}
}, [calculatorType]);
useEffect(() => {
if (open) {
load(1);
}
}, [open, refreshKey, load]);
const handleDelete = async (record) => {
setDeletingId(record.id);
try {
await deletePricingHistory(record.id);
message.success('已删除该测算记录');
// 删除后若当前页已空,回退一页
const nextPage = list.length === 1 && page > 1 ? page - 1 : page;
load(nextPage);
} catch (error) {
message.error(error.message || '删除失败');
} finally {
setDeletingId(null);
}
};
return (
<Drawer
title={(
<span className="pricing-calc-history__title">
<HistoryOutlined />
{title}
<span className="pricing-calc-history__subtitle">
{isAdmin ? '管理员视图 · 显示全部记录' : '仅显示我的测算记录'}
</span>
</span>
)}
width={460}
open={open}
onClose={onClose}
className="pricing-calc-history"
>
<Spin spinning={loading}>
{list.length === 0 && !loading ? (
<Empty description={`暂无${title},完成一次测算后点击「保存测算记录」`} />
) : (
<List
dataSource={list}
pagination={{
current: page,
pageSize: PAGE_SIZE,
total,
size: 'small',
onChange: (nextPage) => load(nextPage),
showTotal: (count) => `共 ${count} 条`,
}}
renderItem={(record) => (
<List.Item
className="pricing-calc-history__item"
actions={[
<Button
key="restore"
size="small"
type="link"
icon={<RollbackOutlined />}
onClick={() => onRestore(record)}
>
还原
</Button>,
<Popconfirm
key="delete"
title="删除该测算记录?"
description="删除后无法恢复。"
okText="删除"
cancelText="取消"
onConfirm={() => handleDelete(record)}
>
<Button
size="small"
type="text"
danger
loading={deletingId === record.id}
icon={<DeleteOutlined />}
aria-label="删除记录"
/>
</Popconfirm>,
]}
>
<List.Item.Meta
title={(
<span className="pricing-calc-history__item-title">
<Tooltip title={`${identityLabel}:${record.spuCode}`}>
<span className="pricing-calc-history__spu">{record.spuCode}</span>
</Tooltip>
{record.brand ? <Tag>{record.brand}</Tag> : null}
<span className="pricing-calc-history__count">{record.rowCount} 行</span>
</span>
)}
description={(
<span className="pricing-calc-history__meta">
<span>{formatTime(record.createdAt)}</span>
{isAdmin && record.userName ? <span>{record.userName}</span> : null}
{record.note ? <span className="pricing-calc-history__note">{record.note}</span> : null}
</span>
)}
/>
</List.Item>
)}
/>
)}
</Spin>
</Drawer>
);
};
export default HistoryDrawer;