245 lines
7.6 KiB
TypeScript
245 lines
7.6 KiB
TypeScript
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>
|
||
),
|
||
}),
|
||
]}
|
||
/>
|
||
);
|
||
}
|