245 lines
7.6 KiB
TypeScript
Raw Normal View History

2026-02-24 17:48:14 +08:00
import { MyButtons, MyColumns, MyProTableProps } from '@/common';
import { Selects } from '@/components/Select';
import { Apis } from '@/gen/Apis';
import { ProTable } from '@ant-design/pro-components';
import { message, Progress, Space } from 'antd';
import { saveAs } from 'file-saver';
import JSZip from 'jszip';
import { useState } from 'react';
import Create from './modals/Create';
import Update from './modals/Update';
interface DataType {
key?: React.Key;
id?: React.Key;
}
export default function Index({ title = '点位配置' }) {
const [count, setCount] = useState(0);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [downloadProgress, setDownloadProgress] = useState(0);
const [downloading, setDownloading] = useState(false);
const [getSelectedRow, setSelectedRow] = useState<any>([]);
const rowSelection: any = {
selectedRowKeys,
onChange: (selectedRowKeys: React.Key[], selectedRows: DataType[]) => {
console.log(selectedRows, 'selectedRows[0]');
if (selectedRowKeys.length > 10) {
message.warning('最多批量下载10个');
return;
}
setSelectedRowKeys(selectedRowKeys);
setSelectedRow(selectedRows);
},
getCheckboxProps: (record: any) => ({
disabled: !record.is_enabled,
}),
onSelectAll: (selected: boolean, selectedRows: DataType[]) => {
if (selected && selectedRows.length > 10) {
message.warning('全选数量超过10个');
return false;
}
},
defaultSelectedRowKeys: !count
? []
: getSelectedRow?.map((item: any) => item.id),
};
// 模拟获取二维码接口
const getQRCode = async (id?: string) => {
let res = await Apis.Patrol.PatrolLocations.PatrolLocationQrCode({
id: Number(id),
});
return res?.data?.qr_code;
};
// 生成带海报的二维码
const generatePosterQR = async (base64: string, res: any) => {
return new Promise((resolve) => {
const canvas = document.createElement('canvas');
const ctx: any = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 800;
// 海报样式
ctx.fillStyle = '#1890ff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = 'bold 36px Arial';
ctx.textAlign = 'center';
ctx.fillText(`${res?.name}`, canvas.width / 2, 130);
const qrImage = new Image();
qrImage.onload = () => {
const qrSize = 300;
const qrX = (canvas.width - qrSize) / 2;
const qrY = 210;
ctx.drawImage(qrImage, qrX, qrY, qrSize, qrSize);
ctx.font = '20px Arial';
ctx.fillText('扫描二维码完成签到', canvas.width / 2, 570);
ctx.font = '16px Arial';
ctx.fillText(res?.code, canvas.width / 2, 605);
resolve(canvas.toDataURL('image/png'));
};
qrImage.src = base64;
});
};
const download = async (type: number) => {
if (!getSelectedRow?.length) {
message.error('请选择巡逻位置!');
return;
}
setDownloading(true);
setDownloadProgress(0);
try {
const zip = new JSZip();
const total = getSelectedRow.length;
for (let i = 0; i < total; i++) {
let res = getSelectedRow?.[i];
if (res?.id) {
await new Promise((resolve: any) => {
setTimeout(resolve, 1000);
});
const qrCode = await getQRCode(res?.id);
if (type === 1) {
const base64Data = qrCode.split(',')[1];
zip.file(`${res?.name}_${res?.code}.png`, base64Data, {
base64: true,
});
}
if (type === 2) {
// 带海报的二维码
const posterData: any = await generatePosterQR(qrCode, res);
const fileData = posterData.split(',')[1];
zip.file(`${res?.name}_${res?.code}.png`, fileData, {
base64: true,
});
}
setCount(i + 1);
const progress = Math.round(((i + 1) / total) * 100);
setDownloadProgress(progress);
// 添加延迟
}
}
const content = await zip.generateAsync({ type: 'blob' });
saveAs(content, `扫码签到二维码.zip`);
setTimeout(() => {
setCount(0);
}, 1000);
} catch (error) {
console.error('下载失败:', error);
message.error('下载失败,请重试');
} finally {
setDownloading(false);
setDownloadProgress(0);
}
};
return (
<ProTable
{...MyProTableProps.props}
loading={{
spinning: downloading,
tip: `正在生成二维码... ${downloadProgress}%`,
indicator: (
<Progress type="circle" percent={downloadProgress} size={20} />
),
}}
request={async (params, sort) =>
MyProTableProps.request(params, sort, Apis.Patrol.PatrolLocations.List)
}
rowSelection={{ type: 'checkbox', ...rowSelection }}
toolBarRender={(action) => [
<MyButtons.Default
key="download_qrcode"
size="middle"
title={`下载纯二维码${
getSelectedRow?.length ? `${count}/${getSelectedRow?.length}` : ''
}`}
onClick={() => download(1)}
/>,
<MyButtons.Default
key="download_qrcode"
size="middle"
title={`下载海报二维码${
getSelectedRow?.length ? `${count}/${getSelectedRow?.length}` : ''
}`}
onClick={() => download(2)}
/>,
<Create key="Create" reload={action?.reload} title={title} />,
]}
columns={[
MyColumns.ID({
search: false,
}),
Selects?.AssetProjects({
title: '选择项目',
key: 'asset_projects_id',
hidden: true,
}),
{
title: '关联项目',
dataIndex: ['asset_project', 'name'],
search: {
transform: (value) => {
return { project_name: value };
},
},
},
{
title: '点位名称',
dataIndex: 'name',
},
{
title: '位置编码',
dataIndex: 'code',
},
MyColumns.Boolean({
dataIndex: 'is_enabled',
title: '启用/禁用',
search: false,
}),
MyColumns.CreatedAt(),
MyColumns.Option({
render: (_, item: any, index, action) => (
<Space key={index}>
<Update item={item} reload={action?.reload} title={title} />
<MyButtons.Default
title={item.is_enabled === 1 ? '禁用' : '启用'}
type={item.is_enabled === 1 ? 'default' : 'primary'}
danger={item.is_enabled === 1}
isConfirm={true}
description={
item.is_enabled === 1
? `确定要禁用点位吗?`
: `确定要启用点位吗?`
}
onConfirm={() =>
Apis.Patrol.PatrolLocations.Update({
id: item.id ?? 0,
is_enabled: item.is_enabled === 1 ? 0 : 1,
name: item.name,
code: item.code,
asset_projects_id: item.asset_projects_id,
}).then(() => action?.reload())
}
/>
<MyButtons.Delete
onConfirm={() =>
Apis.Patrol.PatrolLocations.Delete({ id: item.id }).then(() =>
action?.reload(),
)
}
/>
</Space>
),
}),
]}
/>
);
}