Files
jiu/client/lib/widgets/order_row_actions.dart
T
wangjia 6238b86dcb feat(client): 登录/注册页照原型重建,ds 真相源组件族统一全部屏
- 登录/注册(login.html/register.html 1:1):两栏卡片+品牌渐变面板+主题小衣服
  pill(onSurface 变体)+记住我(记录并预填最近账号)+原型式 toast 校验;
  登录 fidelity 1.4–2.1% 三主题全绿;注册暂不入闸(少 门店编号/兑换券 字段,
  已记 CONTRACT,screens.mjs 留存根)
- ds 原子补齐:DsToast(.toast 单例)/DsCheck(.check/.agree)/DsButton lg 档/
  DsSelect 替换全部旧 DropdownButton/DsField label 在上/DsInput 后缀与密码形态
- 全屏统一:对话框按钮全 DsButton、盒式输入主题钉死(visualDensity.standard、
  h38、InputDecorationTheme 渗漏修复)、图标全 lucide、JetBrains Mono 三端同源、
  BrandMark 真相源 logo、只读模式写操作全量守卫(WriteGuard+DsToast)
- 出入库列表:版式对齐原型(卡片对齐+搜索框居中)、KPI 近30天滚动、结清后
  失效财务应收应付表;商品编辑抽屉介绍库改搜索下拉、图片双击全屏预览
- 删除旧 UI 死代码:DataTableCard/FormDialog/PageScaffold/SearchChip/
  SelectProductDialog/tabStateProvider
- golden/fidelity:stock-in/out 补注册(9%)、login 入册(8%)、goldens 全量重打;
  修复 pubspec flutter_web_plugins 非法声明(CI pub get 阻断)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
2026-07-03 09:58:14 +08:00

93 lines
3.8 KiB
Dart

import 'package:flutter/material.dart';
import '../core/theme/context_tokens.dart';
import 'write_guard.dart';
/// 入/出库单行内操作按钮,列表表格与移动端卡片、入库与出库两屏共用。
///
/// 此前 stock_in / stock_out 各自逐字重复了「详情/打印/结清/修改/删除/提交/通过/拒绝」
/// 的状态门控(draft/pending/approved)与 WriteGuard 包裹脚手架,仅单据类型、路由、
/// 打印函数与回调不同。这里把**相同的结构**收敛到单一来源,差异通过回调注入:
///
/// - [afterPrint]:紧随「打印」之后的附加按钮(入库的「打标签」;出库传空)。
/// - 各 `on*` 回调由调用方绑定到对应单据的确认/跳转逻辑。
List<Widget> buildOrderRowActions({
required BuildContext context,
required bool readonly,
required String status,
required int orderId,
required VoidCallback onDetail,
required VoidCallback onPrint,
required VoidCallback onSettle,
required VoidCallback onEdit,
required VoidCallback onDelete,
required VoidCallback onSubmit,
required VoidCallback onApprove,
required VoidCallback onReject,
required VoidCallback onWithdraw,
required VoidCallback onReturn,
bool canWithdraw = false,
bool canReturn = false,
List<Widget> afterPrint = const [],
}) {
TextButton btn(String text, Color color, VoidCallback onPressed,
{Key? key}) =>
TextButton(
key: key,
onPressed: onPressed,
child: Text(text, style: TextStyle(fontSize: 12, color: color)),
);
// 实心强调按钮(用于「退单」这类需突出的危险操作,与原型一致)。
Widget filledBtn(String text, Color color, VoidCallback onPressed,
{Key? key}) =>
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: ElevatedButton(
key: key,
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: color,
foregroundColor: context.tokens.onPrimary,
elevation: 0,
visualDensity: VisualDensity.compact,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
minimumSize: const Size(0, 30),
padding: const EdgeInsets.symmetric(horizontal: 12),
textStyle:
const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
),
child: Text(text),
),
);
return [
btn('详情', context.tokens.primary, onDetail),
btn('打印', context.tokens.primary, onPrint),
...afterPrint,
if (!readonly && status == 'approved')
WriteGuard(child: btn('结清', context.tokens.accent, onSettle)),
// 退单(已审核单退货):红色实心按钮突出(与原型一致),按权限显示
if (!readonly && status == 'approved' && canReturn)
WriteGuard(
child: filledBtn('退单', context.tokens.danger, onReturn,
key: Key('btn_return_$orderId'))),
if (!readonly && status == 'draft') ...[
WriteGuard(child: btn('修改', context.tokens.primary, onEdit)),
WriteGuard(child: btn('删除', context.tokens.danger, onDelete)),
WriteGuard(child: btn('提交', context.tokens.primary, onSubmit)),
],
if (!readonly && status == 'pending') ...[
WriteGuard(
child: btn('通过', context.tokens.success, onApprove,
key: Key('btn_approve_$orderId'))),
WriteGuard(
child: btn('拒绝', context.tokens.danger, onReject,
key: Key('btn_reject_$orderId'))),
// 撤回(审核中→草稿):管理员/超管任意单、操作员本人单可见,用 warn 样式
if (canWithdraw)
WriteGuard(
child: btn('撤回', context.tokens.warn, onWithdraw,
key: Key('btn_withdraw_$orderId'))),
],
];
}