|
|
@@ -1,12 +1,13 @@
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
import { Eye, Search, RotateCcw } from 'lucide-react';
|
|
|
-import { Button, Space, Table as AntdTable, Input, message, Modal, Form as AntdForm, Card, Alert, Select, DatePicker, InputNumber, Switch, Radio, Checkbox, Cascader, Upload } from 'antd';
|
|
|
-import { UploadOutlined, LockOutlined, KeyOutlined, WarningOutlined, CheckCircleOutlined } from '@ant-design/icons';
|
|
|
+import { Button, Space, Table as AntdTable, Input, message, Modal, Form as AntdForm, Card, Alert, Select, DatePicker, InputNumber, Switch, Radio, Checkbox, Cascader, Upload, Image } from 'antd';
|
|
|
+import { UploadOutlined, LockOutlined, KeyOutlined, WarningOutlined, CheckCircleOutlined, BarcodeOutlined, SendOutlined } from '@ant-design/icons';
|
|
|
import type { ColumnsType } from 'antd/es/table';
|
|
|
import { toast } from 'sonner';
|
|
|
import dayjs, { Dayjs } from 'dayjs';
|
|
|
import { taskManagementApi, MyTaskVO, MyTaskPageParam, PageResponse, MyTaskNodeDetailVO, UpdateNodeApprovalParam } from '../api/mytask';
|
|
|
+import { fileApi } from '../api/file';
|
|
|
import { dateFormatter } from '../utils/formatTime';
|
|
|
import { DICT_TYPE, getDictLabel } from '../utils/dict';
|
|
|
import { setConfAndFields2, FormCreateData } from '../utils/formCreate';
|
|
|
@@ -229,7 +230,12 @@ export default function TaskManagement() {
|
|
|
const [approvalComment, setApprovalComment] = useState(''); // 审核意见
|
|
|
const [approvalLoading, setApprovalLoading] = useState(false); // 审核操作loading状态
|
|
|
const [submitLoading, setSubmitLoading] = useState(false); // 提交操作loading状态
|
|
|
-
|
|
|
+ // 隔离方式字典(isolation_method:0=盲板,1=上锁挂牌,2=拆除)
|
|
|
+ const [isolationMethodDictList, setIsolationMethodDictList] = useState<any[]>([]);
|
|
|
+ // 盲板/拆除类型时的设备编号与附件(仅隔离/方案、解除隔离且隔离方式为盲板或拆除时使用)
|
|
|
+ const [isolationDeviceNumber, setIsolationDeviceNumber] = useState('');
|
|
|
+ const [isolationFileList, setIsolationFileList] = useState<any[]>([]);
|
|
|
+ const [isolationSubmitLoading, setIsolationSubmitLoading] = useState(false);
|
|
|
|
|
|
// 组件挂载时打印调试信息,并从 sessionStorage 读取 status
|
|
|
useEffect(() => {
|
|
|
@@ -288,9 +294,27 @@ export default function TaskManagement() {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ // 获取隔离方式字典(isolation_method)
|
|
|
+ const getIsolationMethodDictList = async () => {
|
|
|
+ try {
|
|
|
+ const { dictDataApi } = await import('../api/DictData');
|
|
|
+ const response = await dictDataApi.getDictDataPage({
|
|
|
+ pageNo: 1,
|
|
|
+ pageSize: -1,
|
|
|
+ dictType: 'isolation_method',
|
|
|
+ });
|
|
|
+ const data = (response as any)?.data || response;
|
|
|
+ const dictList = data?.list || [];
|
|
|
+ setIsolationMethodDictList(dictList);
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('获取隔离方式字典失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
getApprovalStatusDictList();
|
|
|
getUrgencyLevelDictList();
|
|
|
+ getIsolationMethodDictList();
|
|
|
}, []);
|
|
|
|
|
|
/** 查询列表 */
|
|
|
@@ -1050,6 +1074,15 @@ export default function TaskManagement() {
|
|
|
'detailDataWithWorkInfo': detailDataWithWorkInfo,
|
|
|
});
|
|
|
|
|
|
+ // 打开盲板/拆除详情时先清空设备编号和附件,后续若有 formData 再回填
|
|
|
+ if (isIsolation || isReleaseIsolation) {
|
|
|
+ const isolationType = String(detailDataWithWorkInfo.isolationType ?? '').trim();
|
|
|
+ if (isolationType === '0' || isolationType === '2') {
|
|
|
+ setIsolationDeviceNumber('');
|
|
|
+ setIsolationFileList([]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 如果任务状态为"已通过"且有 formData,则从 formData 中解析表单结构
|
|
|
if (isApproved && hasFormData) {
|
|
|
console.log('TaskManagement: ✅ 任务已通过,从 formData 中解析表单结构');
|
|
|
@@ -1158,6 +1191,23 @@ export default function TaskManagement() {
|
|
|
detailForm.setFieldsValue(convertedFormValues);
|
|
|
console.log('TaskManagement: 表单数据已回填(从 formData)', convertedFormValues);
|
|
|
}, 100);
|
|
|
+ } else if (
|
|
|
+ parsedFormData.deviceNumber !== undefined ||
|
|
|
+ (Array.isArray(parsedFormData.attachments) && parsedFormData.attachments.length > 0)
|
|
|
+ ) {
|
|
|
+ // 盲板/拆除 表单回显:deviceNumber + attachments
|
|
|
+ setIsolationDeviceNumber(parsedFormData.deviceNumber ?? '');
|
|
|
+ const list = Array.isArray(parsedFormData.attachments) ? parsedFormData.attachments : [];
|
|
|
+ setIsolationFileList(
|
|
|
+ list.map((item: any, idx: number) => ({
|
|
|
+ uid: `echo-${idx}-${item.url || item.name || idx}`,
|
|
|
+ name: item.name || `文件${idx + 1}`,
|
|
|
+ url: item.url || item.response,
|
|
|
+ status: 'done',
|
|
|
+ response: item.url || item.response,
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ console.log('TaskManagement: 盲板/拆除 formData 已回显', { deviceNumber: parsedFormData.deviceNumber, attachmentsCount: list.length });
|
|
|
} else {
|
|
|
console.warn('TaskManagement: formData 中缺少 conf 或 fields', { conf: !!conf, fields: !!fields });
|
|
|
message.warning('表单数据不完整');
|
|
|
@@ -1822,6 +1872,8 @@ export default function TaskManagement() {
|
|
|
setOriginalConf('');
|
|
|
detailForm.resetFields();
|
|
|
setApprovalComment('');
|
|
|
+ setIsolationDeviceNumber('');
|
|
|
+ setIsolationFileList([]);
|
|
|
}}
|
|
|
footer={null}
|
|
|
width={1000}
|
|
|
@@ -1916,54 +1968,275 @@ export default function TaskManagement() {
|
|
|
|
|
|
// 隔离/方案节点、解除隔离节点和还锁节点
|
|
|
if (isIsolation || isReleaseIsolation || isReturnLock) {
|
|
|
- console.log('TaskManagement: ✅ 进入隔离节点渲染分支', { isIsolation, isReleaseIsolation, isReturnLock, nodeType });
|
|
|
+ const isolationType = String(detailData?.isolationType ?? '').trim();
|
|
|
+ const isLockoutTagout = isolationType === '1'; // 上锁挂牌
|
|
|
+ const isBlindPlate = isolationType === '0'; // 盲板
|
|
|
+ const isDismantle = isolationType === '2'; // 拆除
|
|
|
+ const showLockCabinet = isReturnLock || (isLockoutTagout && (isIsolation || isReleaseIsolation));
|
|
|
+ const showDeviceForm = (isIsolation || isReleaseIsolation) && (isBlindPlate || isDismantle);
|
|
|
+
|
|
|
+ if (showDeviceForm) {
|
|
|
+ const deviceLabel = isReleaseIsolation
|
|
|
+ ? (isBlindPlate ? t('form.releaseBlindPlateDeviceNo') : t('form.restoreDeviceNo'))
|
|
|
+ : (isBlindPlate ? t('form.blindPlateDeviceNo') : t('form.dismantleDeviceNo'));
|
|
|
+ return (
|
|
|
+ <div key="isolation-device-form" style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
|
|
+ <div style={{ flex: 1, minHeight: 0, overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
|
|
|
+ <Card
|
|
|
+ style={{
|
|
|
+ width: '100%',
|
|
|
+ maxWidth: 500,
|
|
|
+ boxShadow: '0 8px 32px rgba(22, 119, 255, 0.12), 0 2px 8px rgba(0,0,0,0.04)',
|
|
|
+ borderRadius: 16,
|
|
|
+ border: '1px solid rgba(22, 119, 255, 0.15)',
|
|
|
+ overflow: 'hidden',
|
|
|
+ background: 'linear-gradient(180deg, #ffffff 0%, #fafcff 100%)',
|
|
|
+ }}
|
|
|
+ bodyStyle={{ padding: 0 }}
|
|
|
+ >
|
|
|
+ <div style={{ padding: '24px 32px 28px' }}>
|
|
|
+ <div style={{ marginBottom: 26 }}>
|
|
|
+ <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 14, fontWeight: 600, color: '#1f2937', marginBottom: 12 }}>
|
|
|
+ <span style={{ width: 28, height: 28, borderRadius: 8, background: '#e6f4ff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
+ <BarcodeOutlined style={{ fontSize: 14, color: '#1677ff' }} />
|
|
|
+ </span>
|
|
|
+ {deviceLabel}
|
|
|
+ </label>
|
|
|
+ <Input
|
|
|
+ value={isolationDeviceNumber}
|
|
|
+ onChange={(e) => !isApproved && setIsolationDeviceNumber(e.target.value)}
|
|
|
+ placeholder={`请输入${deviceLabel}`}
|
|
|
+ maxLength={100}
|
|
|
+ size="large"
|
|
|
+ disabled={isApproved}
|
|
|
+ prefix={<BarcodeOutlined style={{ color: '#91caff', marginRight: 8 }} />}
|
|
|
+ style={{ borderRadius: 10, borderColor: '#d9e8ff', fontSize: 15 }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 14, fontWeight: 600, color: '#1f2937', marginBottom: 12 }}>
|
|
|
+ <span style={{ width: 28, height: 28, borderRadius: 8, background: '#e6f4ff', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
+ <UploadOutlined style={{ fontSize: 14, color: '#1677ff' }} />
|
|
|
+ </span>
|
|
|
+ 附件上传
|
|
|
+ {!isApproved && <span style={{ marginLeft: 8, fontSize: 12, fontWeight: 400, color: '#69b1ff', background: '#e6f4ff', padding: '2px 8px', borderRadius: 6 }}>支持拖拽</span>}
|
|
|
+ </label>
|
|
|
+ {isApproved && isolationFileList.length > 0 ? (
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ borderRadius: 12,
|
|
|
+ padding: '32px 20px',
|
|
|
+ background: 'linear-gradient(180deg, #f5faff 0%, #e8f4ff 50%, #e0efff 100%)',
|
|
|
+ border: '2px solid #91caff',
|
|
|
+ minHeight: 180,
|
|
|
+ display: 'flex',
|
|
|
+ flexWrap: 'wrap',
|
|
|
+ gap: 16,
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ alignContent: 'center',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Image.PreviewGroup>
|
|
|
+ {isolationFileList.filter((f: any) => {
|
|
|
+ const u = f.url || f.response;
|
|
|
+ return /\.(jpg|jpeg|png|gif|webp|bmp)(\?|$)/i.test(String(u || '')) || /\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(String(f.name || ''));
|
|
|
+ }).map((file: any) => (
|
|
|
+ <Image
|
|
|
+ key={file.uid}
|
|
|
+ width={160}
|
|
|
+ height={160}
|
|
|
+ src={file.url || file.response}
|
|
|
+ style={{ objectFit: 'cover', borderRadius: 10, cursor: 'pointer', flexShrink: 0 }}
|
|
|
+ alt={file.name}
|
|
|
+ />
|
|
|
+ ))}
|
|
|
+ </Image.PreviewGroup>
|
|
|
+ {isolationFileList.filter((f: any) => {
|
|
|
+ const u = f.url || f.response;
|
|
|
+ return !/\.(jpg|jpeg|png|gif|webp|bmp)(\?|$)/i.test(String(u || '')) && !/\.(jpg|jpeg|png|gif|webp|bmp)$/i.test(String(f.name || ''));
|
|
|
+ }).map((file: any) => (
|
|
|
+ <a
|
|
|
+ key={file.uid}
|
|
|
+ href={file.url || file.response}
|
|
|
+ target="_blank"
|
|
|
+ rel="noopener noreferrer"
|
|
|
+ style={{ display: 'block', padding: '12px 16px', background: '#fff', borderRadius: 10, color: '#1677ff', border: '1px solid #91caff', maxWidth: 240, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}
|
|
|
+ >
|
|
|
+ {file.name}
|
|
|
+ </a>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ ) : isApproved ? (
|
|
|
+ <div style={{ padding: 24, textAlign: 'center', color: '#8c8c8c', background: '#fafafa', borderRadius: 12 }}>暂无附件</div>
|
|
|
+ ) : (
|
|
|
+ <Upload.Dragger
|
|
|
+ fileList={isolationFileList}
|
|
|
+ onChange={({ fileList }) => setIsolationFileList(fileList.slice(-5))}
|
|
|
+ multiple
|
|
|
+ showUploadList={{ showRemoveIcon: true }}
|
|
|
+ customRequest={async ({ file, onSuccess, onError }) => {
|
|
|
+ try {
|
|
|
+ const url = await fileApi.upload(file as File);
|
|
|
+ onSuccess?.(url);
|
|
|
+ } catch (e: any) {
|
|
|
+ onError?.(e);
|
|
|
+ message.error(e?.message || '文件上传失败');
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ style={{
|
|
|
+ borderRadius: 12,
|
|
|
+ padding: '32px 20px',
|
|
|
+ background: 'linear-gradient(180deg, #f5faff 0%, #e8f4ff 50%, #e0efff 100%)',
|
|
|
+ border: '2px dashed #91caff',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <p className="ant-upload-drag-icon" style={{ marginBottom: 12 }}>
|
|
|
+ <span style={{ width: 64, height: 64, borderRadius: 16, background: 'linear-gradient(135deg, rgba(22,119,255,0.15) 0%, rgba(64,150,255,0.1) 100%)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
|
+ <UploadOutlined style={{ fontSize: 32, color: '#1677ff' }} />
|
|
|
+ </span>
|
|
|
+ </p>
|
|
|
+ <p className="ant-upload-text" style={{ margin: 0, color: '#0958d9', fontSize: 15, fontWeight: 500 }}>点击或拖拽文件到此区域上传</p>
|
|
|
+ <p className="ant-upload-hint" style={{ margin: '8px 0 0', color: '#69b1ff', fontSize: 13 }}>最多 5 个文件,支持多选</p>
|
|
|
+ </Upload.Dragger>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </Card>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-end gap-3" style={{ padding: '20px 24px', borderTop: '1px solid rgba(22, 119, 255, 0.1)', flexShrink: 0, background: 'linear-gradient(0deg, #f0f7ff 0%, #fafcff 60%, #fff 100%)' }}>
|
|
|
+ {!isApproved ? (
|
|
|
+ <Button
|
|
|
+ type="primary"
|
|
|
+ loading={isolationSubmitLoading}
|
|
|
+ onClick={async () => {
|
|
|
+ const nodeId = detailData.nodeId || detailData.id;
|
|
|
+ if (!nodeId) {
|
|
|
+ message.error('节点ID不存在');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const uploadedFiles = isolationFileList.filter((f: any) => f.status === 'done' && (f.response != null));
|
|
|
+ const uploadingCount = isolationFileList.filter((f: any) => f.status === 'uploading').length;
|
|
|
+ if (uploadingCount > 0) {
|
|
|
+ message.warning('请等待文件上传完成');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (isolationFileList.length > 0 && uploadedFiles.length === 0) {
|
|
|
+ message.warning('请等待文件上传完成或移除未上传成功的文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ setIsolationSubmitLoading(true);
|
|
|
+ try {
|
|
|
+ const attachmentUrls = uploadedFiles.map((f: any) => {
|
|
|
+ const url = typeof f.response === 'string' ? f.response : (f.response?.url ?? '');
|
|
|
+ return { name: f.name, url };
|
|
|
+ });
|
|
|
+ const payload = {
|
|
|
+ deviceNumber: isolationDeviceNumber,
|
|
|
+ attachments: attachmentUrls,
|
|
|
+ };
|
|
|
+ const formDataString = JSON.stringify(payload);
|
|
|
+ await taskManagementApi.updateNodeApproval({
|
|
|
+ nodeId: typeof nodeId === 'number' ? nodeId : Number(nodeId),
|
|
|
+ approvalStatus: 'approved',
|
|
|
+ formData: formDataString,
|
|
|
+ });
|
|
|
+ message.success(t('common.submit') + t('common.success'));
|
|
|
+ setDetailVisible(false);
|
|
|
+ setDetailData(null);
|
|
|
+ setIsolationDeviceNumber('');
|
|
|
+ setIsolationFileList([]);
|
|
|
+ getList();
|
|
|
+ } catch (error: any) {
|
|
|
+ message.error(error?.message || '提交失败');
|
|
|
+ } finally {
|
|
|
+ setIsolationSubmitLoading(false);
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ icon={<SendOutlined />}
|
|
|
+ style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500, boxShadow: '0 4px 14px rgba(22, 119, 255, 0.35)' }}
|
|
|
+ >
|
|
|
+ {t('common.submit')}
|
|
|
+ </Button>
|
|
|
+ ) : (
|
|
|
+ <Button
|
|
|
+ onClick={() => {
|
|
|
+ setDetailVisible(false);
|
|
|
+ setDetailData(null);
|
|
|
+ setIsolationDeviceNumber('');
|
|
|
+ setIsolationFileList([]);
|
|
|
+ }}
|
|
|
+ style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500 }}
|
|
|
+ >
|
|
|
+ {t('common.cancel')}
|
|
|
+ </Button>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('TaskManagement: ✅ 进入隔离节点渲染分支', { isIsolation, isReleaseIsolation, isReturnLock, nodeType, isolationType });
|
|
|
const isolationContent = (
|
|
|
- <div
|
|
|
+ <div
|
|
|
key="isolation-content"
|
|
|
style={{
|
|
|
+ flex: 1,
|
|
|
+ minHeight: 0,
|
|
|
+ overflow: 'hidden',
|
|
|
display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
alignItems: 'center',
|
|
|
- minHeight: '400px',
|
|
|
- padding: '40px 20px'
|
|
|
+ justifyContent: 'center',
|
|
|
+ padding: '24px',
|
|
|
+ background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)',
|
|
|
}}
|
|
|
>
|
|
|
<Card
|
|
|
style={{
|
|
|
width: '100%',
|
|
|
- maxWidth: '500px',
|
|
|
+ maxWidth: 500,
|
|
|
textAlign: 'center',
|
|
|
- borderRadius: '12px',
|
|
|
- boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
|
|
- border: '1px solid #e8e8e8'
|
|
|
- }}
|
|
|
- bodyStyle={{
|
|
|
- padding: '40px 30px'
|
|
|
+ borderRadius: 16,
|
|
|
+ boxShadow: '0 8px 32px rgba(22, 119, 255, 0.12), 0 2px 8px rgba(0,0,0,0.04)',
|
|
|
+ border: '1px solid rgba(22, 119, 255, 0.15)',
|
|
|
+ background: 'linear-gradient(180deg, #ffffff 0%, #fafcff 100%)',
|
|
|
}}
|
|
|
+ bodyStyle={{ padding: '48px 40px' }}
|
|
|
>
|
|
|
- <div style={{ marginBottom: '24px' }}>
|
|
|
- <LockOutlined
|
|
|
- style={{
|
|
|
- fontSize: '64px',
|
|
|
- color: '#1890ff',
|
|
|
- display: 'block'
|
|
|
- }}
|
|
|
- />
|
|
|
+ <div style={{ marginBottom: 28 }}>
|
|
|
+ <span
|
|
|
+ style={{
|
|
|
+ width: 88,
|
|
|
+ height: 88,
|
|
|
+ borderRadius: 20,
|
|
|
+ background: 'linear-gradient(135deg, #1677ff 0%, #4096ff 50%, #69b1ff 100%)',
|
|
|
+ display: 'inline-flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ boxShadow: '0 8px 24px rgba(22, 119, 255, 0.35)',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <LockOutlined style={{ fontSize: 42, color: '#fff' }} />
|
|
|
+ </span>
|
|
|
</div>
|
|
|
<div
|
|
|
style={{
|
|
|
- fontSize: '20px',
|
|
|
- fontWeight: 500,
|
|
|
- color: '#333',
|
|
|
- lineHeight: '1.6'
|
|
|
+ fontSize: 18,
|
|
|
+ fontWeight: 600,
|
|
|
+ color: '#1f2937',
|
|
|
+ lineHeight: 1.6,
|
|
|
+ marginBottom: 8,
|
|
|
}}
|
|
|
>
|
|
|
{t('form.lockCabinetTip')}
|
|
|
</div>
|
|
|
+ <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 13, color: '#69b1ff' }}>
|
|
|
+ <KeyOutlined />
|
|
|
+ <span>完成取锁、取钥匙后,任务将自动推进</span>
|
|
|
+ </div>
|
|
|
</Card>
|
|
|
</div>
|
|
|
);
|
|
|
- console.log('TaskManagement: 隔离节点内容已创建', isolationContent);
|
|
|
return isolationContent;
|
|
|
}
|
|
|
|
|
|
@@ -2382,59 +2655,65 @@ export default function TaskManagement() {
|
|
|
})()}
|
|
|
</div>
|
|
|
) : (
|
|
|
- <div
|
|
|
+ <div
|
|
|
style={{
|
|
|
+ flex: 1,
|
|
|
+ minHeight: 0,
|
|
|
+ overflow: 'hidden',
|
|
|
display: 'flex',
|
|
|
- justifyContent: 'center',
|
|
|
alignItems: 'center',
|
|
|
- minHeight: '400px',
|
|
|
- padding: '40px 20px'
|
|
|
+ justifyContent: 'center',
|
|
|
+ padding: '24px',
|
|
|
+ background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)',
|
|
|
}}
|
|
|
>
|
|
|
<Card
|
|
|
style={{
|
|
|
width: '100%',
|
|
|
- maxWidth: '500px',
|
|
|
+ maxWidth: 500,
|
|
|
textAlign: 'center',
|
|
|
- borderRadius: '12px',
|
|
|
- boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
|
|
- border: '1px solid #e8e8e8'
|
|
|
- }}
|
|
|
- bodyStyle={{
|
|
|
- padding: '40px 30px'
|
|
|
+ borderRadius: 16,
|
|
|
+ boxShadow: '0 8px 32px rgba(22, 119, 255, 0.12), 0 2px 8px rgba(0,0,0,0.04)',
|
|
|
+ border: '1px solid rgba(22, 119, 255, 0.15)',
|
|
|
+ background: 'linear-gradient(180deg, #ffffff 0%, #fafcff 100%)',
|
|
|
}}
|
|
|
+ bodyStyle={{ padding: '48px 40px' }}
|
|
|
>
|
|
|
- <div style={{ marginBottom: '24px' }}>
|
|
|
- <CheckCircleOutlined
|
|
|
- style={{
|
|
|
- fontSize: '64px',
|
|
|
- color: '#1890ff',
|
|
|
- display: 'block'
|
|
|
- }}
|
|
|
- />
|
|
|
+ <div style={{ marginBottom: 24 }}>
|
|
|
+ <span
|
|
|
+ style={{
|
|
|
+ width: 88,
|
|
|
+ height: 88,
|
|
|
+ borderRadius: 20,
|
|
|
+ background: 'linear-gradient(135deg, #52c41a 0%, #73d13d 50%, #95de64 100%)',
|
|
|
+ display: 'inline-flex',
|
|
|
+ alignItems: 'center',
|
|
|
+ justifyContent: 'center',
|
|
|
+ boxShadow: '0 8px 24px rgba(82, 196, 26, 0.35)',
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <CheckCircleOutlined style={{ fontSize: 42, color: '#fff' }} />
|
|
|
+ </span>
|
|
|
</div>
|
|
|
- <div
|
|
|
- style={{
|
|
|
- fontSize: '20px',
|
|
|
- fontWeight: 500,
|
|
|
- color: '#333',
|
|
|
- lineHeight: '1.6'
|
|
|
- }}
|
|
|
- >
|
|
|
+ <div style={{ fontSize: 18, fontWeight: 600, color: '#1f2937', lineHeight: 1.6 }}>
|
|
|
无需填写表单,直接点击底部按钮提交即可
|
|
|
</div>
|
|
|
+ <div style={{ marginTop: 12, fontSize: 13, color: '#69b1ff' }}>
|
|
|
+ 确认无误后点击「完成」结束本节点
|
|
|
+ </div>
|
|
|
</Card>
|
|
|
</div>
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
{/* 底部按钮 */}
|
|
|
- <div
|
|
|
+ <div
|
|
|
className="flex justify-end gap-3"
|
|
|
style={{
|
|
|
- padding: '16px 24px',
|
|
|
- borderTop: '1px solid #f0f0f0',
|
|
|
- flexShrink: 0
|
|
|
+ padding: '20px 24px',
|
|
|
+ borderTop: '1px solid rgba(22, 119, 255, 0.1)',
|
|
|
+ flexShrink: 0,
|
|
|
+ background: 'linear-gradient(0deg, #f0f7ff 0%, #fafcff 60%, #fff 100%)',
|
|
|
}}
|
|
|
>
|
|
|
<Button
|
|
|
@@ -2446,6 +2725,7 @@ export default function TaskManagement() {
|
|
|
setOriginalConf('');
|
|
|
detailForm.resetFields();
|
|
|
}}
|
|
|
+ style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500 }}
|
|
|
>
|
|
|
{t('common.cancel')}
|
|
|
</Button>
|
|
|
@@ -2540,6 +2820,7 @@ export default function TaskManagement() {
|
|
|
setSubmitLoading(false);
|
|
|
}
|
|
|
}}
|
|
|
+ style={{ minWidth: 120, height: 44, borderRadius: 10, fontSize: 15, fontWeight: 500, boxShadow: '0 4px 14px rgba(22, 119, 255, 0.35)' }}
|
|
|
>
|
|
|
{(() => {
|
|
|
// 从 detailData.type 或 detailData.nodeType 获取节点类型
|