Files
eryao/apps/lib/features/divination/data/models/divination_backend_models.dart
T
qzl e80a82bef4 docs: 更新协议文档,删除废弃计划文档
- 更新 http-error-codes, user-points-chat-data-protocol
- 更新 divination-run-protocol, profile-protocol
- 删除废弃的后端和前端设计计划文档
2026-04-08 17:23:02 +08:00

350 lines
10 KiB
Dart

import 'divination_params.dart';
import 'divination_result.dart';
class PointsBalanceData {
const PointsBalanceData({
required this.balance,
required this.frozenBalance,
required this.availableBalance,
required this.runCost,
required this.canRun,
});
factory PointsBalanceData.fromJson(Map<String, dynamic> json) {
return PointsBalanceData(
balance: _requiredInt(json, 'balance'),
frozenBalance: _requiredInt(json, 'frozenBalance'),
availableBalance: _requiredInt(json, 'availableBalance'),
runCost: _requiredInt(json, 'runCost'),
canRun: _requiredBool(json, 'canRun'),
);
}
final int balance;
final int frozenBalance;
final int availableBalance;
final int runCost;
final bool canRun;
}
class RunAcceptedData {
const RunAcceptedData({
required this.taskId,
required this.threadId,
required this.runId,
required this.created,
});
factory RunAcceptedData.fromJson(Map<String, dynamic> json) {
return RunAcceptedData(
taskId: _requiredString(json, 'taskId'),
threadId: _requiredString(json, 'threadId'),
runId: _requiredString(json, 'runId'),
created: _requiredBool(json, 'created'),
);
}
final String taskId;
final String threadId;
final String runId;
final bool created;
}
class DivinationRunAggregate {
const DivinationRunAggregate({
this.threadId,
required this.derived,
required this.signLevel,
required this.conclusion,
required this.focusPoints,
required this.advice,
required this.keywords,
required this.answer,
});
final DerivedDivinationData derived;
final String? threadId;
final String signLevel;
final List<String> conclusion;
final List<String> focusPoints;
final List<String> advice;
final List<String> keywords;
final String answer;
DivinationResultData toViewData(DivinationParams params) {
return DivinationResultData(
params: params,
threadId: threadId,
binaryCode: derived.binaryCode,
changedBinaryCode: derived.changedBinaryCode,
guaName: derived.guaName,
targetGuaName: derived.targetGuaName,
upperName: derived.upperName,
lowerName: derived.lowerName,
signType: signLevel,
keywords: keywords.join(''),
focusPoints: focusPoints,
conclusion: _asBullet(conclusion),
analysis: answer,
suggestion: _asBullet(advice),
ganzhi: GanzhiData(
yearGanZhi: derived.ganzhi.yearGanZhi,
monthGanZhi: derived.ganzhi.monthGanZhi,
dayGanZhi: derived.ganzhi.dayGanZhi,
timeGanZhi: derived.ganzhi.timeGanZhi,
yearKongWang: derived.ganzhi.yearKongWang,
monthKongWang: derived.ganzhi.monthKongWang,
dayKongWang: derived.ganzhi.dayKongWang,
timeKongWang: derived.ganzhi.timeKongWang,
yueJian: derived.ganzhi.yueJian,
riChen: derived.ganzhi.riChen,
yuePo: derived.ganzhi.yuePo,
riChong: derived.ganzhi.riChong,
),
wuXingStatus: derived.wuXingStatuses,
yaoLines: derived.yaoInfoList
.map((line) => line.toViewModel())
.toList(growable: false),
targetYaoLines: derived.targetYaoInfoList
.map((line) => line.toViewModel())
.toList(growable: false),
);
}
String _asBullet(List<String> lines) {
if (lines.isEmpty) {
return '';
}
return List<String>.generate(
lines.length,
(i) => '${i + 1}. ${lines[i]}',
growable: false,
).join('\n');
}
}
class DerivedDivinationData {
const DerivedDivinationData({
required this.question,
required this.questionType,
required this.divinationMethod,
required this.divinationTime,
required this.binaryCode,
required this.changedBinaryCode,
required this.guaName,
required this.upperName,
required this.lowerName,
required this.targetGuaName,
required this.worldPosition,
required this.responsePosition,
required this.hasChangingYao,
required this.ganzhi,
required this.wuXingStatuses,
required this.yaoInfoList,
required this.targetYaoInfoList,
});
factory DerivedDivinationData.fromJson(Map<String, dynamic> json) {
final wuXingRaw = _requiredMap(json, 'wuXingStatuses');
return DerivedDivinationData(
question: _requiredString(json, 'question'),
questionType: _requiredString(json, 'questionType'),
divinationMethod: _requiredString(json, 'divinationMethod'),
divinationTime: _requiredString(json, 'divinationTime'),
binaryCode: _requiredString(json, 'binaryCode'),
changedBinaryCode: _requiredString(json, 'changedBinaryCode'),
guaName: _requiredString(json, 'guaName'),
upperName: _requiredString(json, 'upperName'),
lowerName: _requiredString(json, 'lowerName'),
targetGuaName: _requiredString(json, 'targetGuaName'),
worldPosition: _requiredInt(json, 'worldPosition'),
responsePosition: _requiredInt(json, 'responsePosition'),
hasChangingYao: _requiredBool(json, 'hasChangingYao'),
ganzhi: GanzhiBackend.fromJson(_requiredMap(json, 'ganzhi')),
wuXingStatuses: wuXingRaw.map(
(key, value) => MapEntry(key, value.toString()),
),
yaoInfoList: _parseYaoList(json['yaoInfoList']),
targetYaoInfoList: _parseYaoList(json['targetYaoInfoList']),
);
}
final String question;
final String questionType;
final String divinationMethod;
final String divinationTime;
final String binaryCode;
final String changedBinaryCode;
final String guaName;
final String upperName;
final String lowerName;
final String targetGuaName;
final int worldPosition;
final int responsePosition;
final bool hasChangingYao;
final GanzhiBackend ganzhi;
final Map<String, String> wuXingStatuses;
final List<YaoBackendLine> yaoInfoList;
final List<YaoBackendLine> targetYaoInfoList;
static List<YaoBackendLine> _parseYaoList(Object? raw) {
final list = raw as List<dynamic>?;
if (list == null) {
throw const FormatException(
'Missing required list: yaoInfoList/targetYaoInfoList',
);
}
return list
.map((item) {
if (item is! Map<String, dynamic>) {
throw const FormatException('Invalid yao line item');
}
return YaoBackendLine.fromJson(item);
})
.toList(growable: false);
}
}
class GanzhiBackend {
const GanzhiBackend({
required this.yearGanZhi,
required this.monthGanZhi,
required this.dayGanZhi,
required this.timeGanZhi,
required this.yearKongWang,
required this.monthKongWang,
required this.dayKongWang,
required this.timeKongWang,
required this.yueJian,
required this.riChen,
required this.yuePo,
required this.riChong,
});
factory GanzhiBackend.fromJson(Map<String, dynamic> json) {
return GanzhiBackend(
yearGanZhi: _requiredString(json, 'yearGanZhi'),
monthGanZhi: _requiredString(json, 'monthGanZhi'),
dayGanZhi: _requiredString(json, 'dayGanZhi'),
timeGanZhi: _requiredString(json, 'timeGanZhi'),
yearKongWang: _requiredString(json, 'yearKongWang'),
monthKongWang: _requiredString(json, 'monthKongWang'),
dayKongWang: _requiredString(json, 'dayKongWang'),
timeKongWang: _requiredString(json, 'timeKongWang'),
yueJian: _requiredString(json, 'yueJian'),
riChen: _requiredString(json, 'riChen'),
yuePo: _requiredString(json, 'yuePo'),
riChong: _requiredString(json, 'riChong'),
);
}
final String yearGanZhi;
final String monthGanZhi;
final String dayGanZhi;
final String timeGanZhi;
final String yearKongWang;
final String monthKongWang;
final String dayKongWang;
final String timeKongWang;
final String yueJian;
final String riChen;
final String yuePo;
final String riChong;
}
class YaoBackendLine {
const YaoBackendLine({
required this.position,
required this.spiritName,
required this.relationName,
required this.tiganName,
required this.elementName,
required this.isYang,
required this.isChanging,
required this.specialMark,
});
factory YaoBackendLine.fromJson(Map<String, dynamic> json) {
return YaoBackendLine(
position: _requiredInt(json, 'position'),
spiritName: _requiredString(json, 'spiritName'),
relationName: _requiredString(json, 'relationName'),
tiganName: _requiredString(json, 'tiganName'),
elementName: _requiredString(json, 'elementName'),
isYang: _requiredBool(json, 'isYang'),
isChanging: _requiredBool(json, 'isChanging'),
specialMark: _requiredStringAllowEmpty(json, 'specialMark'),
);
}
final int position;
final String spiritName;
final String relationName;
final String tiganName;
final String elementName;
final bool isYang;
final bool isChanging;
final String specialMark;
YaoLineData toViewModel() {
final type = switch ((isYang, isChanging)) {
(true, false) => YaoType.youngYang,
(false, false) => YaoType.youngYin,
(true, true) => YaoType.oldYang,
(false, true) => YaoType.oldYin,
};
return YaoLineData(
index: position - 1,
spirit: spiritName,
relation: relationName,
branch: tiganName,
element: elementName,
type: type,
mark: specialMark,
);
}
}
String _requiredStringAllowEmpty(Map<String, dynamic> json, String key) {
if (!json.containsKey(key)) {
throw FormatException('Invalid or missing field: $key');
}
final value = json[key];
if (value is! String) {
throw FormatException('Invalid or missing field: $key');
}
return value;
}
String _requiredString(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is! String || value.isEmpty) {
throw FormatException('Invalid or missing field: $key');
}
return value;
}
int _requiredInt(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is! num) {
throw FormatException('Invalid or missing field: $key');
}
return value.toInt();
}
bool _requiredBool(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is! bool) {
throw FormatException('Invalid or missing field: $key');
}
return value;
}
Map<String, dynamic> _requiredMap(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is! Map<String, dynamic>) {
throw FormatException('Invalid or missing field: $key');
}
return value;
}