Files
jiu/client/lib/models/number_rule.dart
T
wangjia 8385c23c40 feat: 编号规则支持模式/日期格式,商品编码接入统一编号
- number_rules 新增 mode(date_seq 日期+序号3位按周期重置 / seq 连续6位)与 seq_period 列
- 单号生成按 mode + date_format 拼接,跨日期周期自动重置;启动回填 product→seq
- 商品建号接入 number_rules(seq 模式、前缀可配、从现有最大序列号播种,续发连续编号)
- 设置屏:加「模式」列、当前序号按周期显示(未开单显0);编辑弹窗前缀所有类型可改,
  有日期的序号系统自动(只读置灰)、可改日期格式,商品编码序号可调大不可调小
- 桌面原型 settings 补「编号规则」面板+编辑弹窗、m-settings 改准;atoms 去数字框原生箭头
- 同步 CONTRACT / screens.mjs / db-schema.html 与 settings fidelity 基准

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bupi8Kdqkfx2N5acFsHTx5
2026-09-02 21:30:10 +08:00

90 lines
2.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
class NumberRule {
final int id;
final String type;
final String prefix;
/// 编号模式:date_seq=日期+序号(3 位,按 dateFormat 周期重置)| seq=连续序号(6 位,不重置)
final String mode;
final int currentNo;
final String dateFormat;
/// date_seq 当前序号所属的日期串(如 "20260902"),用于示例的跨周期重置判断;seq 模式为空。
final String seqPeriod;
const NumberRule({
required this.id,
required this.type,
required this.prefix,
required this.mode,
required this.currentNo,
required this.dateFormat,
required this.seqPeriod,
});
String get typeLabel {
switch (type) {
case 'stock_in':
return '入库单';
case 'stock_out':
return '出库单';
case 'inventory_check':
return '盘点单';
case 'product':
return '商品编码';
default:
return type;
}
}
bool get isSeq => mode == 'seq';
String get modeLabel => isSeq ? '连续序号' : '日期 + 序号';
/// 展示用「当前序号」:
/// seq → 原值(连续累计)。
/// date_seq → 本周期已开始(seqPeriod==今天) 显示本周期计数,否则显示 0
/// (今天还没生成过,下一张就是 001,故当前=0)。
int get effectiveCurrentNo {
if (isSeq) return currentNo;
return dateStr(dateFormat, DateTime.now()) == seqPeriod ? currentNo : 0;
}
/// 按 dateFormat 生成当天日期串(与后端 formatByRule 一致)。
static String dateStr(String fmt, DateTime now) {
final y4 = now.year.toString().padLeft(4, '0');
final y2 = (now.year % 100).toString().padLeft(2, '0');
final mo = now.month.toString().padLeft(2, '0');
final d = now.day.toString().padLeft(2, '0');
switch (fmt) {
case 'YYYYMM':
return '$y4$mo';
case 'YYMMDD':
return '$y2$mo$d';
default: // YYYYMMDD 及未知
return '$y4$mo$d';
}
}
/// 下一编号示例(与后端 advanceNumberRule 口径一致):
/// seq → 前缀 + 6 位连续序号(如 DS031115
/// date_seq → 前缀 + 日期串 + 3 位序号;跨日期周期时序号从 001 起
String get exampleNo {
if (isSeq) {
return '$prefix${(currentNo + 1).toString().padLeft(6, '0')}';
}
final ds = dateStr(dateFormat, DateTime.now());
final next = (ds == seqPeriod) ? currentNo + 1 : 1;
return '$prefix$ds${next.toString().padLeft(3, '0')}';
}
factory NumberRule.fromJson(Map<String, dynamic> json) => NumberRule(
id: (json['id'] as num).toInt(),
type: json['type'] as String,
prefix: json['prefix'] as String? ?? '',
mode: json['mode'] as String? ?? 'date_seq',
currentNo: (json['current_no'] as num).toInt(),
dateFormat: json['date_format'] as String? ?? 'YYYYMMDD',
seqPeriod: json['seq_period'] as String? ?? '',
);
}