Explorar o código

feat: 费用明细弹窗优化 — TDDropdownMenu+左右布局+必填标记+样式统一

- 明细弹窗:标题居中、TDDropdownMenu 替换自绘下拉
- 左右同行布局(标签80px+控件),必填红*标记
- 右侧控件圆角边框(clipBehavior+padding)
- 数量/单价 textAlign 居中
- 明细说明 TDTextarea 样式对齐费用事由(bordered+minLines+maxLines)
- 底部按钮 medium→large
- 下拉标签同步修复(catLabel/unitLabel)
chengc hai 5 días
pai
achega
dc16899ca1

+ 92 - 48
lib/features/expense_application/expense_application_apply_page.dart

@@ -745,6 +745,8 @@ class _ExpenseApplicationApplyPageState
     final cats = _availableDetailCategories;
     String cat = cats.isNotEmpty ? cats.first.code : 'other';
     String unit = l10n.get('unitPiece');
+    String catLabel = l10n.get(cats.firstWhere((c) => c.code == cat).nameKey);
+    String unitLabel = l10n.get('unitPiece');
     final qtyCtrl = TextEditingController(text: '1');
     final priceCtrl = TextEditingController();
     final remarkCtrl = TextEditingController();
@@ -781,6 +783,7 @@ class _ExpenseApplicationApplyPageState
               const SizedBox(height: 16),
               // 费用类别 — 左右布局,必填
               Row(
+                crossAxisAlignment: CrossAxisAlignment.center,
                 children: [
                   SizedBox(
                     width: 80,
@@ -788,29 +791,35 @@ class _ExpenseApplicationApplyPageState
                   ),
                   const SizedBox(width: 8),
                   Expanded(
-                    child: TDDropdownMenu(
-                      items: [
-                        TDDropdownItem(
-                          label: l10n.get(
-                            cats.firstWhere((c) => c.code == cat).nameKey,
+                    child: Container(
+                      clipBehavior: Clip.antiAlias,
+                      padding: const EdgeInsets.symmetric(horizontal: 12),
+                      decoration: BoxDecoration(
+                        borderRadius: BorderRadius.circular(8),
+                        border: Border.all(color: colors.border, width: 1),
+                      ),
+                      child: TDDropdownMenu(
+                        items: [
+                          TDDropdownItem(
+                            label: catLabel,
+                            options: cats
+                                .map(
+                                  (c) => TDDropdownItemOption(
+                                    value: c.code,
+                                    label: l10n.get(c.nameKey),
+                                  ),
+                                )
+                                .toList(),
                           ),
-                          options: cats
-                              .map(
-                                (c) => TDDropdownItemOption(
-                                  value: c.code,
-                                  label: l10n.get(c.nameKey),
-                                ),
-                              )
-                              .toList(),
-                        ),
-                      ],
-                      closeOnClickOverlay: true,
-                      onMenuClosed: (index) {
-                        if (index >= 0 && index < cats.length) {
-                          cat = cats[index].code;
-                          setDlg(() {});
-                        }
-                      },
+                        ],
+                        closeOnClickOverlay: true,
+                        onMenuClosed: (index) {
+                          if (index >= 0 && index < cats.length) {
+                            cat = cats[index].code;
+                            setDlg(() {});
+                          }
+                        },
+                      ),
                     ),
                   ),
                 ],
@@ -818,6 +827,7 @@ class _ExpenseApplicationApplyPageState
               const SizedBox(height: 12),
               // 数量 — 左右布局,必填
               Row(
+                crossAxisAlignment: CrossAxisAlignment.center,
                 children: [
                   SizedBox(
                     width: 80,
@@ -825,38 +835,59 @@ class _ExpenseApplicationApplyPageState
                   ),
                   const SizedBox(width: 8),
                   Expanded(
-                    child: TDInput(controller: qtyCtrl, hintText: '>0'),
+                    child: Container(
+                      clipBehavior: Clip.antiAlias,
+                      padding: const EdgeInsets.symmetric(horizontal: 12),
+                      decoration: BoxDecoration(
+                        borderRadius: BorderRadius.circular(8),
+                        border: Border.all(color: colors.border, width: 1),
+                      ),
+                      child: TDInput(
+                        controller: qtyCtrl,
+                        hintText: '>0',
+                        contentAlignment: TextAlign.center,
+                      ),
+                    ),
                   ),
                 ],
               ),
               const SizedBox(height: 12),
               // 单位 — 左右布局
               Row(
+                crossAxisAlignment: CrossAxisAlignment.center,
                 children: [
                   SizedBox(width: 80, child: _label(l10n.get('unit'))),
                   const SizedBox(width: 8),
                   Expanded(
-                    child: TDDropdownMenu(
-                      items: [
-                        TDDropdownItem(
-                          label: unit,
-                          options: unitOptions
-                              .map(
-                                (u) => TDDropdownItemOption(
-                                  value: u,
-                                  label: l10n.get(u),
-                                ),
-                              )
-                              .toList(),
-                        ),
-                      ],
-                      closeOnClickOverlay: true,
-                      onMenuClosed: (index) {
-                        if (index >= 0 && index < unitOptions.length) {
-                          unit = l10n.get(unitOptions[index]);
-                          setDlg(() {});
-                        }
-                      },
+                    child: Container(
+                      clipBehavior: Clip.antiAlias,
+                      padding: const EdgeInsets.symmetric(horizontal: 12),
+                      decoration: BoxDecoration(
+                        borderRadius: BorderRadius.circular(8),
+                        border: Border.all(color: colors.border, width: 1),
+                      ),
+                      child: TDDropdownMenu(
+                        items: [
+                          TDDropdownItem(
+                            label: unitLabel,
+                            options: unitOptions
+                                .map(
+                                  (u) => TDDropdownItemOption(
+                                    value: u,
+                                    label: l10n.get(u),
+                                  ),
+                                )
+                                .toList(),
+                          ),
+                        ],
+                        closeOnClickOverlay: true,
+                        onMenuClosed: (index) {
+                          if (index >= 0 && index < unitOptions.length) {
+                            unit = l10n.get(unitOptions[index]);
+                            setDlg(() {});
+                          }
+                        },
+                      ),
                     ),
                   ),
                 ],
@@ -864,6 +895,7 @@ class _ExpenseApplicationApplyPageState
               const SizedBox(height: 12),
               // 单价 — 左右布局,必填
               Row(
+                crossAxisAlignment: CrossAxisAlignment.center,
                 children: [
                   SizedBox(
                     width: 80,
@@ -871,7 +903,19 @@ class _ExpenseApplicationApplyPageState
                   ),
                   const SizedBox(width: 8),
                   Expanded(
-                    child: TDInput(controller: priceCtrl, hintText: '>0'),
+                    child: Container(
+                      clipBehavior: Clip.antiAlias,
+                      padding: const EdgeInsets.symmetric(horizontal: 12),
+                      decoration: BoxDecoration(
+                        borderRadius: BorderRadius.circular(8),
+                        border: Border.all(color: colors.border, width: 1),
+                      ),
+                      child: TDInput(
+                        controller: priceCtrl,
+                        hintText: '>0',
+                        contentAlignment: TextAlign.center,
+                      ),
+                    ),
                   ),
                 ],
               ),
@@ -895,7 +939,7 @@ class _ExpenseApplicationApplyPageState
                   Expanded(
                     child: TDButton(
                       text: l10n.get('cancel'),
-                      size: TDButtonSize.medium,
+                      size: TDButtonSize.large,
                       type: TDButtonType.outline,
                       shape: TDButtonShape.rectangle,
                       theme: TDButtonTheme.defaultTheme,
@@ -906,7 +950,7 @@ class _ExpenseApplicationApplyPageState
                   Expanded(
                     child: TDButton(
                       text: l10n.get('confirm'),
-                      size: TDButtonSize.medium,
+                      size: TDButtonSize.large,
                       type: TDButtonType.fill,
                       shape: TDButtonShape.rectangle,
                       theme: TDButtonTheme.primary,
@@ -1027,7 +1071,7 @@ class _ExpenseApplicationApplyPageState
                   decoration: BoxDecoration(
                     color: colors.bgPage,
                     borderRadius: BorderRadius.circular(4),
-                    border: Border.all(color: colors.border),
+                    border: Border.all(color: colors.border, width: 1),
                   ),
                   child: Center(
                     child: Icon(