| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904 |
- import React, { useState, useEffect } from 'react';
- import { Button, Table, Space, Modal, Form, Input, Select, message, List, Avatar, Progress, Tag, Timeline, DatePicker, Switch, Dropdown, Menu } from 'antd';
- import type { MenuProps } from 'antd';
- import { CloseOutlined } from '@ant-design/icons';
- import dayjs from 'dayjs';
- import { WorkOrderAPI } from './api/work_orders.ts';
- import { DeviceInstanceAPI } from './api/device_instance.ts';
- import { Uploader } from './components_uploader.tsx';
- import { WorkOrderPriority, WorkOrderStatus } from '../../client/share/monitorTypes.ts';
- import type { WorkOrder, WorkOrderSettings, DeadlineInfo } from '../../client/share/monitorTypes.ts';
- const { Column } = Table;
- const { Option } = Select;
- const { TextArea } = Input;
- export function WorkOrdersPage() {
- const [workOrders, setWorkOrders] = useState<WorkOrder[]>([]);
- const [settings, setSettings] = useState<WorkOrderSettings>();
- const [loading, setLoading] = useState(false);
- const [modalVisible, setModalVisible] = useState(false);
- const [currentOrder, setCurrentOrder] = useState<Partial<WorkOrder>>();
- const [categories, setCategories] = useState<string[]>([]);
- const [devices, setDevices] = useState<any[]>([]);
- const [attachments, setAttachments] = useState<any[]>([]);
- const [comments, setComments] = useState<any[]>([]);
- const [commentContent, setCommentContent] = useState('');
- const [form] = Form.useForm();
- const [historyVisible, setHistoryVisible] = useState(false);
- const [statusHistory, setStatusHistory] = useState<any[]>([]);
- const [deadlineInfo, setDeadlineInfo] = useState<DeadlineInfo>();
- const [autoDispatchVisible, setAutoDispatchVisible] = useState(false);
- const [autoDispatchForm] = Form.useForm();
- const [detailModalVisible, setDetailModalVisible] = useState(false);
- const [currentDetail, setCurrentDetail] = useState('');
- useEffect(() => {
- // 开发环境下生成模拟数据
- if (process.env.NODE_ENV === 'development') {
- const mockOrders = [
- {
- id: 'mock-1',
- title: '设备网络故障',
- order_no: `WO-${dayjs().format('YYYYMMDD')}-1001`,
- device_name: '网络交换机1',
- problem_desc: '设备无法连接网络',
- priority: WorkOrderPriority.URGENT,
- creator_id: 'system',
- creator_name: '系统管理员',
- deadline: dayjs().add(1, 'day').toISOString(),
- created_at: dayjs().toISOString(),
- updated_at: dayjs().toISOString(),
- problem_type: '网络',
- status: WorkOrderStatus.PENDING,
- feedback: '',
- attachments: []
- },
- {
- id: 'mock-2',
- title: '服务器硬件故障',
- order_no: `WO-${dayjs().format('YYYYMMDD')}-1002`,
- device_name: '服务器A',
- problem_desc: '硬盘故障需要更换',
- priority: WorkOrderPriority.IMPORTANT,
- creator_id: 'system',
- creator_name: '系统管理员',
- deadline: dayjs().add(2, 'day').toISOString(),
- created_at: dayjs().toISOString(),
- updated_at: dayjs().toISOString(),
- problem_type: '硬件',
- status: WorkOrderStatus.PROCESSING,
- feedback: '已订购新硬盘',
- attachments: []
- },
- {
- id: 'mock-3',
- title: '软件系统升级',
- order_no: `WO-${dayjs().format('YYYYMMDD')}-1003`,
- device_name: '办公电脑',
- problem_desc: '需要升级到最新版本',
- priority: WorkOrderPriority.NORMAL,
- creator_id: 'system',
- creator_name: '系统管理员',
- deadline: dayjs().add(3, 'day').toISOString(),
- created_at: dayjs().toISOString(),
- updated_at: dayjs().toISOString(),
- problem_type: '软件',
- status: WorkOrderStatus.CLOSED,
- feedback: '已完成升级',
- attachments: []
- },
- {
- id: 'mock-4',
- title: '打印机维护',
- order_no: `WO-${dayjs().format('YYYYMMDD')}-1004`,
- device_name: '办公室打印机',
- problem_desc: '定期维护保养',
- priority: WorkOrderPriority.NORMAL,
- creator_id: 'system',
- creator_name: '系统管理员',
- deadline: dayjs().add(4, 'day').toISOString(),
- created_at: dayjs().toISOString(),
- updated_at: dayjs().toISOString(),
- problem_type: '其他',
- status: WorkOrderStatus.PENDING,
- feedback: '',
- attachments: []
- },
- {
- id: 'mock-5',
- title: '数据库优化',
- order_no: `WO-${dayjs().format('YYYYMMDD')}-1005`,
- device_name: '数据库服务器',
- problem_desc: '查询性能优化',
- priority: WorkOrderPriority.IMPORTANT,
- creator_id: 'system',
- creator_name: '系统管理员',
- deadline: dayjs().add(5, 'day').toISOString(),
- created_at: dayjs().toISOString(),
- updated_at: dayjs().toISOString(),
- problem_type: '软件',
- status: WorkOrderStatus.PROCESSING,
- feedback: '正在优化索引',
- attachments: []
- }
- ];
- setWorkOrders(mockOrders);
- } else {
- fetchData();
- }
- fetchSettings();
- fetchCategories();
- fetchDevices();
- }, []);
- const [searchParams, setSearchParams] = useState({
- status: undefined,
- problemType: undefined,
- keyword: undefined,
- startDate: undefined,
- endDate: undefined
- });
- const fetchData = async () => {
- setLoading(true);
- try {
- const result = await WorkOrderAPI.getList(searchParams);
- setWorkOrders(result.data);
- } catch (error) {
- message.error('获取工单列表失败');
- } finally {
- setLoading(false);
- }
- };
- const handleSearch = (values: any) => {
- setSearchParams({
- status: values.status,
- problemType: values.problemType,
- keyword: values.keyword,
- startDate: values.dateRange?.[0]?.toISOString(),
- endDate: values.dateRange?.[1]?.toISOString()
- });
- };
- const handleReset = () => {
- setSearchParams({
- status: undefined,
- problemType: undefined,
- keyword: undefined,
- startDate: undefined,
- endDate: undefined
- });
- };
- const fetchSettings = async () => {
- try {
- const result = await WorkOrderAPI.getSettings();
- setSettings(result.data);
- } catch (error) {
- message.error('获取工单设置失败');
- }
- };
- const fetchCategories = async () => {
- try {
- const result = await WorkOrderAPI.getCategories();
- setCategories(result.data);
- } catch (error) {
- message.error('获取分类列表失败');
- }
- };
- const fetchDevices = async () => {
- try {
- const result = await DeviceInstanceAPI.getDeviceInstances();
- setDevices(result.data);
- } catch (error) {
- message.error('获取设备列表失败');
- }
- };
- const fetchComments = async (id: string) => {
- try {
- const result = await WorkOrderAPI.getComments(id);
- setComments(result.data);
- } catch (error) {
- message.error('获取评论失败');
- }
- };
- const fetchStatusHistory = async (id: string) => {
- try {
- const result = await WorkOrderAPI.getStatusHistory(id);
- setStatusHistory(result.data);
- } catch (error) {
- message.error('获取状态历史失败');
- }
- };
- const checkDeadline = async (order: WorkOrder) => {
- if (!order.deadline) return;
-
- try {
- const result = await WorkOrderAPI.getDeadline(order.id);
- const { remaining_hours, is_overdue } = result.data;
-
- let color = 'green';
- let text = '进行中';
- let progress = 100;
-
- if (is_overdue) {
- color = 'red';
- text = '已超时';
- progress = 0;
- } else if (remaining_hours < 24) {
- color = 'orange';
- text = `即将到期 (剩余${remaining_hours}小时)`;
- progress = Math.max(10, Math.min(90, remaining_hours * 4));
- }
-
- setDeadlineInfo({
- color,
- text,
- progress: Number(progress),
- remainingTime: `${remaining_hours}小时`,
- isOverdue: remaining_hours < 0,
- });
- } catch (error) {
- message.error('获取时限信息失败');
- }
- };
- const handleCreate = () => {
- setCurrentOrder({});
- setModalVisible(true);
- };
- const handleEdit = async (record: WorkOrder) => {
- setCurrentOrder(record);
- form.setFieldsValue(record);
- setModalVisible(true);
- checkDeadline(record);
- if (record.id) {
- await fetchComments(record.id);
- }
- };
- const handleSubmit = async () => {
- try {
- const values = await form.validateFields();
- if (currentOrder?.id) {
- await WorkOrderAPI.update(currentOrder.id, values);
- message.success('更新工单成功');
- } else {
- await WorkOrderAPI.create(values);
- message.success('创建工单成功');
- }
- setModalVisible(false);
- fetchData();
- } catch (error) {
- message.error('操作失败');
- }
- };
- const handleStatusChange = async (id: string, status: string) => {
- Modal.confirm({
- title: '确认状态变更',
- content: (
- <Form form={form}>
- <Form.Item name="comment" label="变更备注" rules={[{required: true}]}>
- <Input.TextArea placeholder="请输入状态变更原因" />
- </Form.Item>
- </Form>
- ),
- onOk: async (close) => {
- try {
- const values = await form.validateFields();
- await WorkOrderAPI.changeStatus(
- id,
- status,
- 'current_user', // TODO: 替换为实际用户
- values.comment
- );
- message.success('状态更新成功');
- fetchData();
- close();
- } catch (error) {
- message.error('状态更新失败');
- }
- }
- });
- };
- const renderStatusActions = (record: WorkOrder) => {
- const statusOptions = settings?.statusOptions || [];
- const currentStatusIndex = statusOptions.indexOf(record.status);
- const nextStatus = statusOptions[currentStatusIndex + 1];
- const prevStatus = statusOptions[currentStatusIndex - 1];
- return (
- <Space>
- {prevStatus && (
- <Button
- size="small"
- onClick={() => handleStatusChange(record.id, prevStatus)}
- >
- 回退到{prevStatus}
- </Button>
- )}
- {nextStatus && (
- <Button
- type="primary"
- size="small"
- onClick={() => handleStatusChange(record.id, nextStatus)}
- >
- 推进到{nextStatus}
- </Button>
- )}
- {!nextStatus && !prevStatus && (
- <span>无可用操作</span>
- )}
- </Space>
- );
- };
- const handleShowHistory = async (id: string) => {
- await fetchStatusHistory(id);
- setHistoryVisible(true);
- };
- const handleAssign = async (id: string, assignee: string) => {
- try {
- await WorkOrderAPI.assign(id, assignee);
- message.success('分配成功');
- fetchData();
- } catch (error) {
- message.error('分配失败');
- }
- };
- const handleUploadSuccess = (fileUrl: string, fileInfo: any) => {
- if (currentOrder?.id) {
- setAttachments(prev => [...prev, {
- id: fileInfo.id,
- url: fileUrl,
- name: fileInfo.original_filename
- }]);
- message.success('附件上传成功');
- }
- };
- const handleAddComment = async () => {
- if (!currentOrder?.id) {
- message.error('请先保存工单');
- return;
- }
-
- if (!commentContent.trim()) {
- message.error('评论内容不能为空');
- return;
- }
-
- if (commentContent.length > 500) {
- message.error('评论内容不能超过500字');
- return;
- }
-
- // 简单敏感词过滤
- const bannedWords = ['敏感词1', '敏感词2', '敏感词3'];
- if (bannedWords.some(word => commentContent.includes(word))) {
- message.error('评论包含不允许的内容');
- return;
- }
-
- try {
- await WorkOrderAPI.addComment(currentOrder.id, commentContent);
- setCommentContent('');
- await fetchComments(currentOrder.id);
- message.success('评论添加成功');
- } catch (error) {
- message.error('评论添加失败');
- }
- };
- const handleAccept = async (id: string) => {
- try {
- await WorkOrderAPI.changeStatus(id, '处理中', 'current_user', '工单已受理');
- message.success('工单受理成功');
- fetchData();
- } catch (error) {
- message.error('受理失败');
- }
- };
- const handleReassign = async (id: string) => {
- Modal.confirm({
- title: '改派工单',
- content: (
- <Select placeholder="选择新的处理人" style={{ width: '100%' }}>
- <Option value="user1">用户1</Option>
- <Option value="user2">用户2</Option>
- <Option value="user3">用户3</Option>
- </Select>
- ),
- onOk: async (close) => {
- try {
- await WorkOrderAPI.assign(id, 'new_assignee'); // TODO: 替换为实际选择的值
- message.success('工单改派成功');
- fetchData();
- close();
- } catch (error) {
- message.error('改派失败');
- }
- }
- });
- };
- const handleClose = async (id: string) => {
- Modal.confirm({
- title: '关闭工单',
- content: (
- <Form form={form}>
- <Form.Item name="feedback" label="处理结果" rules={[{required: true}]}>
- <TextArea placeholder="请输入处理结果反馈" />
- </Form.Item>
- </Form>
- ),
- onOk: async (close) => {
- try {
- const values = await form.validateFields();
- await WorkOrderAPI.changeStatus(
- id,
- '已关闭',
- 'current_user',
- values.feedback
- );
- message.success('工单已关闭');
- fetchData();
- close();
- } catch (error) {
- message.error('关闭失败');
- }
- }
- });
- };
- return (
- <div>
- <div style={{ marginBottom: 16, display: 'flex', justifyContent: 'space-between' }}>
- <Space>
- <Button type="primary" onClick={handleCreate}>
- 新建工单
- </Button>
- <Button type="primary" onClick={() => setAutoDispatchVisible(true)}>
- 自动派工
- </Button>
- </Space>
- <Space>
- <Button
- type="primary"
- onClick={async () => {
- try {
- const data = await WorkOrderAPI.exportList(searchParams);
- const url = window.URL.createObjectURL(new Blob([data]));
- const link = document.createElement('a');
- link.href = url;
- link.setAttribute('download', `工单列表_${dayjs().format('YYYYMMDD')}.xlsx`);
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
- message.success('导出成功');
- } catch (error) {
- message.error('导出失败');
- }
- }}
- >
- 工单导出
- </Button>
- </Space>
- </div>
- <Form layout="inline" onFinish={handleSearch} style={{ marginBottom: 16 }}>
- <Form.Item name="status" label="工单状态">
- <Select style={{ width: 120 }} allowClear>
- {Object.values(WorkOrderStatus).map(status => (
- <Option key={status} value={status}>{status}</Option>
- ))}
- </Select>
- </Form.Item>
- <Form.Item name="problemType" label="问题分类">
- <Select style={{ width: 120 }} allowClear>
- {categories.map(category => (
- <Option key={category} value={category}>{category}</Option>
- ))}
- </Select>
- </Form.Item>
- <Form.Item name="keyword" label="关键字">
- <Input placeholder="请输入关键字" />
- </Form.Item>
- <Form.Item name="dateRange" label="时间范围">
- <DatePicker.RangePicker />
- </Form.Item>
- <Form.Item>
- <Button type="primary" htmlType="submit">
- 查询
- </Button>
- <Button style={{ marginLeft: 8 }} onClick={handleReset}>
- 重置
- </Button>
- </Form.Item>
- </Form>
- <Table dataSource={workOrders} loading={loading} rowKey="id">
- <Column title="工单编号" dataIndex="order_no" key="order_no" />
- <Column title="设备名称" dataIndex="device_name" key="device_name" />
- <Column title="问题描述" dataIndex="problem_desc" key="problem_desc" ellipsis />
- <Column title="故障等级" dataIndex="priority" key="priority" />
- <Column title="创建人" dataIndex="creator_name" key="creator_name" />
- <Column
- title="截止日期"
- dataIndex="deadline"
- key="deadline"
- render={(deadline) => deadline ? dayjs(deadline).format('YYYY-MM-DD') : '-'}
- />
- <Column
- title="创建日期"
- dataIndex="created_at"
- key="created_at"
- render={(date) => dayjs(date).format('YYYY-MM-DD')}
- />
- <Column title="问题分类" dataIndex="problem_type" key="problem_type" />
- <Column
- title="状态"
- dataIndex="status"
- key="status"
- render={(status, record: WorkOrder) => (
- <Space>
- <span>{status}</span>
- {deadlineInfo && record.id === currentOrder?.id && (
- <Tag color={deadlineInfo.color}>{deadlineInfo.text}</Tag>
- )}
- </Space>
- )}
- />
- <Column
- title="结果反馈"
- dataIndex="feedback"
- key="feedback"
- render={(feedback) => (
- feedback ? (
- <a onClick={() => {
- setCurrentDetail(feedback);
- setDetailModalVisible(true);
- }}>详情</a>
- ) : '-'
- )}
- />
- <Column
- title="附件"
- dataIndex="attachments"
- key="attachments"
- render={(attachments) => attachments?.length > 0 ? `${attachments.length}个` : '无'}
- />
- <Column
- title="操作"
- key="action"
- render={(_, record: WorkOrder) => (
- <Space size="middle">
- <Dropdown
- overlay={
- <Menu>
- {record.status === '待受理' && (
- <Menu.Item key="accept" onClick={() => handleAccept(record.id)}>
- 受理
- </Menu.Item>
- )}
- {record.status === '处理中' && (
- <Menu.Item key="reassign" onClick={() => handleReassign(record.id)}>
- 改派
- </Menu.Item>
- )}
- <Menu.Item
- key="close"
- onClick={() => handleClose(record.id)}
- danger
- >
- 关闭
- </Menu.Item>
- </Menu>
- }
- >
- <Button type="primary" size="small">操作</Button>
- </Dropdown>
- <Button type="link" size="small" onClick={() => handleShowHistory(record.id)}>
- 流程
- </Button>
- </Space>
- )}
- />
- </Table>
- <Modal
- title={
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
- <div>{currentOrder?.id ? '工单详情' : '新建工单'}</div>
- <Button
- type="text"
- icon={<CloseOutlined />}
- onClick={() => setModalVisible(false)}
- style={{ marginRight: -16 }}
- />
- </div>
- }
- visible={modalVisible}
- onOk={handleSubmit}
- onCancel={() => setModalVisible(false)}
- width={800}
- footer={
- <div style={{ textAlign: 'center' }}>
- <Button key="submit" type="primary" onClick={handleSubmit}>
- 确定
- </Button>
- </div>
- }
- closable={false}
- >
- <Form form={form} layout="vertical">
- <Form.Item name="order_no" label="工单编号" rules={[{ required: true }]}>
- <Input placeholder="自动生成" disabled />
- </Form.Item>
- <Form.Item name="device_id" label="设备" rules={[{ required: true }]}>
- <Select showSearch optionFilterProp="children">
- {devices.map(device => (
- <Option key={device.id} value={device.id}>
- {device.name}
- </Option>
- ))}
- </Select>
- </Form.Item>
- <Form.Item name="problem_desc" label="问题描述" rules={[{ required: true }]}>
- <TextArea rows={4} />
- </Form.Item>
- <Form.Item name="priority" label="故障等级" rules={[{ required: true }]}>
- <Select>
- <Option value="紧急">紧急</Option>
- <Option value="高">高</Option>
- <Option value="中">中</Option>
- <Option value="低">低</Option>
- </Select>
- </Form.Item>
- <Form.Item name="deadline" label="截止日期" rules={[{ required: true }]}>
- <DatePicker style={{ width: '100%' }} />
- </Form.Item>
- <Form.Item name="problem_type" label="问题分类">
- <Select>
- {categories.map(category => (
- <Option key={category} value={category}>
- {category}
- </Option>
- ))}
- </Select>
- </Form.Item>
- <Form.Item name="feedback" label="结果反馈">
- <TextArea rows={2} />
- </Form.Item>
- <Form.Item label="附件">
- <Uploader
- onSuccess={handleUploadSuccess}
- onError={(error) => message.error(`上传失败: ${error.message}`)}
- onProgress={(percent) => (
- <Progress percent={percent} status="active" />
- )}
- />
- {attachments.length > 0 && (
- <List
- dataSource={attachments}
- renderItem={item => (
- <List.Item>
- <a href={item.url} target="_blank" rel="noopener noreferrer">
- {item.name}
- </a>
- </List.Item>
- )}
- />
- )}
- </Form.Item>
- </Form>
- {currentOrder?.id && (
- <div style={{ marginTop: 24 }}>
- <h3>评论</h3>
- <List
- className="comment-list"
- itemLayout="horizontal"
- dataSource={comments}
- renderItem={item => (
- <List.Item>
- <List.Item.Meta
- avatar={<Avatar>{item.author.charAt(0)}</Avatar>}
- title={item.author}
- description={item.content}
- />
- <div>{dayjs(item.created_at).format('YYYY-MM-DD HH:mm')}</div>
- </List.Item>
- )}
- />
- <TextArea
- rows={4}
- value={commentContent}
- onChange={(e) => setCommentContent(e.target.value)}
- placeholder="输入评论内容"
- />
- <Button
- type="primary"
- onClick={handleAddComment}
- style={{ marginTop: 16 }}
- >
- 提交评论
- </Button>
- </div>
- )}
- </Modal>
- <Modal
- title={`工单流程记录 (共${statusHistory.length}条)`}
- visible={historyVisible}
- onCancel={() => setHistoryVisible(false)}
- footer={null}
- width={800}
- >
- <div style={{ maxHeight: '60vh', overflowY: 'auto' }}>
- <Timeline mode="alternate">
- {statusHistory.map(item => (
- <Timeline.Item
- key={item.id}
- color={
- item.status_to === '已完成' ? 'green' :
- item.status_to === '已取消' ? 'red' : 'blue'
- }
- >
- <div style={{ padding: '8px 16px', background: '#f9f9f9', borderRadius: 4 }}>
- <strong>{item.status_from} → {item.status_to}</strong>
- <div style={{ marginTop: 8 }}>
- <Tag color="geekblue">{item.operator}</Tag>
- <Tag>{dayjs(item.created_at).format('YYYY-MM-DD HH:mm')}</Tag>
- </div>
- {item.comment && (
- <div style={{ marginTop: 8 }}>
- <p style={{ marginBottom: 0 }}><strong>备注:</strong></p>
- <p style={{ marginTop: 4 }}>{item.comment}</p>
- </div>
- )}
- </div>
- </Timeline.Item>
- ))}
- </Timeline>
- </div>
- </Modal>
- <Modal
- title={
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
- <div>
- 自动派工
- <Switch
- style={{ marginLeft: 16 }}
- checkedChildren="开"
- unCheckedChildren="关"
- defaultChecked
- />
- </div>
- <Button
- type="text"
- icon={<CloseOutlined />}
- onClick={() => setAutoDispatchVisible(false)}
- style={{ marginRight: -16 }}
- />
- </div>
- }
- open={autoDispatchVisible}
- footer={null}
- width={600}
- closable={false}
- onCancel={() => setAutoDispatchVisible(false)}
- >
- <Form form={autoDispatchForm} layout="vertical">
- <Form.Item name="device_type" label="设备分类">
- <Select placeholder="全部类型设备" allowClear>
- {categories.map(category => (
- <Option key={category} value={category}>{category}</Option>
- ))}
- </Select>
- </Form.Item>
- <Form.Item name="problem_desc" label="问题描述">
- <TextArea rows={3} placeholder="设备名称+告警故障" />
- </Form.Item>
- <Form.Item name="priority" label="故障等级" initialValue="中">
- <Select>
- <Option value="紧急">紧急</Option>
- <Option value="高">高</Option>
- <Option value="中">中</Option>
- <Option value="低">低</Option>
- </Select>
- </Form.Item>
- <Form.Item name="assignee" label="处理人" initialValue="admin">
- <Select>
- <Option value="admin">admin</Option>
- <Option value="user1">用户1</Option>
- <Option value="user2">用户2</Option>
- <Option value="user3">用户3</Option>
- </Select>
- </Form.Item>
- <Form.Item
- name="deadline"
- label="截止时间"
- initialValue={dayjs().add(2, 'day')}
- >
- <DatePicker style={{ width: '100%' }} />
- </Form.Item>
- <Form.Item>
- <div style={{ textAlign: 'center', marginTop: 24 }}>
- <Button
- type="primary"
- onClick={() => {
- autoDispatchForm.validateFields()
- .then(async values => {
- try {
- if (!values.problem_desc) {
- values.problem_desc = `设备${values.device_type || '全部'}告警故障`;
- }
-
- await WorkOrderAPI.create({
- ...values,
- title: '自动派工工单',
- creator_id: 'system',
- creator_name: '系统自动派工',
- status: '待受理'
- });
-
- message.success('自动派工成功');
- setAutoDispatchVisible(false);
- fetchData();
- } catch (error) {
- message.error('自动派工失败');
- }
- })
- .catch(info => {
- console.log('Validate Failed:', info);
- });
- }}
- style={{ width: 120 }}
- >
- 确认
- </Button>
- </div>
- </Form.Item>
- </Form>
- </Modal>
- <Modal
- title={
- <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
- <div>工单详情</div>
- <Button
- type="text"
- icon={<CloseOutlined />}
- onClick={() => setDetailModalVisible(false)}
- style={{ marginRight: -16 }}
- />
- </div>
- }
- visible={detailModalVisible}
- onCancel={() => setDetailModalVisible(false)}
- footer={null}
- width={600}
- closable={false}
- >
- <div style={{ padding: 16 }}>
- {currentDetail}
- </div>
- </Modal>
- </div>
- );
- }
|