feat(client): 库存/出入库移动卡片与详情 sheet 逐一对齐原型结构
- 新增 MCard(原型 .m-card 双栏:mc-main 标题+副行 mono | mc-right 徽章行+ 金额 mono | › | mc-foot ⓘ脚注)+ DsIconBadge(.badge.ico 22px 纯图标)/ DsTextIconBadge(.badge.bi 图标+文字) + statusToneOf 状态词配色表—— 替换原 MobileListCard「标签:值」布局与各屏本地 _icoBadge/_statusColors - 出入库卡:单号 + 供应商/客户·N 项 + 状态/退单/待定价图标徽章 + 合计金额 + 日期·经手人·审核 脚注;库存卡:品名 + 编码·规格 + 状态徽章 + 数量(缺货红/ 预警黄);移动卡不再有行内操作(对齐原型,操作统一在详情 sheet;打标签= 打印,移动端裁剪) - DsTable 窄屏卡片流去外层大卡容器(卡直接铺页面底色,对齐原型 m-scroll)—— 往来/基础数据等全部卡片流屏同步受益 - 出入库详情窄屏改 sheet 专属布局(原型 openOrder):drow 字段行 + 明细 pe-card(头行 图标+「明细 · N 项」+ 行=品名+系列·×数量 | 金额/待定价徽章)+ 合计 drow + 等分按钮行(无组标签);桌面右滑抽屉布局不变 - 相关移动 golden 全量重生成(出入库/库存/往来/基础数据 ×3 主题), 桌面 golden 零漂移;283 测试全绿 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import '../core/responsive/responsive.dart';
|
||||
import '../core/theme/context_tokens.dart';
|
||||
import '../core/theme/app_dims.g.dart';
|
||||
import '../core/theme/app_fonts.dart';
|
||||
import 'ds/m_card.dart';
|
||||
import 'ds/m_sheet.dart';
|
||||
|
||||
/// 右侧滑入抽屉呈现(对齐原型 .drawer / .drawer-mask)。
|
||||
@@ -126,6 +127,9 @@ class OrderDetailDrawer extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final t = context.tokens;
|
||||
// 窄屏:sheet 形态布局(对齐原型 m-stock-*-list openOrder:drow 字段 +
|
||||
// 明细 pe-card + 合计 drow + 等分按钮行),桌面右滑抽屉布局不变。
|
||||
if (context.isMobile) return _buildMobileSheet(context);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
@@ -225,6 +229,159 @@ class OrderDetailDrawer extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
// ── 窄屏 sheet 形态(原型 openOrder)────────────────────────────────────
|
||||
Widget _buildMobileSheet(BuildContext context) {
|
||||
final t = context.tokens;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// 头:单号 + X(grip 由 showMSheet 提供)
|
||||
Container(
|
||||
padding: const EdgeInsets.fromLTRB(16, 4, 8, 8),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(bottom: BorderSide(color: t.borderSubtle))),
|
||||
child: Row(children: [
|
||||
Expanded(
|
||||
child: Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: AppDims.fsTitle,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: t.heading)),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(LucideIcons.x, size: 20, color: t.muted),
|
||||
splashRadius: 18,
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
]),
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(16, 2, 16, 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
for (final r in infoRows)
|
||||
_DrawerRow(label: r.label, value: r.value),
|
||||
// 明细卡(原型 pe-card:头行 图标+「入库明细 · N 项」+ 行列表)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 14),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: t.border),
|
||||
borderRadius: BorderRadius.circular(AppDims.rLg),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.fromLTRB(14, 11, 14, 11),
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(color: t.borderSubtle))),
|
||||
child: Row(children: [
|
||||
Icon(LucideIcons.tableProperties,
|
||||
size: 15, color: t.primary),
|
||||
const SizedBox(width: 8),
|
||||
Text('$linesLabel · ${lines.length} 项',
|
||||
style: TextStyle(
|
||||
fontSize: AppDims.fsSm,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: t.heading)),
|
||||
]),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 14, vertical: 2),
|
||||
child: Column(children: [
|
||||
for (var i = 0; i < lines.length; i++)
|
||||
_mLineRow(t, lines[i], i == lines.length - 1),
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// 合计(原型 drow:label 左 / mono 值右)
|
||||
_mTotalRow(t, '合计金额', totalText, t.heading),
|
||||
if (profitText != null)
|
||||
_mTotalRow(t, '合计利润', profitText!,
|
||||
profitText!.startsWith('-') ? t.danger : t.success),
|
||||
// 操作按钮(原型:等分按钮行,无组标签)
|
||||
if (actionGroups.isNotEmpty) const SizedBox(height: 16),
|
||||
for (var g = 0; g < actionGroups.length; g++) ...[
|
||||
if (g > 0) const SizedBox(height: 10),
|
||||
Row(children: [
|
||||
for (var b = 0;
|
||||
b < actionGroups[g].buttons.length;
|
||||
b++) ...[
|
||||
if (b > 0) const SizedBox(width: 10),
|
||||
Expanded(child: actionGroups[g].buttons[b]),
|
||||
],
|
||||
]),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 窄屏明细行(原型:左 商品名 + 系列·×数量 小字,右 金额 mono / 待定价徽章)。
|
||||
Widget _mLineRow(dynamic t, OrderLine l, bool last) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11),
|
||||
decoration: last
|
||||
? null
|
||||
: BoxDecoration(
|
||||
border: Border(bottom: BorderSide(color: t.borderSubtle))),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l.name,
|
||||
style: TextStyle(
|
||||
fontSize: AppDims.fsBody, color: t.text, height: 1.45)),
|
||||
const SizedBox(height: 2),
|
||||
Text('${l.series} · ×${l.qty}',
|
||||
style: TextStyle(fontSize: AppDims.fsXs, color: t.faint)),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
l.pending
|
||||
? const DsTextIconBadge('待定价')
|
||||
: Text(l.amount.isNotEmpty ? l.amount : l.price,
|
||||
style: TextStyle(
|
||||
fontSize: AppDims.fsBody,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: t.heading,
|
||||
fontFamily: AppFonts.mono,
|
||||
fontFamilyFallback: AppFonts.monoFallback)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _mTotalRow(dynamic t, String label, String value, Color color) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 11),
|
||||
child: Row(children: [
|
||||
Text(label, style: TextStyle(fontSize: AppDims.fsBody, color: t.muted)),
|
||||
const Spacer(),
|
||||
Text(value,
|
||||
style: TextStyle(
|
||||
fontSize: AppDims.fsBody,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: color,
|
||||
fontFamily: AppFonts.mono,
|
||||
fontFamilyFallback: AppFonts.monoFallback)),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DrawerRow extends StatelessWidget {
|
||||
|
||||
Reference in New Issue
Block a user