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
This commit is contained in:
wangjia
2026-07-03 09:58:14 +08:00
parent ca7595b113
commit 6238b86dcb
286 changed files with 16831 additions and 11136 deletions
+92
View File
@@ -0,0 +1,92 @@
// widgets/ds/ds_toast.dart — 原型 .toastatoms.css1:1
// fixed bottom:26 水平居中 / --toast-bg 底 + 白字 fs-body / pad 11 18 / r-md /
// **内容自适应宽**(不定宽、不贯穿)/ .25s 淡入+上滑 / 2.2s 自动消失。
// 单例复用:新消息顶替旧消息(对齐原型同一 #toast 节点 + 计时器重置),
// 天然避免多条提示叠罗汉。语义底色(成功/失败)由调用点传 [bg] 覆盖。
import 'dart:async';
import 'package:flutter/material.dart';
import '../../core/theme/app_dims.g.dart';
import '../../core/theme/context_tokens.dart';
OverlayEntry? _entry;
Timer? _timer;
void showDsToast(
BuildContext context,
String message, {
Color? bg,
Duration duration = const Duration(milliseconds: 2200),
}) {
final overlay = Overlay.maybeOf(context, rootOverlay: true);
if (overlay == null) return;
final color = bg ?? context.tokens.toastBg;
_timer?.cancel();
if (_entry?.mounted ?? false) _entry!.remove();
_entry = null;
final entry = OverlayEntry(
builder: (_) => _DsToast(message: message, bg: color),
);
_entry = entry;
overlay.insert(entry);
_timer = Timer(duration, () {
if (_entry == entry) {
if (entry.mounted) entry.remove();
_entry = null;
}
});
}
class _DsToast extends StatelessWidget {
final String message;
final Color bg;
const _DsToast({required this.message, required this.bg});
@override
Widget build(BuildContext context) {
return Positioned(
left: 0,
right: 0,
bottom: 26,
child: IgnorePointer(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TweenAnimationBuilder<double>(
tween: Tween(begin: 0, end: 1),
duration: const Duration(milliseconds: 250),
curve: Curves.easeOut,
builder: (_, v, child) => Opacity(
opacity: v,
child: Transform.translate(
offset: Offset(0, 20 * (1 - v)), child: child),
),
child: Material(
color: Colors.transparent,
child: Container(
constraints: const BoxConstraints(maxWidth: 560),
padding:
const EdgeInsets.symmetric(horizontal: 18, vertical: 11),
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(AppDims.rMd),
),
child: Text(
message,
style: const TextStyle(
fontSize: AppDims.fsBody,
color: Colors
.white, // ds-ignore: toast 白字固定(承 toast-bg/语义色底)
),
),
),
),
),
],
),
),
);
}
}