feat: 饭卡打印助手 Flutter 版(Phase 1/2:协议服务器 + macOS CUPS 真机打印)
- 协议与 C# 版 card-printer-agent 逐字段对齐(38200-38202 顺延、CORS *、串行任务队列、30 分钟保留) - macOS CUPS 后端:lpoptions 队列发现 + lp 参数列表提交(LC_ALL=C 防本地化粘连坑) - --mock 模拟模式 + bin/agent.dart headless 入口 + 测试卡生成工具 - 真机验收:HiTi CS-200e status 就绪 + 真实出卡;macOS 通用二进制构建通过 - App Sandbox 已关闭(服务需绑回环端口并调用 lp 子进程);zaxprint URL scheme 已注册
This commit is contained in:
commit
689a07ca44
46 files changed
+2986
No files matched your search
@@ -0,0 +1,134 @@
|
||||
/// 与前端 `biz-pc-cloud-zax/src/api/plugin/cardPrinter.ts` 约定的协议 DTO。
|
||||
///
|
||||
/// 字段序列化一律 camelCase,响应统一信封 `{code, msg, data}`(code=0 成功),
|
||||
/// 与 C# 版 card-printer-agent 的 ApiModels.cs 逐字段对齐。
|
||||
library;
|
||||
|
||||
class ManifestPlugin {
|
||||
ManifestPlugin({this.id = 'card-printer', this.name = '卡片打印机', this.version = '1.0.0'});
|
||||
|
||||
final String id;
|
||||
final String name;
|
||||
final String version;
|
||||
|
||||
Map<String, dynamic> toJson() => {'id': id, 'name': name, 'version': version};
|
||||
}
|
||||
|
||||
class RibbonInfo {
|
||||
RibbonInfo({this.type = '', this.remain = -1, this.remainCount = -1});
|
||||
|
||||
/// 色带类型名(如 YMCKO),未知空串
|
||||
String type;
|
||||
|
||||
/// 色带余量百分比 0~100,未知 -1(按常见 100 张装色带折算)
|
||||
int remain;
|
||||
|
||||
/// 色带剩余张数(设备原始值),未知 -1
|
||||
int remainCount;
|
||||
|
||||
Map<String, dynamic> toJson() => {'type': type, 'remain': remain, 'remainCount': remainCount};
|
||||
}
|
||||
|
||||
/// GET /api/card-printer/status 响应
|
||||
class PrinterStatus {
|
||||
PrinterStatus({
|
||||
this.online = false,
|
||||
this.model = '',
|
||||
this.firmware = '',
|
||||
this.connection = 'USB',
|
||||
RibbonInfo? ribbon,
|
||||
this.cardLow = false,
|
||||
this.cardLeft = -1,
|
||||
this.status = 0,
|
||||
this.statusText = '',
|
||||
}) : ribbon = ribbon ?? RibbonInfo();
|
||||
|
||||
bool online;
|
||||
String model;
|
||||
String firmware;
|
||||
|
||||
/// USB / IP
|
||||
String connection;
|
||||
RibbonInfo ribbon;
|
||||
|
||||
/// 卡量是否不足
|
||||
bool cardLow;
|
||||
|
||||
/// 剩余卡量(张),未知 -1
|
||||
int cardLeft;
|
||||
|
||||
/// HiTi 设备状态码,0 = 就绪
|
||||
int status;
|
||||
String statusText;
|
||||
|
||||
/// 打印机已断开/未连接的通用离线态
|
||||
factory PrinterStatus.offline(String statusText) => PrinterStatus(
|
||||
online: false,
|
||||
status: 0x00000080,
|
||||
statusText: statusText,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'online': online,
|
||||
'model': model,
|
||||
'firmware': firmware,
|
||||
'connection': connection,
|
||||
'ribbon': ribbon.toJson(),
|
||||
'cardLow': cardLow,
|
||||
'cardLeft': cardLeft,
|
||||
'status': status,
|
||||
'statusText': statusText,
|
||||
};
|
||||
}
|
||||
|
||||
/// 单面打印图:color 必传,k 为可选树脂黑文字层
|
||||
class CardSideImage {
|
||||
CardSideImage({required this.color, this.k});
|
||||
|
||||
/// 1014×642 彩色层 PNG data URL
|
||||
final String color;
|
||||
|
||||
/// 8bit 灰度树脂 K 文字层 PNG data URL,白底黑字
|
||||
final String? k;
|
||||
|
||||
factory CardSideImage.fromJson(Map<String, dynamic> json) => CardSideImage(
|
||||
color: json['color'] as String? ?? '',
|
||||
k: json['k'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
/// POST /api/card-printer/print 请求
|
||||
class PrintRequest {
|
||||
PrintRequest({this.copies = 1, this.front, this.back});
|
||||
|
||||
final int copies;
|
||||
final CardSideImage? front;
|
||||
final CardSideImage? back;
|
||||
|
||||
factory PrintRequest.fromJson(Map<String, dynamic> json) {
|
||||
CardSideImage? side(Object? raw) =>
|
||||
raw is Map<String, dynamic> ? CardSideImage.fromJson(raw) : null;
|
||||
return PrintRequest(
|
||||
copies: (json['copies'] as num?)?.toInt() ?? 1,
|
||||
front: side(json['front']),
|
||||
back: side(json['back']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// GET /api/card-printer/task/{taskId} 响应
|
||||
class PrintTaskDto {
|
||||
PrintTaskDto({required this.taskId, this.state = 'printing', this.status = 0, this.statusText = ''});
|
||||
|
||||
final String taskId;
|
||||
|
||||
/// printing / done / error
|
||||
final String state;
|
||||
final int status;
|
||||
|
||||
/// error 态时携带错误文案
|
||||
final String statusText;
|
||||
|
||||
Map<String, dynamic> toJson() =>
|
||||
{'taskId': taskId, 'state': state, 'status': status, 'statusText': statusText};
|
||||
}
|
||||
Reference in new issue
Block a user