|
|
@@ -1063,6 +1063,13 @@ export default function MyTask() {
|
|
|
'detailDataWithWorkInfo': detailDataWithWorkInfo,
|
|
|
});
|
|
|
|
|
|
+ // 当前节点无表单(无 formId 且不会从 formData 解析出表单)时清空表单 state,避免完成/结束节点误展示上一节点的自定义表单
|
|
|
+ if (!hasFormId && !(isApproved && hasFormData)) {
|
|
|
+ setFormData({ rule: [], option: {} });
|
|
|
+ setOriginalFields([]);
|
|
|
+ setOriginalConf('');
|
|
|
+ }
|
|
|
+
|
|
|
// 打开盲板/拆除详情时先清空设备编号和附件,后续若有 formData 再回填
|
|
|
if (isIsolation || isReleaseIsolation) {
|
|
|
const isolationType = String(detailDataWithWorkInfo.isolationType ?? '').trim();
|
|
|
@@ -1180,15 +1187,42 @@ export default function MyTask() {
|
|
|
detailForm.setFieldsValue(convertedFormValues);
|
|
|
console.log('MyTask: 表单数据已回填(从 formData)', convertedFormValues);
|
|
|
}, 100);
|
|
|
+ // 有 conf/fields 时也回显 deviceNumber、attachments;attachments 可能是 JSON 字符串
|
|
|
+ const normAttachments = (att: any): any[] => {
|
|
|
+ if (att == null) return []; if (Array.isArray(att)) return att;
|
|
|
+ if (typeof att === 'string' && att.trim()) { try { const p = JSON.parse(att); return Array.isArray(p) ? p : []; } catch { return []; } } return [];
|
|
|
+ };
|
|
|
+ const listInConf = normAttachments(parsedFormData.attachments).length ? normAttachments(parsedFormData.attachments) : normAttachments((detailDataWithWorkInfo as any).attachments);
|
|
|
+ const deviceNumInConf = parsedFormData.deviceNumber ?? (detailDataWithWorkInfo as any).deviceNumber;
|
|
|
+ const hasDeviceInConf = deviceNumInConf !== undefined && deviceNumInConf !== null;
|
|
|
+ if (hasDeviceInConf || listInConf.length > 0) {
|
|
|
+ setIsolationDeviceNumber(deviceNumInConf ?? '');
|
|
|
+ setIsolationFileList(
|
|
|
+ listInConf.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('MyTask: 盲板/拆除 deviceNumber/attachments 已回显', { deviceNumber: deviceNumInConf, attachmentsCount: listInConf.length });
|
|
|
+ }
|
|
|
} else if (
|
|
|
- parsedFormData.deviceNumber !== undefined ||
|
|
|
- (Array.isArray(parsedFormData.attachments) && parsedFormData.attachments.length > 0)
|
|
|
+ (() => {
|
|
|
+ const d = parsedFormData.deviceNumber; const a = parsedFormData.attachments;
|
|
|
+ if (d !== undefined && d !== null) return true;
|
|
|
+ if (a == null) return false; if (Array.isArray(a) && a.length > 0) return true;
|
|
|
+ if (typeof a === 'string' && a.trim()) { try { const p = JSON.parse(a); return Array.isArray(p) && p.length > 0; } catch { return false; } } return false;
|
|
|
+ })()
|
|
|
) {
|
|
|
- // 盲板/拆除 表单回显:deviceNumber + attachments
|
|
|
+ const listElse = (() => {
|
|
|
+ const a = parsedFormData.attachments; if (a == null) return []; if (Array.isArray(a)) return a;
|
|
|
+ if (typeof a === 'string' && a.trim()) { try { const p = JSON.parse(a); return Array.isArray(p) ? p : []; } catch { return []; } } return [];
|
|
|
+ })();
|
|
|
setIsolationDeviceNumber(parsedFormData.deviceNumber ?? '');
|
|
|
- const list = Array.isArray(parsedFormData.attachments) ? parsedFormData.attachments : [];
|
|
|
setIsolationFileList(
|
|
|
- list.map((item: any, idx: number) => ({
|
|
|
+ listElse.map((item: any, idx: number) => ({
|
|
|
uid: `echo-${idx}-${item.url || item.name || idx}`,
|
|
|
name: item.name || `文件${idx + 1}`,
|
|
|
url: item.url || item.response,
|
|
|
@@ -1196,7 +1230,7 @@ export default function MyTask() {
|
|
|
response: item.url || item.response,
|
|
|
}))
|
|
|
);
|
|
|
- console.log('MyTask: 盲板/拆除 formData 已回显', { deviceNumber: parsedFormData.deviceNumber, attachmentsCount: list.length });
|
|
|
+ console.log('MyTask: 盲板/拆除 formData 已回显', { deviceNumber: parsedFormData.deviceNumber, attachmentsCount: listElse.length });
|
|
|
} else {
|
|
|
// 完成/结束等节点可能无表单内容,不提示“表单数据不完整”,有则显示、无则不显示即可
|
|
|
console.warn('MyTask: formData 中缺少 conf 或 fields', { conf: !!conf, fields: !!fields });
|
|
|
@@ -1282,8 +1316,9 @@ export default function MyTask() {
|
|
|
fieldsCount: Array.isArray(fields) ? fields.length : 0
|
|
|
});
|
|
|
|
|
|
- // 如果有表单数据值,回填到表单(在表单配置设置后)
|
|
|
- if (detailDataWithWorkInfo.formData) {
|
|
|
+ // 仅任务已完成(approved)时回显表单数据;进行中一律不回显并清空表单
|
|
|
+ const shouldEchoFormData = detailDataWithWorkInfo.formData && isApproved;
|
|
|
+ if (shouldEchoFormData) {
|
|
|
try {
|
|
|
let formValues = typeof detailDataWithWorkInfo.formData === 'string'
|
|
|
? JSON.parse(detailDataWithWorkInfo.formData)
|
|
|
@@ -1381,6 +1416,31 @@ export default function MyTask() {
|
|
|
} catch (e) {
|
|
|
console.error('MyTask: 解析表单数据失败', e);
|
|
|
}
|
|
|
+ } else if (!isApproved) {
|
|
|
+ // 任务进行中:清空自定义表单,避免带出历史或隔离方案等填写内容
|
|
|
+ setTimeout(() => { try { detailForm.resetFields(); } catch (_) { /* ignore */ } }, 100);
|
|
|
+ }
|
|
|
+ // 隔离/解除隔离完成查看详情:从 formData 回显 deviceNumber、attachments
|
|
|
+ // 隔离/解除隔离完成查看详情:从 formData 或节点详情顶层回显(部分解除隔离节点仅顶层有数据)
|
|
|
+ if (isApproved && (isIsolation || isReleaseIsolation)) {
|
|
|
+ try {
|
|
|
+ const normAtt = (att: any): any[] => { if (att == null) return []; if (Array.isArray(att)) return att; if (typeof att === 'string' && att.trim()) { try { const p = JSON.parse(att); return Array.isArray(p) ? p : []; } catch { return []; } } return []; };
|
|
|
+ let deviceNum: any; let listF: any[];
|
|
|
+ if (detailDataWithWorkInfo.formData) {
|
|
|
+ const parsed = typeof detailDataWithWorkInfo.formData === 'string' ? JSON.parse(detailDataWithWorkInfo.formData) : detailDataWithWorkInfo.formData;
|
|
|
+ listF = normAtt(parsed.attachments).length ? normAtt(parsed.attachments) : normAtt((detailDataWithWorkInfo as any).attachments);
|
|
|
+ deviceNum = parsed.deviceNumber ?? (detailDataWithWorkInfo as any).deviceNumber;
|
|
|
+ } else {
|
|
|
+ deviceNum = (detailDataWithWorkInfo as any).deviceNumber;
|
|
|
+ listF = normAtt((detailDataWithWorkInfo as any).attachments);
|
|
|
+ }
|
|
|
+ const hasDev = deviceNum !== undefined && deviceNum !== null;
|
|
|
+ if (hasDev || listF.length > 0) {
|
|
|
+ setIsolationDeviceNumber(deviceNum ?? '');
|
|
|
+ setIsolationFileList(listF.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('MyTask: formId 分支 deviceNumber/attachments 已回显', { deviceNumber: deviceNum, attachmentsCount: listF.length });
|
|
|
+ }
|
|
|
+ } catch (_) { /* ignore */ }
|
|
|
}
|
|
|
} else {
|
|
|
console.warn('MyTask: 表单详情缺少配置或字段', { conf: !!conf, fields: !!fields, formDetail });
|
|
|
@@ -1396,6 +1456,17 @@ export default function MyTask() {
|
|
|
})();
|
|
|
} else {
|
|
|
setFormLoading(false);
|
|
|
+ if (isApproved && (isIsolation || isReleaseIsolation)) {
|
|
|
+ try {
|
|
|
+ const normAtt = (att: any): any[] => { if (att == null) return []; if (Array.isArray(att)) return att; if (typeof att === 'string' && att.trim()) { try { const p = JSON.parse(att); return Array.isArray(p) ? p : []; } catch { return []; } } return []; };
|
|
|
+ const deviceNum = (detailDataWithWorkInfo as any).deviceNumber;
|
|
|
+ const listF = normAtt((detailDataWithWorkInfo as any).attachments);
|
|
|
+ if ((deviceNum !== undefined && deviceNum !== null) || listF.length > 0) {
|
|
|
+ setIsolationDeviceNumber(deviceNum ?? '');
|
|
|
+ setIsolationFileList(listF.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 })));
|
|
|
+ }
|
|
|
+ } catch (_) { /* ignore */ }
|
|
|
+ }
|
|
|
if (isIsolation || isReleaseIsolation || isReturnLock) {
|
|
|
console.log('MyTask: ⚠️ 隔离类型节点,跳过表单配置获取', { nodeType, isIsolation, isReleaseIsolation, isReturnLock });
|
|
|
} else if (!hasFormId) {
|
|
|
@@ -1957,6 +2028,9 @@ export default function MyTask() {
|
|
|
'typeof detailData.type': typeof detailData.type,
|
|
|
'String(detailData.type)': String(detailData.type)
|
|
|
});
|
|
|
+ const hasFormIdForCurrentNode = detailData?.formId !== undefined && detailData?.formId !== null && (
|
|
|
+ typeof detailData.formId === 'number' || (typeof detailData.formId === 'string' && String(detailData.formId).trim() !== '')
|
|
|
+ );
|
|
|
|
|
|
// 隔离/方案节点、解除隔离节点和还锁节点
|
|
|
if (isIsolation || isReleaseIsolation || isReturnLock) {
|
|
|
@@ -1978,20 +2052,7 @@ export default function MyTask() {
|
|
|
return (
|
|
|
<div key="isolation-device-form" style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
|
|
<div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
|
|
|
- <Card
|
|
|
- style={{
|
|
|
- width: '100%',
|
|
|
- maxWidth: 500,
|
|
|
- margin: '0 auto',
|
|
|
- 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={{ width: '100%' }}>
|
|
|
<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' }}>
|
|
|
@@ -2138,8 +2199,7 @@ export default function MyTask() {
|
|
|
) : null}
|
|
|
</div>
|
|
|
)}
|
|
|
- </div>
|
|
|
- </Card>
|
|
|
+ </div>
|
|
|
</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 ? (
|
|
|
@@ -2258,18 +2318,7 @@ export default function MyTask() {
|
|
|
background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)',
|
|
|
}}
|
|
|
>
|
|
|
- <Card
|
|
|
- style={{
|
|
|
- width: '100%',
|
|
|
- maxWidth: 500,
|
|
|
- textAlign: 'center',
|
|
|
- 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={{ width: '100%', textAlign: 'center', padding: '24px 0' }}>
|
|
|
<div style={{ marginBottom: 28 }}>
|
|
|
<span
|
|
|
style={{
|
|
|
@@ -2301,34 +2350,21 @@ export default function MyTask() {
|
|
|
<KeyOutlined />
|
|
|
<span>完成取锁、取钥匙后,任务将自动推进</span>
|
|
|
</div>
|
|
|
- </Card>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
);
|
|
|
return isolationContent;
|
|
|
}
|
|
|
|
|
|
- // 审核类型节点 (review) - 样式与盲板/拆除、确认节点统一
|
|
|
+ // 审核类型节点 (review) - 表单直接放在外层,取消内置白框
|
|
|
if (isReview) {
|
|
|
return (
|
|
|
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
|
|
<div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
|
|
|
- <Card
|
|
|
- style={{
|
|
|
- width: '100%',
|
|
|
- maxWidth: 500,
|
|
|
- margin: '0 auto',
|
|
|
- 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={{ width: '100%' }}>
|
|
|
{formLoading ? (
|
|
|
<div className="py-8 text-center text-gray-500">{t('form.formLoading')}</div>
|
|
|
- ) : formData.rule && formData.rule.length > 0 ? (
|
|
|
+ ) : hasFormIdForCurrentNode && formData.rule && formData.rule.length > 0 ? (
|
|
|
<div className="space-y-4">
|
|
|
{(() => {
|
|
|
const formConfig = formData.option?.formConfig || defaultFormConfig;
|
|
|
@@ -2366,14 +2402,13 @@ export default function MyTask() {
|
|
|
<div style={{ fontSize: 18, fontWeight: 600, color: '#1f2937', lineHeight: 1.6 }}>无需填写表单,直接点击底部按钮提交即可</div>
|
|
|
</div>
|
|
|
)}
|
|
|
- <div className="flex items-start" style={{ gap: 16, marginTop: 24, paddingTop: 24, borderTop: '1px solid rgba(22, 119, 255, 0.12)', backgroundColor: 'rgba(22, 119, 255, 0.04)', padding: '16px', borderRadius: 12, border: '1px solid rgba(22, 119, 255, 0.1)' }}>
|
|
|
+ <div className="flex items-start" style={{ gap: 16, marginTop: 24, paddingTop: 24, borderTop: '1px solid rgba(22, 119, 255, 0.12)' }}>
|
|
|
<label className="text-sm font-medium text-gray-700 whitespace-nowrap pt-2" style={{ width: defaultFormConfig.labelWidth ? `${defaultFormConfig.labelWidth - 20}px` : '80px', textAlign: defaultFormConfig.labelPosition === 'left' ? 'left' : defaultFormConfig.labelPosition === 'right' ? 'right' : 'left', flexShrink: 0 }}>{t('form.reviewComment')}</label>
|
|
|
<div className="flex-1">
|
|
|
<Input.TextArea rows={4} value={approvalComment} onChange={(e) => setApprovalComment(e.target.value)} placeholder={t('form.reviewCommentPlaceholder')} maxLength={500} showCount disabled={isApproved} readOnly={isApproved} style={{ borderRadius: 10, borderColor: '#d9e8ff' }} />
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
- </Card>
|
|
|
+ </div>
|
|
|
</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%)' }}>
|
|
|
<Button
|
|
|
@@ -2605,15 +2640,16 @@ export default function MyTask() {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- // 其他节点类型(需要根据 formId 获取表单)
|
|
|
+ // 其他节点类型(录入信息等)- 与审核节点统一样式:渐变背景、无内置白框
|
|
|
return (
|
|
|
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
|
|
|
- <div className="space-y-6" style={{ padding: '0 24px', flex: 1, overflowY: 'auto', minHeight: 0 }}>
|
|
|
- {/* 自定义表单 */}
|
|
|
+ <div style={{ flex: 1, minHeight: 0, overflow: 'auto', padding: '24px', background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)' }}>
|
|
|
+ <div style={{ width: '100%' }}>
|
|
|
+ {/* 自定义表单:仅当前节点有 formId 时渲染 */}
|
|
|
{formLoading ? (
|
|
|
<div className="py-8 text-center text-gray-500">{t('form.formLoading')}</div>
|
|
|
- ) : formData.rule && formData.rule.length > 0 ? (
|
|
|
- <div>
|
|
|
+ ) : hasFormIdForCurrentNode && formData.rule && formData.rule.length > 0 ? (
|
|
|
+ <div className="space-y-4">
|
|
|
{(() => {
|
|
|
const formConfig = formData.option?.formConfig || defaultFormConfig;
|
|
|
const layoutColumns = formConfig.layoutColumns || 1;
|
|
|
@@ -2669,18 +2705,7 @@ export default function MyTask() {
|
|
|
background: 'linear-gradient(165deg, #f0f7ff 0%, #fafbff 45%, #fff 100%)',
|
|
|
}}
|
|
|
>
|
|
|
- <Card
|
|
|
- style={{
|
|
|
- width: '100%',
|
|
|
- maxWidth: 500,
|
|
|
- textAlign: 'center',
|
|
|
- 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={{ width: '100%', textAlign: 'center', padding: '24px 0' }}>
|
|
|
<div style={{ marginBottom: 24 }}>
|
|
|
<span
|
|
|
style={{
|
|
|
@@ -2703,10 +2728,11 @@ export default function MyTask() {
|
|
|
<div style={{ marginTop: 12, fontSize: 13, color: '#69b1ff' }}>
|
|
|
确认无误后点击「完成」结束本节点
|
|
|
</div>
|
|
|
- </Card>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
)}
|
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
|
{/* 底部按钮 */}
|
|
|
<div
|