feat: 实现用户画像、占卜历史与后端用户管理模块

This commit is contained in:
ZL-Q
2026-04-06 01:28:10 +08:00
parent d87b2e1e3a
commit 8a18b3528b
77 changed files with 5850 additions and 2604 deletions
@@ -60,6 +60,21 @@ class DivinationParams {
};
}
factory DivinationParams.fromPayload(Map<String, dynamic> payload) {
return DivinationParams(
method: divinationMethodFromName(_requiredString(payload, 'method')),
questionType: questionTypeFromName(
_requiredString(payload, 'questionType'),
),
question: _requiredString(payload, 'question'),
divinationTime: DateTime.parse(
_requiredString(payload, 'divinationTime'),
),
coinBalance: _requiredInt(payload, 'coinBalance'),
userId: _requiredString(payload, 'userId'),
);
}
String toBinary(List<YaoType> yaoStates) {
return yaoStates
.map(
@@ -85,3 +100,43 @@ class DivinationParams {
.join();
}
}
DivinationMethod divinationMethodFromName(String raw) {
return DivinationMethod.values.firstWhere(
(value) => value.name == raw,
orElse: () => DivinationMethod.manual,
);
}
QuestionType questionTypeFromName(String raw) {
return QuestionType.values.firstWhere(
(value) => value.name == raw,
orElse: () => QuestionType.other,
);
}
YaoType yaoTypeFromName(String raw) {
return YaoType.values.firstWhere(
(value) => value.name == raw,
orElse: () => YaoType.undetermined,
);
}
String _requiredString(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is! String || value.isEmpty) {
throw FormatException('Missing required string: $key');
}
return value;
}
int _requiredInt(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is int) {
return value;
}
if (value is num) {
return value.toInt();
}
throw FormatException('Missing required int: $key');
}
@@ -38,6 +38,79 @@ class DivinationResultData {
final List<YaoLineData> targetYaoLines;
bool get hasChangingYao => binaryCode != changedBinaryCode;
Map<String, dynamic> toJson() {
return <String, dynamic>{
'params': params.toPayload(),
'binaryCode': binaryCode,
'changedBinaryCode': changedBinaryCode,
'guaName': guaName,
'targetGuaName': targetGuaName,
'upperName': upperName,
'lowerName': lowerName,
'signType': signType,
'keywords': keywords,
'conclusion': conclusion,
'analysis': analysis,
'suggestion': suggestion,
'ganzhi': ganzhi.toJson(),
'wuXingStatus': wuXingStatus,
'yaoLines': yaoLines.map((line) => line.toJson()).toList(growable: false),
'targetYaoLines': targetYaoLines
.map((line) => line.toJson())
.toList(growable: false),
};
}
factory DivinationResultData.fromJson(Map<String, dynamic> json) {
final paramsRaw = json['params'];
final ganzhiRaw = json['ganzhi'];
final wuXingRaw = json['wuXingStatus'];
final yaoLinesRaw = json['yaoLines'];
final targetYaoLinesRaw = json['targetYaoLines'];
if (paramsRaw is! Map<String, dynamic> ||
ganzhiRaw is! Map<String, dynamic> ||
wuXingRaw is! Map<String, dynamic> ||
yaoLinesRaw is! List<dynamic> ||
targetYaoLinesRaw is! List<dynamic>) {
throw const FormatException('Invalid divination result payload');
}
return DivinationResultData(
params: DivinationParams.fromPayload(paramsRaw),
binaryCode: _requiredString(json, 'binaryCode'),
changedBinaryCode: _requiredString(json, 'changedBinaryCode'),
guaName: _requiredString(json, 'guaName'),
targetGuaName: _requiredString(json, 'targetGuaName'),
upperName: _requiredString(json, 'upperName'),
lowerName: _requiredString(json, 'lowerName'),
signType: _requiredString(json, 'signType'),
keywords: _requiredString(json, 'keywords'),
conclusion: _requiredString(json, 'conclusion'),
analysis: _requiredString(json, 'analysis'),
suggestion: _requiredString(json, 'suggestion'),
ganzhi: GanzhiData.fromJson(ganzhiRaw),
wuXingStatus: wuXingRaw.map(
(key, value) => MapEntry(key, value.toString()),
),
yaoLines: yaoLinesRaw
.map((raw) {
if (raw is! Map<String, dynamic>) {
throw const FormatException('Invalid yao line payload');
}
return YaoLineData.fromJson(raw);
})
.toList(growable: false),
targetYaoLines: targetYaoLinesRaw
.map((raw) {
if (raw is! Map<String, dynamic>) {
throw const FormatException('Invalid target yao line payload');
}
return YaoLineData.fromJson(raw);
})
.toList(growable: false),
);
}
}
class GanzhiData {
@@ -68,6 +141,40 @@ class GanzhiData {
final String riChen;
final String yuePo;
final String riChong;
Map<String, dynamic> toJson() {
return <String, dynamic>{
'yearGanZhi': yearGanZhi,
'monthGanZhi': monthGanZhi,
'dayGanZhi': dayGanZhi,
'timeGanZhi': timeGanZhi,
'yearKongWang': yearKongWang,
'monthKongWang': monthKongWang,
'dayKongWang': dayKongWang,
'timeKongWang': timeKongWang,
'yueJian': yueJian,
'riChen': riChen,
'yuePo': yuePo,
'riChong': riChong,
};
}
factory GanzhiData.fromJson(Map<String, dynamic> json) {
return GanzhiData(
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'),
);
}
}
class YaoLineData {
@@ -88,4 +195,47 @@ class YaoLineData {
final String element;
final YaoType type;
final String mark;
Map<String, dynamic> toJson() {
return <String, dynamic>{
'index': index,
'spirit': spirit,
'relation': relation,
'branch': branch,
'element': element,
'type': type.name,
'mark': mark,
};
}
factory YaoLineData.fromJson(Map<String, dynamic> json) {
return YaoLineData(
index: _requiredInt(json, 'index'),
spirit: _requiredString(json, 'spirit'),
relation: _requiredString(json, 'relation'),
branch: _requiredString(json, 'branch'),
element: _requiredString(json, 'element'),
type: yaoTypeFromName(_requiredString(json, 'type')),
mark: _requiredString(json, 'mark'),
);
}
}
String _requiredString(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is! String || value.isEmpty) {
throw FormatException('Missing required string: $key');
}
return value;
}
int _requiredInt(Map<String, dynamic> json, String key) {
final value = json[key];
if (value is int) {
return value;
}
if (value is num) {
return value.toInt();
}
throw FormatException('Missing required int: $key');
}