Przeglądaj źródła

修复表单标签宽度之后其他预览弹框的渲染调整 还有一些小问题修复

pm 2 miesięcy temu
rodzic
commit
8f75937efa

+ 12 - 3
src/Dashboard.tsx

@@ -93,9 +93,18 @@ export default function Dashboard() {
   const [dropdownTimer, setDropdownTimer] = useState<NodeJS.Timeout | null>(null);
   const [showProfileSettings, setShowProfileSettings] = useState(false);
   const [avatarError, setAvatarError] = useState(false);
+  const [userInfo, setUserInfo] = useState(() => getPermissionUser());
 
-  // 获取用户信息
-  const userInfo = useMemo(() => getPermissionUser(), []);
+  // 个人中心更新资料/头像后只合并变更到 state,不重读存储,避免整页抖动
+  const refreshUserInfo = useCallback((updates?: { avatar?: string; nickname?: string; email?: string }) => {
+    if (updates && Object.keys(updates).length > 0) {
+      setUserInfo((prev) => (prev ? { ...prev, ...updates } : getPermissionUser()));
+      if (updates.avatar !== undefined) setAvatarError(false);
+    } else {
+      setUserInfo(getPermissionUser());
+      setAvatarError(false);
+    }
+  }, []);
 
   // 切换语言
   const changeLanguage = (lang: 'zh' | 'en') => {
@@ -1540,7 +1549,7 @@ export default function Dashboard() {
         {/* 主内容区域 - 可滚动 */}
         <div className="flex-1 px-6 pb-6 overflow-auto">
         {showProfileSettings ? (
-          <ProfileSettings onBack={() => setShowProfileSettings(false)} />
+          <ProfileSettings onBack={() => setShowProfileSettings(false)} onProfileUpdated={refreshUserInfo} />
         ) : activeMenu === 'dashboard' ? (
           hasRole('super_admin') ? <DashboardComponent /> : <ExecutorDashboard />
         ) : activeMenu === 'systemConfig' ? (

+ 81 - 33
src/components/Dashboard.tsx

@@ -15,6 +15,7 @@ import { useNavigate } from 'react-router-dom';
 import dayjs, { Dayjs } from 'dayjs';
 import { setConfAndFields2, FormCreateData } from '../utils/formCreate';
 import { useTranslation } from 'react-i18next';
+import FormUploadField from './FormUploadField';
 
 // 辅助函数:安全地将值转换为 dayjs 对象
 const safeToDayjs = (value: any): dayjs.Dayjs | null => {
@@ -656,6 +657,18 @@ export default function Dashboard() {
       );
     }
 
+    // 与表单设计器一致:每字段 labelCol/wrapperCol,避免长标签堆叠
+    const getItemLayout = (f: any) => {
+      const isTop = formConfig.labelPosition === 'top';
+      const w = f.labelWidth ?? formConfig.labelWidth ?? 100;
+      const effective = (typeof w === 'number' && w > 0) ? w : 100;
+      return {
+        labelCol: isTop ? undefined : { flex: `${effective}px`, style: { minWidth: `${effective}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } },
+        wrapperCol: isTop ? undefined : { flex: 'auto', style: { minWidth: 0 } },
+      };
+    };
+    const itemLayout = getItemLayout(field);
+
     // 处理普通字段
     switch (field.type) {
       case 'textarea':
@@ -667,6 +680,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.TextArea 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'} 
@@ -689,6 +704,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.Password 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'}
@@ -710,6 +727,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <InputNumber 
                 style={{ width: '100%' }} 
@@ -731,6 +750,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Select
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -754,6 +775,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 if (!value) return undefined;
                 if (value && typeof value === 'object' && 'valueOf' in value && typeof value.valueOf === 'function' && 'isValid' in value && typeof value.isValid === 'function') {
@@ -804,6 +827,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期范围' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 if (!value || !Array.isArray(value) || value.length !== 2) return undefined;
                 const [start, end] = value;
@@ -881,6 +906,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 if (!value) return undefined;
                 if (value && typeof value === 'object' && 'valueOf' in value) {
@@ -931,6 +958,8 @@ export default function Dashboard() {
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
               valuePropName="checked"
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Switch disabled={field.disabled} />
             </AntdForm.Item>
@@ -945,6 +974,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Radio.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -963,6 +994,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Checkbox.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -981,6 +1014,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Cascader
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -1002,23 +1037,15 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请上传' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
-              <Upload
+              <FormUploadField
+                uploadType={field.uploadType}
+                maxCount={field.maxCount}
+                accept={field.accept}
                 disabled={field.disabled}
-                maxCount={field.uploadType === 'single-image' ? 1 : field.maxCount || (field.uploadType === 'multiple-image' ? 9 : undefined)}
-                accept={field.accept || (field.uploadType === 'single-image' || field.uploadType === 'multiple-image' ? 'image/*' : undefined)}
-                listType={(field.uploadType === 'file' ? 'text' : 'picture-card') as 'text' | 'picture-card' | 'picture'}
-                multiple={field.uploadType !== 'single-image'}
-              >
-                {field.uploadType === 'file' ? (
-                  <Button icon={<UploadOutlined />}>上传文件</Button>
-                ) : (
-                  <div>
-                    <UploadOutlined />
-                    <div style={{ marginTop: 8 }}>上传</div>
-                  </div>
-                )}
-              </Upload>
+              />
             </AntdForm.Item>
           </div>
         );
@@ -1032,6 +1059,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <DatePicker 
                 style={{ width: '100%' }} 
@@ -1058,6 +1087,8 @@ export default function Dashboard() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -1080,6 +1111,8 @@ export default function Dashboard() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -1102,6 +1135,8 @@ export default function Dashboard() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -1125,6 +1160,8 @@ export default function Dashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input 
                 type={field.inputType || 'text'}
@@ -2606,15 +2643,21 @@ export default function Dashboard() {
                                           layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                           size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                           requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                          labelCol={formConfig.labelWidth ? {
-                                            style: {
-                                              width: `${formConfig.labelWidth}px`,
-                                              textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                            }
-                                          } : undefined}
+                                          labelCol={
+                                            formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                              ? undefined
+                                              : {
+                                                  flex: `${formConfig.labelWidth}px`,
+                                                  style: {
+                                                    minWidth: `${formConfig.labelWidth}px`,
+                                                    textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                                  },
+                                                }
+                                          }
+                                          wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                                         >
                                           <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                             {(formData.rule || []).map((field: any) => {
                                               const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                               return renderFieldPreview(fieldWithDisabled);
@@ -2755,9 +2798,9 @@ export default function Dashboard() {
                                   const layoutColumns = formConfig.layoutColumns || 1;
                                   const gridStyle = layoutColumns > 1 ? { display: 'grid', gridTemplateColumns: `repeat(${layoutColumns}, minmax(0, 1fr))`, gap: '12px', rowGap: '16px' } : undefined;
                                   return (
-                                    <AntdForm form={taskDetailForm} layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'} size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize} requiredMark={formConfig.hideRequiredMark ? false : undefined} labelCol={formConfig.labelWidth ? { style: { width: `${formConfig.labelWidth}px`, textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left' } } : undefined}>
+                                    <AntdForm form={taskDetailForm} layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'} size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize} requiredMark={formConfig.hideRequiredMark ? false : undefined} labelCol={formConfig.labelPosition === 'top' || !formConfig.labelWidth ? undefined : { flex: `${formConfig.labelWidth}px`, style: { minWidth: `${formConfig.labelWidth}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } }} wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}>
                                       <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                         {(formData.rule || []).map((field: any) => {
                                           const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                           return renderFieldPreview(fieldWithDisabled);
@@ -2959,21 +3002,26 @@ export default function Dashboard() {
                                 layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                 size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                 requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                labelCol={formConfig.labelWidth ? { 
-                                  style: { 
-                                    width: `${formConfig.labelWidth}px`,
-                                    textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                  } 
-                                } : undefined}
+                                labelCol={
+                                  formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                    ? undefined
+                                    : {
+                                        flex: `${formConfig.labelWidth}px`,
+                                        style: {
+                                          minWidth: `${formConfig.labelWidth}px`,
+                                          textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                        },
+                                      }
+                                }
+                                wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                               >
                                 <div 
                                   style={gridStyle} 
                                   className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}
                                 >
                                   <style>{`
-                                    .form-detail-grid .ant-form-item {
-                                      margin-bottom: 12px;
-                                    }
+                                    .form-detail-grid .ant-form-item { margin-bottom: 12px; }
+                                    .form-detail-grid .ant-form-item-control { min-width: 0; }
                                   `}</style>
                                   {(formData.rule || []).map((field: any) => {
                                     const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;

+ 81 - 33
src/components/ExecutorDashboard.tsx

@@ -12,6 +12,7 @@ import { useNavigate } from 'react-router-dom';
 import { useTranslation } from 'react-i18next';
 import dayjs, { Dayjs } from 'dayjs';
 import { setConfAndFields2, FormCreateData } from '../utils/formCreate';
+import FormUploadField from './FormUploadField';
 import { dictDataApi, DictDataVO } from '../api/DictData';
 // @ts-ignore
 import urgecy1Icon from '../assets/urgecy1.png';
@@ -492,6 +493,18 @@ export default function ExecutorDashboard() {
       );
     }
 
+    // 与表单设计器一致:每字段 labelCol/wrapperCol
+    const getItemLayout = (f: any) => {
+      const isTop = formConfig.labelPosition === 'top';
+      const w = f.labelWidth ?? formConfig.labelWidth ?? 100;
+      const effective = (typeof w === 'number' && w > 0) ? w : 100;
+      return {
+        labelCol: isTop ? undefined : { flex: `${effective}px`, style: { minWidth: `${effective}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } },
+        wrapperCol: isTop ? undefined : { flex: 'auto', style: { minWidth: 0 } },
+      };
+    };
+    const itemLayout = getItemLayout(field);
+
     // 处理普通字段
     switch (field.type) {
       case 'textarea':
@@ -503,6 +516,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.TextArea 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'} 
@@ -525,6 +540,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.Password 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'}
@@ -546,6 +563,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <InputNumber 
                 style={{ width: '100%' }} 
@@ -567,6 +586,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Select
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -590,6 +611,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 if (!value) return undefined;
                 if (value && typeof value === 'object' && 'valueOf' in value && typeof value.valueOf === 'function' && 'isValid' in value && typeof value.isValid === 'function') {
@@ -640,6 +663,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期范围' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 if (!value || !Array.isArray(value) || value.length !== 2) return undefined;
                 const [start, end] = value;
@@ -717,6 +742,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 if (!value) return undefined;
                 if (value && typeof value === 'object' && 'valueOf' in value) {
@@ -767,6 +794,8 @@ export default function ExecutorDashboard() {
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
               valuePropName="checked"
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Switch disabled={field.disabled} />
             </AntdForm.Item>
@@ -781,6 +810,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Radio.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -799,6 +830,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Checkbox.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -817,6 +850,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Cascader
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -838,23 +873,15 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请上传' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
-              <Upload
+              <FormUploadField
+                uploadType={field.uploadType}
+                maxCount={field.maxCount}
+                accept={field.accept}
                 disabled={field.disabled}
-                maxCount={field.uploadType === 'single-image' ? 1 : field.maxCount || (field.uploadType === 'multiple-image' ? 9 : undefined)}
-                accept={field.accept || (field.uploadType === 'single-image' || field.uploadType === 'multiple-image' ? 'image/*' : undefined)}
-                listType={(field.uploadType === 'file' ? 'text' : 'picture-card') as 'text' | 'picture-card' | 'picture'}
-                multiple={field.uploadType !== 'single-image'}
-              >
-                {field.uploadType === 'file' ? (
-                  <Button icon={<UploadOutlined />}>上传文件</Button>
-                ) : (
-                  <div>
-                    <UploadOutlined />
-                    <div style={{ marginTop: 8 }}>上传</div>
-                  </div>
-                )}
-              </Upload>
+              />
             </AntdForm.Item>
           </div>
         );
@@ -868,6 +895,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <DatePicker 
                 style={{ width: '100%' }} 
@@ -894,6 +923,8 @@ export default function ExecutorDashboard() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -916,6 +947,8 @@ export default function ExecutorDashboard() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -938,6 +971,8 @@ export default function ExecutorDashboard() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -961,6 +996,8 @@ export default function ExecutorDashboard() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input 
                 type={field.inputType || 'text'}
@@ -1937,15 +1974,21 @@ export default function ExecutorDashboard() {
                                           layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                           size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                           requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                          labelCol={formConfig.labelWidth ? {
-                                            style: {
-                                              width: `${formConfig.labelWidth}px`,
-                                              textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                            }
-                                          } : undefined}
+                                          labelCol={
+                                            formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                              ? undefined
+                                              : {
+                                                  flex: `${formConfig.labelWidth}px`,
+                                                  style: {
+                                                    minWidth: `${formConfig.labelWidth}px`,
+                                                    textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                                  },
+                                                }
+                                          }
+                                          wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                                         >
                                           <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                             {(formData.rule || []).map((field: any) => {
                                               const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                               return renderFieldPreview(fieldWithDisabled);
@@ -2086,9 +2129,9 @@ export default function ExecutorDashboard() {
                                   const layoutColumns = formConfig.layoutColumns || 1;
                                   const gridStyle = layoutColumns > 1 ? { display: 'grid', gridTemplateColumns: `repeat(${layoutColumns}, minmax(0, 1fr))`, gap: '12px', rowGap: '16px' } : undefined;
                                   return (
-                                    <AntdForm form={taskDetailForm} layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'} size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize} requiredMark={formConfig.hideRequiredMark ? false : undefined} labelCol={formConfig.labelWidth ? { style: { width: `${formConfig.labelWidth}px`, textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left' } } : undefined}>
+                                    <AntdForm form={taskDetailForm} layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'} size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize} requiredMark={formConfig.hideRequiredMark ? false : undefined} labelCol={formConfig.labelPosition === 'top' || !formConfig.labelWidth ? undefined : { flex: `${formConfig.labelWidth}px`, style: { minWidth: `${formConfig.labelWidth}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } }} wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}>
                                       <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                         {(formData.rule || []).map((field: any) => {
                                           const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                           return renderFieldPreview(fieldWithDisabled);
@@ -2298,21 +2341,26 @@ export default function ExecutorDashboard() {
                                 layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                 size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                 requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                labelCol={formConfig.labelWidth ? { 
-                                  style: { 
-                                    width: `${formConfig.labelWidth}px`,
-                                    textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                  } 
-                                } : undefined}
+                                labelCol={
+                                  formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                    ? undefined
+                                    : {
+                                        flex: `${formConfig.labelWidth}px`,
+                                        style: {
+                                          minWidth: `${formConfig.labelWidth}px`,
+                                          textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                        },
+                                      }
+                                }
+                                wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                               >
                                 <div 
                                   style={gridStyle} 
                                   className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}
                                 >
                                   <style>{`
-                                    .form-detail-grid .ant-form-item {
-                                      margin-bottom: 12px;
-                                    }
+                                    .form-detail-grid .ant-form-item { margin-bottom: 12px; }
+                                    .form-detail-grid .ant-form-item-control { min-width: 0; }
                                   `}</style>
                                   {(formData.rule || []).map((field: any) => {
                                     const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;

+ 55 - 27
src/components/FormDesigner.tsx

@@ -67,6 +67,7 @@ import { toast } from 'sonner';
 import * as FormApi from '../api/bpm/form';
 import { DICT_TYPE, getIntDictOptions, setDictOptions, DictDataType } from '../utils/dict';
 import { dictDataApi } from '../api/DictData';
+import FormUploadField from './FormUploadField';
 
 const { TextArea } = Input;
 const { Panel } = Collapse;
@@ -235,7 +236,8 @@ const componentLibrary: Record<string, ComponentItem[]> = {
   '布局组件': [
     { type: 'card', label: '卡片容器', icon: Layout },
     { type: 'grid', label: '双栏布局', icon: Grid, layoutColumns: 2 },
-    { type: 'grid', label: '三栏布局', icon: Grid, layoutColumns: 3 },
+    // 三栏布局暂时隐藏
+    // { type: 'grid', label: '三栏布局', icon: Grid, layoutColumns: 3 },
     { type: 'tabs', label: '选项卡', icon: FileText },
   ],
 };
@@ -2300,24 +2302,13 @@ export default function FormDesigner() {
             />
           );
         case 'upload':
-          const uploadProps = {
-            disabled: field.disabled,
-            maxCount: field.uploadType === 'single-image' ? 1 : field.maxCount || (field.uploadType === 'multiple-image' ? 9 : undefined),
-            accept: field.accept || (field.uploadType === 'single-image' || field.uploadType === 'multiple-image' ? 'image/*' : undefined),
-            listType: (field.uploadType === 'file' ? 'text' : 'picture-card') as 'text' | 'picture-card' | 'picture',
-            multiple: field.uploadType !== 'single-image',
-          };
           return (
-            <Upload {...uploadProps}>
-              {field.uploadType === 'file' ? (
-                <Button icon={<UploadOutlined />}>上传文件</Button>
-              ) : (
-                <div>
-                  <UploadOutlined />
-                  <div style={{ marginTop: 8 }}>上传</div>
-                </div>
-              )}
-            </Upload>
+            <FormUploadField
+              uploadType={field.uploadType}
+              maxCount={field.maxCount}
+              accept={field.accept}
+              disabled={field.disabled}
+            />
           );
         case 'alert':
           const themeClass =
@@ -2447,12 +2438,29 @@ export default function FormDesigner() {
       }
     });
 
+    // 预览与设计器一致:每个字段使用 field.labelWidth ?? formConfig.labelWidth ?? 100,保证长标签不堆叠
+    const rawLabelWidth = field.labelWidth ?? formConfig?.labelWidth ?? 100;
+    const effectiveLabelWidth = (typeof rawLabelWidth === 'number' && rawLabelWidth > 0) ? rawLabelWidth : 100;
+    const isTopLabel = formConfig?.labelPosition === 'top';
+    const previewLabelCol = isTopLabel
+      ? undefined
+      : {
+          flex: `${effectiveLabelWidth}px`,
+          style: {
+            minWidth: `${effectiveLabelWidth}px`,
+            textAlign: formConfig?.labelPosition === 'right' ? 'right' : 'left',
+          },
+        };
+    const previewWrapperCol = isTopLabel ? undefined : { flex: 'auto', style: { minWidth: 0 } };
+
     return (
       <AntdForm.Item
         label={field.label + (formConfig?.labelSuffix || '')}
         required={field.required && !formConfig?.hideRequiredMark}
         rules={rules}
         name={field.id}
+        labelCol={previewLabelCol}
+        wrapperCol={previewWrapperCol}
       >
         {renderFieldComponent()}
         {field.hint && (
@@ -2817,7 +2825,8 @@ export default function FormDesigner() {
                   >
                     <Radio value={1}>单栏</Radio>
                     <Radio value={2}>双栏</Radio>
-                    <Radio value={3}>三栏</Radio>
+                    {/* 三栏选项暂时隐藏 */}
+                    {/* <Radio value={3}>三栏</Radio> */}
                   </Radio.Group>
                 </div>
                 <div className="flex items-center justify-between">
@@ -3595,7 +3604,7 @@ export default function FormDesigner() {
           </div>
         </div>
 
-        {/* 预览弹窗 */}
+        {/* 预览弹窗:宽度与表单管理预览弹框一致 */}
         <Modal
           title="表单预览"
           open={previewVisible}
@@ -3633,7 +3642,7 @@ export default function FormDesigner() {
               </div>
             </div>
           ]}
-          width={800}
+          width={960}
         >
           <div className="p-2">
             {(() => {
@@ -3651,12 +3660,25 @@ export default function FormDesigner() {
                   layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                   size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                   requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                  labelCol={formConfig.labelWidth ? { 
-                    style: { 
-                      width: `${formConfig.labelWidth}px`,
-                      textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                    } 
-                  } : undefined}
+                  labelCol={
+                    formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                      ? undefined
+                      : {
+                          flex: `${formConfig.labelWidth}px`,
+                          style: {
+                            minWidth: `${formConfig.labelWidth}px`,
+                            textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                          },
+                        }
+                  }
+                  wrapperCol={
+                    formConfig.labelPosition === 'top'
+                      ? undefined
+                      : {
+                          flex: 'auto',
+                          style: { minWidth: 0 },
+                        }
+                  }
                 >
                   <div 
                     style={gridStyle} 
@@ -3666,6 +3688,12 @@ export default function FormDesigner() {
                       .form-preview-grid .ant-form-item {
                         margin-bottom: 12px;
                       }
+                      .form-preview-grid .ant-form-item-control {
+                        min-width: 0;
+                      }
+                      .form-preview-grid .ant-form-item-control-input-content {
+                        min-width: 0;
+                      }
                     `}</style>
                     {fields.map((field) => {
                       const spanStyle: React.CSSProperties | undefined = previewLayoutColumns > 1 

+ 92 - 55
src/components/FormManagement.tsx

@@ -10,6 +10,7 @@ import { DICT_TYPE, getDictLabel } from '../utils/dict';
 import { dateFormatter } from '../utils/formatTime';
 import { setConfAndFields2, FormCreateData } from '../utils/formCreate';
 import { useTranslation } from 'react-i18next';
+import FormUploadField from './FormUploadField';
 
 export default function FormManagement() {
   const { t } = useTranslation();
@@ -45,6 +46,7 @@ export default function FormManagement() {
     formSize: 'middle',
     labelSuffix: '',
     labelWidth: 100,
+    layoutColumns: 1 as 1 | 2 | 3,
     hideRequiredMark: false,
     showValidationError: true,
     inlineValidation: false,
@@ -52,11 +54,18 @@ export default function FormManagement() {
     showResetButton: false,
   };
 
+  // 合并表单配置:兼容 option.formConfig 或 option 即 formConfig 两种后端结构
+  const getMergedFormConfig = () => ({
+    ...defaultFormConfig,
+    ...(detailData.option?.formConfig || detailData.option || {}),
+  });
+
   // 渲染字段预览(支持嵌套结构)
   const renderFieldPreview = (field: any, parentSpanStyle?: React.CSSProperties): React.ReactNode => {
-    const formConfig = detailData.option?.formConfig || defaultFormConfig;
+    const formConfig = getMergedFormConfig();
     const layoutColumns = formConfig.layoutColumns || 1;
     const spanStyle = parentSpanStyle || (layoutColumns > 1 ? { gridColumn: `span ${Math.min(layoutColumns, field.span || 1)}` } : undefined);
+    const wrapperStyle: React.CSSProperties = spanStyle || {};
 
     // 处理容器类型(card 和 grid)
     if (field.type === 'card') {
@@ -126,17 +135,31 @@ export default function FormManagement() {
       );
     }
 
+    // 与表单设计器一致:每字段 labelCol/wrapperCol
+    const getItemLayout = (f: any) => {
+      const isTop = formConfig.labelPosition === 'top';
+      const w = f.labelWidth ?? formConfig.labelWidth ?? 100;
+      const effective = (typeof w === 'number' && w > 0) ? w : 100;
+      return {
+        labelCol: isTop ? undefined : { flex: `${effective}px`, style: { minWidth: `${effective}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } },
+        wrapperCol: isTop ? undefined : { flex: 'auto', style: { minWidth: 0 } },
+      };
+    };
+    const itemLayout = getItemLayout(field);
+
     // 处理普通字段
     switch (field.type) {
       case 'textarea':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseInput') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.TextArea 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : t('common.pleaseInput')} 
@@ -152,13 +175,15 @@ export default function FormManagement() {
         );
       case 'password':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseInput') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.Password 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : t('common.pleaseInput')}
@@ -173,13 +198,15 @@ export default function FormManagement() {
         );
       case 'number':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseInput') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <InputNumber 
                 style={{ width: '100%' }} 
@@ -194,13 +221,15 @@ export default function FormManagement() {
         );
       case 'select':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelect') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Select
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : t('common.pleaseSelect')}
@@ -217,13 +246,15 @@ export default function FormManagement() {
         );
       case 'date':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelectDate') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <DatePicker 
                 className="w-full" 
@@ -237,13 +268,15 @@ export default function FormManagement() {
         );
       case 'daterange':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelectDateRange') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <DatePicker.RangePicker 
                 className="w-full" 
@@ -257,13 +290,15 @@ export default function FormManagement() {
         );
       case 'datetime':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelectDateTime') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <DatePicker 
                 className="w-full" 
@@ -279,13 +314,15 @@ export default function FormManagement() {
         );
       case 'timepicker':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelectTime') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <TimePicker 
                 className="w-full" 
@@ -300,7 +337,7 @@ export default function FormManagement() {
         );
       case 'switch':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
@@ -308,6 +345,8 @@ export default function FormManagement() {
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelect') }] : []}
               help={field.hint}
               valuePropName="checked"
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Switch disabled={field.disabled} />
             </AntdForm.Item>
@@ -315,13 +354,15 @@ export default function FormManagement() {
         );
       case 'radio':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelect') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Radio.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -333,13 +374,15 @@ export default function FormManagement() {
         );
       case 'checkbox':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelect') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Checkbox.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -351,13 +394,15 @@ export default function FormManagement() {
         );
       case 'cascader':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseSelect') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Cascader
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : t('common.pleaseSelect')}
@@ -372,42 +417,36 @@ export default function FormManagement() {
         );
       case 'upload':
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.upload') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
-              <Upload
+              <FormUploadField
+                uploadType={field.uploadType}
+                maxCount={field.maxCount}
+                accept={field.accept}
                 disabled={field.disabled}
-                maxCount={field.uploadType === 'single-image' ? 1 : field.maxCount || (field.uploadType === 'multiple-image' ? 9 : undefined)}
-                accept={field.accept || (field.uploadType === 'single-image' || field.uploadType === 'multiple-image' ? 'image/*' : undefined)}
-                listType={(field.uploadType === 'file' ? 'text' : 'picture-card') as 'text' | 'picture-card' | 'picture'}
-                multiple={field.uploadType !== 'single-image'}
-              >
-                {field.uploadType === 'file' ? (
-                  <Button icon={<UploadOutlined />}>{t('common.uploadFile')}</Button>
-                ) : (
-                  <div>
-                    <UploadOutlined />
-                    <div style={{ marginTop: 8 }}>{t('common.upload')}</div>
-                  </div>
-                )}
-              </Upload>
+              />
             </AntdForm.Item>
           </div>
         );
       default:
         return (
-          <div key={field.id} style={spanStyle}>
+          <div key={field.id} style={wrapperStyle}>
             <AntdForm.Item
               label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
               name={field.name || field.field}
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || t('common.pleaseInput') }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input 
                 type={field.inputType || 'text'}
@@ -833,11 +872,11 @@ export default function FormManagement() {
             </Button>
           </div>,
         ]}
-        width={800}
+        width={960}
       >
         <div className="p-2">
           {(() => {
-            const formConfig = detailData.option?.formConfig || defaultFormConfig;
+            const formConfig = getMergedFormConfig();
             const layoutColumns = formConfig.layoutColumns || 1;
             const gridStyle = layoutColumns > 1 ? {
               display: 'grid',
@@ -846,31 +885,29 @@ export default function FormManagement() {
               rowGap: '16px',
             } : undefined;
 
+            const isHorizontal = formConfig.labelPosition !== 'top';
+            const effectiveLabelWidth = Math.max(0, Number(formConfig.labelWidth) || defaultFormConfig.labelWidth);
             return (
-              <AntdForm
-                form={detailForm}
-                layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
-                size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
-                requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                labelCol={formConfig.labelWidth ? { 
-                  style: { 
-                    width: `${formConfig.labelWidth}px`,
-                    textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                  } 
-                } : undefined}
-              >
-                <div 
-                  style={gridStyle} 
-                  className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}
+              <>
+                <style>{`
+                  .form-preview-grid .ant-form-item { margin-bottom: 12px; }
+                  .form-preview-grid .ant-form-item-control { min-width: 0; }
+                `}</style>
+                <AntdForm
+                  form={detailForm}
+                  layout={formConfig.labelPosition === 'top' ? 'vertical' : 'horizontal'}
+                  size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
+                  requiredMark={formConfig.hideRequiredMark ? false : undefined}
+                  wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                 >
-                  <style>{`
-                    .form-detail-grid .ant-form-item {
-                      margin-bottom: 12px;
-                    }
-                  `}</style>
-                  {(detailData.rule || []).map((field: any) => renderFieldPreview(field))}
-                </div>
-              </AntdForm>
+                  <div 
+                    style={gridStyle} 
+                    className={layoutColumns === 1 ? 'space-y-4' : 'form-preview-grid'}
+                  >
+                    {(detailData.rule || []).map((field: any) => renderFieldPreview(field))}
+                  </div>
+                </AntdForm>
+              </>
             );
           })()}
         </div>

+ 99 - 0
src/components/FormUploadField.tsx

@@ -0,0 +1,99 @@
+import React, { useState, useEffect } from 'react';
+import { Upload, Button } from 'antd';
+import { UploadOutlined } from '@ant-design/icons';
+import type { UploadFile } from 'antd/es/upload/interface';
+import { fileApi } from '../api/file';
+
+// 上传接口由 fileApi.upload 固定使用 /admin-api/infra/file/upload(axios baseURL + /infra/file/upload)
+
+function toFileList(value: string | string[] | undefined): UploadFile[] {
+  if (value == null || value === '') return [];
+  const urls = Array.isArray(value) ? value : [value];
+  return urls.filter(Boolean).map((url, i) => ({
+    uid: `-${i}-${url}`,
+    name: url.split('/').pop() || `文件${i + 1}`,
+    status: 'done' as const,
+    url: url,
+  }));
+}
+
+function extractUrls(fileList: UploadFile[]): string[] {
+  return fileList
+    .map((f) => (f.response as string) ?? f.url)
+    .filter(Boolean) as string[];
+}
+
+export interface FormUploadFieldProps {
+  value?: string | string[];
+  onChange?: (value: string | string[]) => void;
+  disabled?: boolean;
+  uploadType?: 'single-image' | 'multiple-image' | 'file';
+  maxCount?: number;
+  accept?: string;
+}
+
+/**
+ * 自定义表单上传组件:内部固定使用 /admin-api/infra/file/upload,支持图片/文件上传与回显。
+ */
+export default function FormUploadField({
+  value,
+  onChange,
+  disabled = false,
+  uploadType = 'multiple-image',
+  maxCount,
+  accept,
+}: FormUploadFieldProps) {
+  const [fileList, setFileList] = useState<UploadFile[]>(() => toFileList(value));
+
+  useEffect(() => {
+    setFileList((prev) => {
+      const fromValue = toFileList(value);
+      const pending = prev.filter((f) => f.status === 'uploading');
+      if (pending.length === 0) return fromValue;
+      return [...fromValue, ...pending];
+    });
+  }, [value]);
+
+  const isSingleImage = uploadType === 'single-image';
+  const limit = maxCount ?? (isSingleImage ? 1 : uploadType === 'multiple-image' ? 9 : undefined);
+  const acceptAttr = accept ?? (uploadType === 'file' ? undefined : 'image/*');
+  const listType = uploadType === 'file' ? 'text' : 'picture-card';
+
+  return (
+    <Upload
+      disabled={disabled}
+      listType={listType as 'text' | 'picture-card' | 'picture'}
+      fileList={fileList}
+      maxCount={limit}
+      accept={acceptAttr}
+      multiple={!isSingleImage}
+      customRequest={async ({ file, onSuccess, onError }) => {
+        try {
+          const url = await fileApi.upload(file as File);
+          onSuccess?.(url);
+        } catch (e: any) {
+          onError?.(e);
+        }
+      }}
+      onChange={({ fileList: nextList }) => {
+        const list = nextList.map((f) => {
+          if (f.response && !f.url) return { ...f, url: f.response as string };
+          return f;
+        });
+        setFileList(list);
+        const urls = extractUrls(list);
+        const out = isSingleImage ? (urls[0] ?? '') : urls;
+        onChange?.(out);
+      }}
+    >
+      {uploadType === 'file' ? (
+        <Button icon={<UploadOutlined />}>上传文件</Button>
+      ) : (
+        <div>
+          <UploadOutlined />
+          <div style={{ marginTop: 8 }}>上传</div>
+        </div>
+      )}
+    </Upload>
+  );
+}

+ 80 - 33
src/components/MyTask.tsx

@@ -15,6 +15,7 @@ import urgecy1Icon from '../assets/urgecy1.png';
 import urgecy2Icon from '../assets/urgecy2.png';
 import urgecy3Icon from '../assets/urgecy3.png';
 import { useTranslation } from 'react-i18next';
+import FormUploadField from './FormUploadField';
 
 // 辅助函数:安全地将值转换为 dayjs 对象
 const safeToDayjs = (value: any): dayjs.Dayjs | null => {
@@ -439,6 +440,18 @@ export default function MyTask() {
       );
     }
 
+    // 与表单设计器一致:每字段 labelCol/wrapperCol
+    const getItemLayout = (f: any) => {
+      const isTop = formConfig.labelPosition === 'top';
+      const w = f.labelWidth ?? formConfig.labelWidth ?? 100;
+      const effective = (typeof w === 'number' && w > 0) ? w : 100;
+      return {
+        labelCol: isTop ? undefined : { flex: `${effective}px`, style: { minWidth: `${effective}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } },
+        wrapperCol: isTop ? undefined : { flex: 'auto', style: { minWidth: 0 } },
+      };
+    };
+    const itemLayout = getItemLayout(field);
+
     // 处理普通字段
     switch (field.type) {
       case 'textarea':
@@ -450,6 +463,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.TextArea 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'} 
@@ -472,6 +487,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.Password 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'}
@@ -493,6 +510,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <InputNumber 
                 style={{ width: '100%' }} 
@@ -514,6 +533,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Select
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -537,6 +558,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 // 选择日期时,将 dayjs 对象转换为毫秒级时间戳
                 if (!value) return undefined;
@@ -590,6 +613,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期范围' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 // 选择日期范围时,将 dayjs 对象数组转换为毫秒级时间戳数组
                 if (!value || !Array.isArray(value) || value.length !== 2) return undefined;
@@ -670,6 +695,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 // 选择日期时间时,将 dayjs 对象转换为毫秒级时间戳
                 if (!value) return undefined;
@@ -722,6 +749,8 @@ export default function MyTask() {
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
               valuePropName="checked"
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Switch disabled={field.disabled} />
             </AntdForm.Item>
@@ -736,6 +765,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Radio.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -754,6 +785,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Checkbox.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -772,6 +805,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Cascader
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -793,23 +828,15 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请上传' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
-              <Upload
+              <FormUploadField
+                uploadType={field.uploadType}
+                maxCount={field.maxCount}
+                accept={field.accept}
                 disabled={field.disabled}
-                maxCount={field.uploadType === 'single-image' ? 1 : field.maxCount || (field.uploadType === 'multiple-image' ? 9 : undefined)}
-                accept={field.accept || (field.uploadType === 'single-image' || field.uploadType === 'multiple-image' ? 'image/*' : undefined)}
-                listType={(field.uploadType === 'file' ? 'text' : 'picture-card') as 'text' | 'picture-card' | 'picture'}
-                multiple={field.uploadType !== 'single-image'}
-              >
-                {field.uploadType === 'file' ? (
-                  <Button icon={<UploadOutlined />}>上传文件</Button>
-                ) : (
-                  <div>
-                    <UploadOutlined />
-                    <div style={{ marginTop: 8 }}>上传</div>
-                  </div>
-                )}
-              </Upload>
+              />
             </AntdForm.Item>
           </div>
         );
@@ -850,6 +877,8 @@ export default function MyTask() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -872,6 +901,8 @@ export default function MyTask() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -895,6 +926,8 @@ export default function MyTask() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -918,6 +951,8 @@ export default function MyTask() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input 
                 type={field.inputType || 'text'}
@@ -2179,15 +2214,21 @@ export default function MyTask() {
                                           layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                           size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                           requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                          labelCol={formConfig.labelWidth ? {
-                                            style: {
-                                              width: `${formConfig.labelWidth}px`,
-                                              textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                            }
-                                          } : undefined}
+                                          labelCol={
+                                            formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                              ? undefined
+                                              : {
+                                                  flex: `${formConfig.labelWidth}px`,
+                                                  style: {
+                                                    minWidth: `${formConfig.labelWidth}px`,
+                                                    textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                                  },
+                                                }
+                                          }
+                                          wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                                         >
                                           <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                             {(formData.rule || []).map((field: any) => {
                                               const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                               return renderFieldPreview(fieldWithDisabled);
@@ -2381,10 +2422,11 @@ export default function MyTask() {
                                       layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                       size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                       requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                      labelCol={formConfig.labelWidth ? { style: { width: `${formConfig.labelWidth}px`, textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left' } } : undefined}
+                                      labelCol={formConfig.labelPosition === 'top' || !formConfig.labelWidth ? undefined : { flex: `${formConfig.labelWidth}px`, style: { minWidth: `${formConfig.labelWidth}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } }}
+                                      wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                                     >
                                       <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                         {(formData.rule || []).map((field: any) => {
                                           const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                           return renderFieldPreview(fieldWithDisabled);
@@ -2666,21 +2708,26 @@ export default function MyTask() {
                               layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                               size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                               requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                              labelCol={formConfig.labelWidth ? { 
-                                style: { 
-                                  width: `${formConfig.labelWidth}px`,
-                                  textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                } 
-                              } : undefined}
+                              labelCol={
+                                formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                  ? undefined
+                                  : {
+                                      flex: `${formConfig.labelWidth}px`,
+                                      style: {
+                                        minWidth: `${formConfig.labelWidth}px`,
+                                        textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                      },
+                                    }
+                              }
+                              wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                             >
                               <div 
                                 style={gridStyle} 
                                 className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}
                               >
                                 <style>{`
-                                  .form-detail-grid .ant-form-item {
-                                    margin-bottom: 12px;
-                                  }
+                                  .form-detail-grid .ant-form-item { margin-bottom: 12px; }
+                                    .form-detail-grid .ant-form-item-control { min-width: 0; }
                                 `}</style>
                                 {(formData.rule || []).map((field: any) => {
                                   // 如果已通过,禁用所有字段

+ 101 - 72
src/components/ProcessDesigner.tsx

@@ -146,6 +146,7 @@ import { segregationPointApi, SegregationPointVO } from '../api/spm';
 import { getFormPage, getForm, FormVO } from '../api/bpm/form';
 import { setConfAndFields2, FormCreateData } from '../utils/formCreate';
 import { dictDataApi, DictDataVO } from '../api/DictData';
+import FormUploadField from './FormUploadField';
 
 // 节点配置
 const nodeConfigs = [
@@ -3643,38 +3644,33 @@ export default function ProcessDesigner() {
                                     allowClear
                                   >
                                     {(() => {
-                                      // 找到所有与当前"解除隔离"节点连线的"隔离/方案"节点
-                                      // 连线方向:隔离节点(source) -> 解除隔离节点(target)
+                                      // 从当前「解除隔离」节点向前(沿连线反向)查找所有上游节点,再从中筛出「隔离/方案」节点
+                                      // 这样即使中间隔了多个节点(如 隔离 -> A -> B -> 解除隔离),下拉也能出现对应隔离节点
                                       const currentNodeId = selectedNode?.id;
-                                      
-                                      // 找到所有以当前节点为 target 的 edge(隔离节点指向解除隔离节点)
-                                      const incomingEdges = edges.filter(edge => 
-                                        String(edge.target) === String(currentNodeId)
-                                      );
-                                      
-                                      // 也检查反向连线(解除隔离节点指向隔离节点,虽然不常见但兼容)
-                                      const outgoingEdges = edges.filter(edge => 
-                                        String(edge.source) === String(currentNodeId)
-                                      );
-                                      
-                                      // 收集所有已连线的隔离节点ID
-                                      const connectedIsolationNodeIds = new Set<string>();
-                                      incomingEdges.forEach(edge => {
-                                        connectedIsolationNodeIds.add(String(edge.source));
-                                      });
-                                      outgoingEdges.forEach(edge => {
-                                        connectedIsolationNodeIds.add(String(edge.target));
-                                      });
-                                      
-                                      // 获取所有隔离节点
+                                      if (!currentNodeId) return [];
+
+                                      let queue = [String(currentNodeId)];
+                                      const upstreamIds = new Set<string>();
+
+                                      while (queue.length > 0) {
+                                        const nextQueue: string[] = [];
+                                        for (const id of queue) {
+                                          edges.forEach(edge => {
+                                            if (String(edge.target) !== id) return;
+                                            const src = String(edge.source);
+                                            if (upstreamIds.has(src)) return;
+                                            upstreamIds.add(src);
+                                            nextQueue.push(src);
+                                          });
+                                        }
+                                        queue = nextQueue;
+                                      }
+
                                       const isolationNodes = nodes.filter(n => n.data?.type === 'isolation');
-                                      
-                                      // 如果有连线,只显示已连线的隔离节点;否则显示所有隔离节点(兼容旧数据)
-                                      const nodesToShow = connectedIsolationNodeIds.size > 0
-                                        ? isolationNodes.filter(n => connectedIsolationNodeIds.has(String(n.id)))
-                                        : isolationNodes;
-                                      
-                                      return nodesToShow.map(node => (
+                                      const nodesToShow = isolationNodes.filter(n => upstreamIds.has(String(n.id)));
+                                      const nodesToShowFinal = nodesToShow.length > 0 ? nodesToShow : isolationNodes;
+
+                                      return nodesToShowFinal.map(node => (
                                         <Select.Option key={node.id} value={node.id}>
                                           {node.data?.label || nodeConfigs.find(c => c.type === 'isolation')?.label || '隔离/方案'}
                                         </Select.Option>
@@ -4080,7 +4076,7 @@ export default function ProcessDesigner() {
             关闭
           </Button>
         ]}
-        width={800}
+        width={960}
         style={{ top: 20 }}
         styles={{ body: { maxHeight: 'calc(90vh - 120px)', overflowY: 'auto', overflowX: 'hidden' } }}
       >
@@ -4088,10 +4084,28 @@ export default function ProcessDesigner() {
           {(() => {
             const formConfig = formPreviewDetailData.option?.formConfig || defaultFormConfig;
             const layoutColumns = formConfig.layoutColumns || 1;
-            
+            const gridStyle = layoutColumns > 1 ? {
+              display: 'grid',
+              gridTemplateColumns: `repeat(${layoutColumns}, minmax(0, 1fr))`,
+              gap: '12px',
+              rowGap: '16px',
+            } : undefined;
+
+            // 与表单设计器一致:每个字段使用 field.labelWidth ?? formConfig.labelWidth ?? 100
+            const getPreviewItemLayout = (f: any) => {
+              const raw = f.labelWidth ?? formConfig.labelWidth ?? 100;
+              const w = (typeof raw === 'number' && raw > 0) ? raw : 100;
+              const isTop = formConfig.labelPosition === 'top';
+              return {
+                labelCol: isTop ? undefined : { flex: `${w}px`, style: { minWidth: `${w}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } },
+                wrapperCol: isTop ? undefined : { flex: 'auto', style: { minWidth: 0 } },
+              };
+            };
+
             // 渲染字段预览(支持嵌套结构)
             const renderFieldPreview = (field: any, parentSpanStyle?: React.CSSProperties): React.ReactNode => {
               const spanStyle = parentSpanStyle || (layoutColumns > 1 ? { gridColumn: `span ${Math.min(layoutColumns, field.span || 1)}` } : undefined);
+              const itemLayout = getPreviewItemLayout(field);
 
               // 处理容器类型(card 和 grid)
               if (field.type === 'card') {
@@ -4155,12 +4169,14 @@ export default function ProcessDesigner() {
               switch (field.type) {
                 case 'textarea':
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         required={field.required && !formConfig.hideRequiredMark}
                         help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <Input.TextArea 
                           placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'} 
@@ -4171,12 +4187,14 @@ export default function ProcessDesigner() {
                   );
                 case 'number':
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         required={field.required && !formConfig.hideRequiredMark}
                         help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <InputNumber style={{ width: '100%' }} placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'} />
                       </AntdForm.Item>
@@ -4184,12 +4202,14 @@ export default function ProcessDesigner() {
                   );
                 case 'select':
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         required={field.required && !formConfig.hideRequiredMark}
                         help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <Select placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}>
                           {(field.options || []).map((opt: any, idx: number) => (
@@ -4201,12 +4221,14 @@ export default function ProcessDesigner() {
                   );
                 case 'date':
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         required={field.required && !formConfig.hideRequiredMark}
                         help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <DatePicker style={{ width: '100%' }} placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择日期'} />
                       </AntdForm.Item>
@@ -4214,11 +4236,13 @@ export default function ProcessDesigner() {
                   );
                 case 'switch':
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         valuePropName="checked"
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <Switch />
                       </AntdForm.Item>
@@ -4226,12 +4250,14 @@ export default function ProcessDesigner() {
                   );
                 case 'radio':
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         required={field.required && !formConfig.hideRequiredMark}
                         help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <Radio.Group>
                           {(field.options || []).map((opt: any, idx: number) => (
@@ -4243,12 +4269,14 @@ export default function ProcessDesigner() {
                   );
                 case 'checkbox':
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         required={field.required && !formConfig.hideRequiredMark}
                         help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <Checkbox.Group>
                           {(field.options || []).map((opt: any, idx: number) => (
@@ -4258,14 +4286,36 @@ export default function ProcessDesigner() {
                       </AntdForm.Item>
                     </div>
                   );
+                case 'upload':
+                  return (
+                    <div key={field.id} style={spanStyle}>
+                      <AntdForm.Item
+                        label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
+                        name={field.name || field.field}
+                        required={field.required && !formConfig.hideRequiredMark}
+                        help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
+                      >
+                        <FormUploadField
+                          uploadType={field.uploadType}
+                          maxCount={field.maxCount}
+                          accept={field.accept}
+                          disabled={field.disabled}
+                        />
+                      </AntdForm.Item>
+                    </div>
+                  );
                 default:
                   return (
-                    <div key={field.id} style={spanStyle} className="form-item-wrapper">
+                    <div key={field.id} style={spanStyle}>
                       <AntdForm.Item
                         label={(field.label || field.title || '') + (formConfig.labelSuffix || '')}
                         name={field.name || field.field}
                         required={field.required && !formConfig.hideRequiredMark}
                         help={field.hint}
+                        labelCol={itemLayout.labelCol}
+                        wrapperCol={itemLayout.wrapperCol}
                       >
                         <Input 
                           type={field.inputType || 'text'}
@@ -4277,48 +4327,27 @@ export default function ProcessDesigner() {
               }
             };
 
-            // 预览模式下,强制使用更小的 label 宽度,让输入区域更宽
-            const previewLabelSpan = formConfig.labelPosition !== 'top' 
-              ? (formConfig.labelWidth ? Math.min(Math.floor(formConfig.labelWidth / 8), 4) : 4)
-              : undefined;
-            const previewWrapperSpan = previewLabelSpan ? 24 - previewLabelSpan : undefined;
-
             return (
               <>
                 <style>{`
-                  .form-preview-modal .ant-form-item-label {
-                    flex: 0 0 auto !important;
-                    max-width: none !important;
-                  }
-                  .form-preview-modal .ant-form-item-label > label {
-                    font-size: 14px !important;
-                    white-space: nowrap !important;
-                    overflow: hidden !important;
-                    text-overflow: ellipsis !important;
+                  .form-preview-grid .ant-form-item {
+                    margin-bottom: 12px;
                   }
-                  .form-preview-modal .ant-form-item-control {
-                    flex: 1 1 auto !important;
-                    min-width: 0 !important;
-                  }
-                  .form-preview-modal .form-item-wrapper {
-                    background-color: #f5f5f5;
-                    border-radius: 8px;
-                    padding: 12px 16px;
-                    margin-bottom: 16px;
-                  }
-                  .form-preview-modal .form-item-wrapper .ant-form-item {
-                    margin-bottom: 0;
+                  .form-preview-grid .ant-form-item-control {
+                    min-width: 0;
                   }
                 `}</style>
                 <AntdForm
                   form={formPreviewForm}
                   layout={formConfig.labelPosition === 'top' ? 'vertical' : 'horizontal'}
-                  size={formConfig.formSize || 'middle'}
-                  labelCol={previewLabelSpan ? { span: previewLabelSpan } : undefined}
-                  wrapperCol={previewWrapperSpan ? { span: previewWrapperSpan } : undefined}
-                  className="form-preview-modal"
+                  size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
+                  requiredMark={formConfig.hideRequiredMark ? false : undefined}
+                  wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                 >
-                  <div style={layoutColumns > 1 ? { display: 'grid', gridTemplateColumns: `repeat(${layoutColumns}, minmax(0, 1fr))`, gap: '16px' } : {}}>
+                  <div
+                    style={gridStyle}
+                    className={layoutColumns === 1 ? 'space-y-4' : 'form-preview-grid'}
+                  >
                     {(formPreviewDetailData.rule || []).map((field: any) => renderFieldPreview(field))}
                   </div>
                 </AntdForm>

+ 8 - 1
src/components/ProfileSettings.tsx

@@ -9,11 +9,16 @@ import { getPermissionInfo, setPermissionInfo } from '../utils/permission';
 import { fileApi } from '../api/file';
 import { clearAuth } from '../utils/auth';
 
+/** 传给父组件的增量更新,只传有变化的字段,避免整页刷新/抖动 */
+export type ProfileUpdatePayload = { avatar?: string; nickname?: string; email?: string };
+
 interface ProfileSettingsProps {
   onBack: () => void;
+  /** 个人资料或头像更新后调用,传入变更字段即可,父组件仅合并 state 不重读存储 */
+  onProfileUpdated?: (updates: ProfileUpdatePayload) => void;
 }
 
-export default function ProfileSettings({ onBack }: ProfileSettingsProps) {
+export default function ProfileSettings({ onBack, onProfileUpdated }: ProfileSettingsProps) {
   const navigate = useNavigate();
   const { t } = useTranslation();
   // 用户信息显示
@@ -128,6 +133,7 @@ export default function ProfileSettings({ onBack }: ProfileSettingsProps) {
           },
         };
         setPermissionInfo(updatedPermissionInfo);
+        onProfileUpdated?.({ avatar, nickname: nickname.trim(), email: email.trim() });
       }
     } catch (error: any) {
       toast.error(error.message || t('profile.saveFailed'));
@@ -224,6 +230,7 @@ export default function ProfileSettings({ onBack }: ProfileSettingsProps) {
           },
         };
         setPermissionInfo(updatedPermissionInfo);
+        onProfileUpdated?.({ avatar: fileUrl });
       }
     } catch (error: any) {
       toast.error(error.message || t('profile.avatarUploadFailed'));

+ 92 - 38
src/components/TaskManagement.tsx

@@ -15,6 +15,7 @@ import urgecy1Icon from '../assets/urgecy1.png';
 import urgecy2Icon from '../assets/urgecy2.png';
 import urgecy3Icon from '../assets/urgecy3.png';
 import { useTranslation } from 'react-i18next';
+import FormUploadField from './FormUploadField';
 
 // 辅助函数:安全地将值转换为 dayjs 对象
 const safeToDayjs = (value: any): dayjs.Dayjs | null => {
@@ -453,6 +454,18 @@ export default function TaskManagement() {
       );
     }
 
+    // 与表单设计器一致:每字段 labelCol/wrapperCol
+    const getItemLayout = (f: any) => {
+      const isTop = formConfig.labelPosition === 'top';
+      const w = f.labelWidth ?? formConfig.labelWidth ?? 100;
+      const effective = (typeof w === 'number' && w > 0) ? w : 100;
+      return {
+        labelCol: isTop ? undefined : { flex: `${effective}px`, style: { minWidth: `${effective}px`, textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left' } },
+        wrapperCol: isTop ? undefined : { flex: 'auto', style: { minWidth: 0 } },
+      };
+    };
+    const itemLayout = getItemLayout(field);
+
     // 处理普通字段
     switch (field.type) {
       case 'textarea':
@@ -464,6 +477,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.TextArea 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'} 
@@ -486,6 +501,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input.Password 
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请输入'}
@@ -507,6 +524,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <InputNumber 
                 style={{ width: '100%' }} 
@@ -528,6 +547,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Select
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -551,6 +572,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 // 选择日期时,将 dayjs 对象转换为毫秒级时间戳
                 if (!value) return undefined;
@@ -604,6 +627,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期范围' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 // 选择日期范围时,将 dayjs 对象数组转换为毫秒级时间戳数组
                 if (!value || !Array.isArray(value) || value.length !== 2) return undefined;
@@ -684,6 +709,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
               getValueFromEvent={(value) => {
                 // 选择日期时间时,将 dayjs 对象转换为毫秒级时间戳
                 if (!value) return undefined;
@@ -736,6 +763,8 @@ export default function TaskManagement() {
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
               valuePropName="checked"
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Switch disabled={field.disabled} />
             </AntdForm.Item>
@@ -750,6 +779,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Radio.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -768,6 +799,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Checkbox.Group disabled={field.disabled}>
                 {(field.options || []).map((opt: any, idx: number) => (
@@ -786,6 +819,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Cascader
                 placeholder={typeof field.placeholder === 'string' ? field.placeholder : '请选择'}
@@ -807,23 +842,15 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请上传' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
-              <Upload
+              <FormUploadField
+                uploadType={field.uploadType}
+                maxCount={field.maxCount}
+                accept={field.accept}
                 disabled={field.disabled}
-                maxCount={field.uploadType === 'single-image' ? 1 : field.maxCount || (field.uploadType === 'multiple-image' ? 9 : undefined)}
-                accept={field.accept || (field.uploadType === 'single-image' || field.uploadType === 'multiple-image' ? 'image/*' : undefined)}
-                listType={(field.uploadType === 'file' ? 'text' : 'picture-card') as 'text' | 'picture-card' | 'picture'}
-                multiple={field.uploadType !== 'single-image'}
-              >
-                {field.uploadType === 'file' ? (
-                  <Button icon={<UploadOutlined />}>上传文件</Button>
-                ) : (
-                  <div>
-                    <UploadOutlined />
-                    <div style={{ marginTop: 8 }}>上传</div>
-                  </div>
-                )}
-              </Upload>
+              />
             </AntdForm.Item>
           </div>
         );
@@ -837,6 +864,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <DatePicker 
                 style={{ width: '100%' }} 
@@ -864,6 +893,8 @@ export default function TaskManagement() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -886,6 +917,8 @@ export default function TaskManagement() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择时间' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -909,6 +942,8 @@ export default function TaskManagement() {
                   required={field.required && !formConfig.hideRequiredMark}
                   rules={field.required ? [{ required: true, message: field.requiredMessage || '请选择日期' }] : []}
                   help={field.hint}
+                  labelCol={itemLayout.labelCol}
+                  wrapperCol={itemLayout.wrapperCol}
                 >
                   <DatePicker 
                     style={{ width: '100%' }} 
@@ -932,6 +967,8 @@ export default function TaskManagement() {
               required={field.required && !formConfig.hideRequiredMark}
               rules={field.required ? [{ required: true, message: field.requiredMessage || '请输入' }] : []}
               help={field.hint}
+              labelCol={itemLayout.labelCol}
+              wrapperCol={itemLayout.wrapperCol}
             >
               <Input 
                 type={field.inputType || 'text'}
@@ -2222,15 +2259,21 @@ export default function TaskManagement() {
                                           layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                           size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                           requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                          labelCol={formConfig.labelWidth ? {
-                                            style: {
-                                              width: `${formConfig.labelWidth}px`,
-                                              textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                            }
-                                          } : undefined}
+                                          labelCol={
+                                            formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                              ? undefined
+                                              : {
+                                                  flex: `${formConfig.labelWidth}px`,
+                                                  style: {
+                                                    minWidth: `${formConfig.labelWidth}px`,
+                                                    textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                                  },
+                                                }
+                                          }
+                                          wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                                         >
                                           <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                            <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                             {(formData.rule || []).map((field: any) => {
                                               const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                               return renderFieldPreview(fieldWithDisabled);
@@ -2436,15 +2479,21 @@ export default function TaskManagement() {
                                       layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                                       size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                                       requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                                      labelCol={formConfig.labelWidth ? {
-                                        style: {
-                                          width: `${formConfig.labelWidth}px`,
-                                          textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                        }
-                                      } : undefined}
+                                      labelCol={
+                                        formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                          ? undefined
+                                          : {
+                                              flex: `${formConfig.labelWidth}px`,
+                                              style: {
+                                                minWidth: `${formConfig.labelWidth}px`,
+                                                textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                              },
+                                            }
+                                      }
+                                      wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                                     >
                                       <div style={gridStyle} className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}>
-                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; }`}</style>
+                                        <style>{`.form-detail-grid .ant-form-item { margin-bottom: 12px; } .form-detail-grid .ant-form-item-control { min-width: 0; }`}</style>
                                         {(formData.rule || []).map((field: any) => {
                                           const fieldWithDisabled = isApproved ? { ...field, disabled: true, readOnly: true } : field;
                                           return renderFieldPreview(fieldWithDisabled);
@@ -2751,21 +2800,26 @@ export default function TaskManagement() {
                               layout={formConfig.labelPosition === 'top' ? 'vertical' : formConfig.labelPosition === 'left' ? 'horizontal' : 'horizontal'}
                               size={formConfig.formSize === 'default' ? 'middle' : formConfig.formSize}
                               requiredMark={formConfig.hideRequiredMark ? false : undefined}
-                              labelCol={formConfig.labelWidth ? { 
-                                style: { 
-                                  width: `${formConfig.labelWidth}px`,
-                                  textAlign: formConfig.labelPosition === 'left' ? 'left' : formConfig.labelPosition === 'right' ? 'right' : 'left'
-                                } 
-                              } : undefined}
+                              labelCol={
+                                formConfig.labelPosition === 'top' || !formConfig.labelWidth
+                                  ? undefined
+                                  : {
+                                      flex: `${formConfig.labelWidth}px`,
+                                      style: {
+                                        minWidth: `${formConfig.labelWidth}px`,
+                                        textAlign: formConfig.labelPosition === 'right' ? 'right' : 'left',
+                                      },
+                                    }
+                              }
+                              wrapperCol={formConfig.labelPosition === 'top' ? undefined : { flex: 'auto', style: { minWidth: 0 } }}
                             >
                               <div 
                                 style={gridStyle} 
                                 className={layoutColumns === 1 ? 'space-y-4' : 'form-detail-grid'}
                               >
                                 <style>{`
-                                  .form-detail-grid .ant-form-item {
-                                    margin-bottom: 12px;
-                                  }
+                                  .form-detail-grid .ant-form-item { margin-bottom: 12px; }
+                                  .form-detail-grid .ant-form-item-control { min-width: 0; }
                                 `}</style>
                                 {(formData.rule || []).map((field: any) => {
                                   // 如果已通过,禁用所有字段