小程序导出账单接口
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import createAxios from '@/utils/request';
|
||||
import { downloadBlob } from '@/api/common/download.ts';
|
||||
import type { IBillDetail } from '@/domain/iBill.ts';
|
||||
|
||||
/** 账单详情(账单信息 + 合并商品明细 + 关联订单) */
|
||||
@@ -17,3 +18,12 @@ export async function payBill(id: number, data: { paid_at: string; pay_remark?:
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/** 合并导出账单:勾选账单跨账单按商品合并明细,可按一级分类过滤 */
|
||||
export async function exportBills(ids: number[], categoryId: number) {
|
||||
return downloadBlob(
|
||||
'/recon/bill/export',
|
||||
{ ids: ids.join(','), category_id: categoryId },
|
||||
'门店账单.xlsx'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ import {
|
||||
Input,
|
||||
message,
|
||||
Modal,
|
||||
Select,
|
||||
Table,
|
||||
Tag,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import type { TableProps } from 'antd';
|
||||
import { UnorderedListOutlined } from '@ant-design/icons';
|
||||
import { DownloadOutlined, UnorderedListOutlined } from '@ant-design/icons';
|
||||
import dayjs from 'dayjs';
|
||||
import XinTable from '@/components/XinTable';
|
||||
import type {
|
||||
@@ -24,8 +25,9 @@ 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 { getBillDetail, payBill } from '@/api/recon/bill.ts';
|
||||
import { exportBills, 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';
|
||||
|
||||
@@ -53,8 +55,20 @@ 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 }[]>([]);
|
||||
|
||||
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) => {
|
||||
@@ -93,6 +107,20 @@ const BillPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
/** 提交合并导出:下载失败时 downloadBlob 内部已提示,保留勾选便于重试 */
|
||||
const handleExport = async () => {
|
||||
if (selectedRowKeys.length === 0) {
|
||||
return;
|
||||
}
|
||||
setExporting(true);
|
||||
try {
|
||||
await exportBills(selectedRowKeys, categoryId);
|
||||
setExportOpen(false);
|
||||
} finally {
|
||||
setExporting(false);
|
||||
}
|
||||
};
|
||||
|
||||
/** 合并商品明细列:品名/包规/单位/单价(加权平均)/数量/重量/金额 */
|
||||
const itemColumns: TableProps<IBillGoodsItem>['columns'] = [
|
||||
{ title: '品名', dataIndex: 'product_name', width: 160, align: 'center' },
|
||||
@@ -306,6 +334,26 @@ 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,
|
||||
dom.columnHeight,
|
||||
],
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -313,7 +361,8 @@ const BillPage: React.FC = () => {
|
||||
<div className="mb-5">
|
||||
<Title level={3}>门店账单</Title>
|
||||
<Text type="secondary">
|
||||
采购单完成后在「采购单」页生成,每个门店单独一张;账单总金额 = 商品金额 + 配送费 + 附加金额(周转筐/托盘)。
|
||||
采购单完成后在「采购单」页生成,每个门店单独一张;账单总金额 = 商品金额 + 配送费 + 附加金额(周转筐/托盘);
|
||||
勾选多张账单可合并导出为一个 Excel(明细跨账单按商品合并,可按一级分类过滤)。
|
||||
</Text>
|
||||
</div>
|
||||
<XinTable<IBill> {...tableProps} />
|
||||
@@ -415,6 +464,32 @@ 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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user