Add employee serial QR query support
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import QRCode from 'qrcode';
|
||||
import {
|
||||
Card,
|
||||
Table,
|
||||
@@ -17,8 +18,10 @@ import {
|
||||
PlusOutlined,
|
||||
EditOutlined,
|
||||
DeleteOutlined,
|
||||
QrcodeOutlined,
|
||||
KeyOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { authApi, employeesApi } from '@/services/api';
|
||||
import type { User, UserRole, CreateUserRequest, UpdateUserRequest, EmployeeSerial } from '@/types';
|
||||
|
||||
@@ -42,21 +45,10 @@ const ROLE_OPTIONS = (Object.keys(ROLE_LABEL) as UserRole[]).map((value) => ({
|
||||
|
||||
const canLoginBackend = (role?: UserRole) => !!role && BACKEND_ROLES.includes(role);
|
||||
|
||||
function renderEmployeeSerial(serials?: EmployeeSerial[]) {
|
||||
const activeSerial = serials?.find((serial) => serial.isActive) || serials?.[0];
|
||||
if (!activeSerial) return '-';
|
||||
|
||||
return (
|
||||
<Space direction="vertical" size={0}>
|
||||
<span style={{ fontFamily: 'monospace' }}>{activeSerial.serialNumber}</span>
|
||||
<Tag color={activeSerial.isActive ? 'green' : 'red'}>
|
||||
{activeSerial.isActive ? '有效' : '已吊销'}
|
||||
</Tag>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
const getDisplaySerial = (serials?: EmployeeSerial[]) => serials?.find((serial) => serial.isActive) || serials?.[0];
|
||||
|
||||
function EmployeeSerialsPage() {
|
||||
const navigate = useNavigate();
|
||||
const currentUser = authApi.getCurrentUser();
|
||||
const isAdmin = currentUser?.role === 'admin';
|
||||
|
||||
@@ -81,6 +73,10 @@ function EmployeeSerialsPage() {
|
||||
const [resetLoading, setResetLoading] = useState(false);
|
||||
const [resetForm] = Form.useForm<{ newPassword: string }>();
|
||||
|
||||
const [qrCodeVisible, setQrCodeVisible] = useState(false);
|
||||
const [qrCodeDataUrl, setQrCodeDataUrl] = useState('');
|
||||
const [selectedSerial, setSelectedSerial] = useState('');
|
||||
|
||||
const loadEmployees = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
@@ -192,6 +188,23 @@ function EmployeeSerialsPage() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleViewQRCode = async (serialNumber: string) => {
|
||||
try {
|
||||
const queryUrl = `${window.location.origin}/query?serial=${serialNumber}`;
|
||||
const qrCode = await QRCode.toDataURL(queryUrl);
|
||||
setQrCodeDataUrl(qrCode);
|
||||
setSelectedSerial(serialNumber);
|
||||
setQrCodeVisible(true);
|
||||
} catch (err: any) {
|
||||
message.error(err?.message || '生成二维码失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleQuerySerial = (serialNumber: string) => {
|
||||
setQrCodeVisible(false);
|
||||
navigate(`/query?serial=${serialNumber}`);
|
||||
};
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{ title: '姓名', dataIndex: 'name', key: 'name', width: 120 },
|
||||
@@ -209,8 +222,30 @@ function EmployeeSerialsPage() {
|
||||
title: '员工码',
|
||||
dataIndex: 'employeeSerials',
|
||||
key: 'employeeSerials',
|
||||
width: 190,
|
||||
render: (serials?: EmployeeSerial[]) => renderEmployeeSerial(serials),
|
||||
width: 240,
|
||||
render: (serials?: EmployeeSerial[]) => {
|
||||
const serial = getDisplaySerial(serials);
|
||||
if (!serial) return '-';
|
||||
|
||||
return (
|
||||
<Space direction="vertical" size={0}>
|
||||
<Space size={8}>
|
||||
<span style={{ fontFamily: 'monospace' }}>{serial.serialNumber}</span>
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<QrcodeOutlined />}
|
||||
onClick={() => handleViewQRCode(serial.serialNumber)}
|
||||
>
|
||||
查看二维码
|
||||
</Button>
|
||||
</Space>
|
||||
<Tag color={serial.isActive ? 'green' : 'red'}>
|
||||
{serial.isActive ? '有效' : '已吊销'}
|
||||
</Tag>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
@@ -397,6 +432,31 @@ function EmployeeSerialsPage() {
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title="员工码二维码"
|
||||
open={qrCodeVisible}
|
||||
onCancel={() => setQrCodeVisible(false)}
|
||||
footer={null}
|
||||
width={400}
|
||||
>
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
{qrCodeDataUrl && (
|
||||
<>
|
||||
<img
|
||||
src={qrCodeDataUrl}
|
||||
alt="员工码二维码"
|
||||
style={{ width: 200, height: 200, cursor: 'pointer' }}
|
||||
onClick={() => handleQuerySerial(selectedSerial)}
|
||||
/>
|
||||
<p style={{ marginTop: 12, fontFamily: 'monospace', fontSize: 16, fontWeight: 'bold', color: '#165DFF' }}>
|
||||
{selectedSerial}
|
||||
</p>
|
||||
<p style={{ marginTop: 8, fontSize: 12, color: '#999' }}>点击二维码可打开查询页面</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title={resetPasswordEmployee ? `重置密码:${resetPasswordEmployee.name}` : '重置密码'}
|
||||
open={!!resetPasswordEmployee}
|
||||
|
||||
Reference in New Issue
Block a user