178 lines
5.9 KiB
JavaScript
178 lines
5.9 KiB
JavaScript
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;
|