账单导出

This commit is contained in:
liu
2026-09-13 23:42:35 +08:00
parent 5784875939
commit 80cbd452e5
12 changed files with 112 additions and 228 deletions
+20 -62
View File
@@ -8,7 +8,6 @@ import {
Input,
message,
Modal,
Select,
Table,
Tag,
Typography,
@@ -25,9 +24,8 @@ import type {
import type { IBill, IBillDetail, IBillGoodsItem, IBillOrder } from '@/domain/iBill.ts';
import { BILL_STATUS_MAP } from '@/domain/iBill.ts';
import { STORE_ORDER_STATUS_MAP } from '@/domain/iStoreOrder.ts';
import { exportBills, getBillDetail, payBill } from '@/api/recon/bill.ts';
import { exportBill, getBillDetail, payBill } from '@/api/recon/bill.ts';
import { getStoreOptions } from '@/api/customer/store.ts';
import { getCategoryTree } from '@/api/product/category.ts';
import type IStore from '@/domain/iStore.ts';
import AuthButton from '@/components/AuthButton';
@@ -55,20 +53,11 @@ const BillPage: React.FC = () => {
const [paySaving, setPaySaving] = useState(false);
const [payForm] = Form.useForm<PayFormValues>();
// 合并导出(勾选账单跨账单按商品合并明细,可按一级分类过滤)
const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
const [exportOpen, setExportOpen] = useState(false);
const [exporting, setExporting] = useState(false);
const [categoryId, setCategoryId] = useState(0);
const [topCategories, setTopCategories] = useState<{ value: number; label: string }[]>([]);
// 单独导出(每行一张账单,账单内明细按商品合并)
const [exportingId, setExportingId] = useState<number | null>(null);
useEffect(() => {
getStoreOptions().then((res) => setStores(res.data.data ?? []));
getCategoryTree().then((res) =>
setTopCategories(
(res.data.data ?? []).map((c) => ({ value: c.id!, label: c.name ?? '' })),
),
);
}, []);
const openDetail = async (id: number) => {
@@ -107,17 +96,16 @@ const BillPage: React.FC = () => {
}
};
/** 提交合并导出:下载失败时 downloadBlob 内部已提示,保留勾选便于重试 */
const handleExport = async () => {
if (selectedRowKeys.length === 0) {
/** 单独导出:下载失败时 downloadBlob 内部已提示 */
const handleExport = async (record: IBill) => {
if (!record.id) {
return;
}
setExporting(true);
setExportingId(record.id);
try {
await exportBills(selectedRowKeys, categoryId);
setExportOpen(false);
await exportBill(record.id);
} finally {
setExporting(false);
setExportingId(null);
}
};
@@ -328,6 +316,16 @@ const BillPage: React.FC = () => {
icon={<UnorderedListOutlined />}
onClick={() => openDetail(record.id!)}
/>,
<AuthButton key="export" auth="recon.bill.export">
<Button
size="small"
color="orange"
variant="solid"
icon={<DownloadOutlined />}
loading={exportingId === record.id}
onClick={() => handleExport(record)}
/>
</AuthButton>,
record.status === 0 ? (
<AuthButton key="pay" auth="recon.bill.pay">
<Button size="small" variant="solid" color="green" onClick={() => openPay(record)}>
@@ -346,21 +344,7 @@ const BillPage: React.FC = () => {
operateRender,
formProps: false,
actionBarRender: (dom) => [dom.search, dom.keywordSearch],
rowSelection: {
selectedRowKeys,
onChange: (keys) => setSelectedRowKeys(keys.map(Number)),
preserveSelectedRowKeys: true,
},
toolBarRender: (dom) => [
<AuthButton key="export" auth="recon.bill.export">
<Button
icon={<DownloadOutlined />}
disabled={selectedRowKeys.length === 0}
onClick={() => setExportOpen(true)}
>
导出{selectedRowKeys.length > 0 ? `(${selectedRowKeys.length})` : ''}
</Button>
</AuthButton>,
dom.columnSetting,
dom.hideBorder,
dom.reload,
@@ -374,7 +358,7 @@ const BillPage: React.FC = () => {
<Title level={3}>门店账单</Title>
<Text type="secondary">
采购单完成后在「采购单」页生成,每个门店单独一张;账单总金额 = 商品金额 + 配送费 + 附加金额(周转筐/托盘)+ 售后金额(可正负);
勾选多张账单可合并导出为一个 Excel(明细跨账单按商品合并,可按一级分类过滤)。
每行可单独导出为一个 Excel(账单内明细按商品合并)。
</Text>
</div>
<XinTable<IBill> {...tableProps} />
@@ -484,32 +468,6 @@ const BillPage: React.FC = () => {
</Form.Item>
</Form>
</Modal>
{/* 合并导出:勾选账单跨账单按商品合并明细,可按一级分类过滤 */}
<Modal
title="导出账单"
open={exportOpen}
onCancel={() => setExportOpen(false)}
onOk={handleExport}
confirmLoading={exporting}
okText="导出"
destroyOnHidden
>
<div className="py-2 text-gray-500">
已选 <Text strong>{selectedRowKeys.length}</Text> 张账单,导出为一个
Excel:商品明细跨账单按商品合并,表尾汇总配送费、附加金额与总金额;
选择分类后仅导出该一级分类下的商品明细(配送费/附加金额仍全额汇总)。
</div>
<Form layout="vertical">
<Form.Item label="商品分类">
<Select
value={categoryId}
onChange={(value) => setCategoryId(value)}
options={[{ value: 0, label: '全部分类' }, ...topCategories]}
/>
</Form.Item>
</Form>
</Modal>
</>
);
};