feat: 接入起卦后端流程并完善积分扣减链路
This commit is contained in:
@@ -14,6 +14,8 @@ from pydantic import (
|
||||
field_validator,
|
||||
)
|
||||
|
||||
from ..domain.divination import DivinationPayload
|
||||
|
||||
_RFC3339_WITH_TZ_PATTERN = re.compile(
|
||||
r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$"
|
||||
)
|
||||
@@ -69,6 +71,9 @@ class ForwardedPropsPayload(BaseModel):
|
||||
|
||||
runtime_mode: RuntimeMode
|
||||
client_time: ClientTimeContext | None = None
|
||||
divination_payload: DivinationPayload | None = Field(
|
||||
default=None, alias="divinationPayload"
|
||||
)
|
||||
|
||||
|
||||
def parse_forwarded_props(forwarded_props: object) -> ForwardedPropsPayload:
|
||||
@@ -90,3 +95,10 @@ def parse_forwarded_props_client_time(
|
||||
def parse_forwarded_props_runtime_mode(forwarded_props: object) -> RuntimeMode:
|
||||
payload = parse_forwarded_props(forwarded_props)
|
||||
return payload.runtime_mode
|
||||
|
||||
|
||||
def parse_forwarded_props_divination_payload(
|
||||
forwarded_props: object,
|
||||
) -> DivinationPayload | None:
|
||||
payload = parse_forwarded_props(forwarded_props)
|
||||
return payload.divination_payload
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
|
||||
class DivinationMethod(str, Enum):
|
||||
MANUAL = "手动起卦"
|
||||
AUTO = "自动起卦"
|
||||
|
||||
|
||||
class YaoType(str, Enum):
|
||||
SHAO_YANG = "少阳"
|
||||
SHAO_YIN = "少阴"
|
||||
LAO_YANG = "老阳"
|
||||
LAO_YIN = "老阴"
|
||||
|
||||
|
||||
class SpecialMark(str, Enum):
|
||||
SHI = "世"
|
||||
YING = "应"
|
||||
NONE = ""
|
||||
|
||||
|
||||
class YaoDetail(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
position: int = Field(ge=1, le=6)
|
||||
spirit_name: str = Field(alias="spiritName", min_length=1)
|
||||
relation_name: str = Field(alias="relationName", min_length=1)
|
||||
tigan_name: str = Field(alias="tiganName", min_length=1)
|
||||
element_name: str = Field(alias="elementName", min_length=1)
|
||||
is_yang: bool = Field(alias="isYang")
|
||||
is_changing: bool = Field(alias="isChanging")
|
||||
special_mark: SpecialMark = Field(alias="specialMark", default=SpecialMark.NONE)
|
||||
|
||||
|
||||
class FushenDetail(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
position: int = Field(ge=1, le=6)
|
||||
relation_name: str = Field(alias="relationName", min_length=1)
|
||||
tigan_name: str = Field(alias="tiganName", min_length=1)
|
||||
element_name: str = Field(alias="elementName", min_length=1)
|
||||
|
||||
|
||||
class GanzhiDetail(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
year_gan_zhi: str = Field(alias="yearGanZhi", min_length=2, max_length=2)
|
||||
month_gan_zhi: str = Field(alias="monthGanZhi", min_length=2, max_length=2)
|
||||
day_gan_zhi: str = Field(alias="dayGanZhi", min_length=2, max_length=2)
|
||||
time_gan_zhi: str = Field(alias="timeGanZhi", min_length=2, max_length=2)
|
||||
year_kong_wang: str = Field(alias="yearKongWang", min_length=2, max_length=2)
|
||||
month_kong_wang: str = Field(alias="monthKongWang", min_length=2, max_length=2)
|
||||
day_kong_wang: str = Field(alias="dayKongWang", min_length=2, max_length=2)
|
||||
time_kong_wang: str = Field(alias="timeKongWang", min_length=2, max_length=2)
|
||||
yue_jian: str = Field(alias="yueJian", min_length=2)
|
||||
ri_chen: str = Field(alias="riChen", min_length=2)
|
||||
yue_po: str = Field(alias="yuePo", min_length=2)
|
||||
ri_chong: str = Field(alias="riChong", min_length=2)
|
||||
|
||||
|
||||
class DivinationPayload(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
||||
|
||||
divination_method: DivinationMethod = Field(alias="divinationMethod")
|
||||
question_type: str = Field(alias="questionType", min_length=1, max_length=32)
|
||||
question: str = Field(min_length=1, max_length=300)
|
||||
divination_time_iso: str = Field(alias="divinationTimeIso", min_length=20)
|
||||
yao_lines: list[YaoType] = Field(alias="yaoLines", min_length=6, max_length=6)
|
||||
|
||||
@field_validator("divination_time_iso")
|
||||
@classmethod
|
||||
def validate_divination_time_iso(cls, value: str) -> str:
|
||||
normalized = value.replace("Z", "+00:00")
|
||||
dt = datetime.fromisoformat(normalized)
|
||||
if dt.tzinfo is None:
|
||||
raise ValueError("divinationTimeIso must include timezone")
|
||||
return value
|
||||
|
||||
|
||||
class DerivedDivinationData(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
||||
|
||||
question: str = Field(min_length=1)
|
||||
question_type: str = Field(alias="questionType", min_length=1)
|
||||
divination_method: DivinationMethod = Field(alias="divinationMethod")
|
||||
divination_time: str = Field(alias="divinationTime", min_length=1)
|
||||
binary_code: str = Field(alias="binaryCode", min_length=6, max_length=6)
|
||||
changed_binary_code: str = Field(
|
||||
alias="changedBinaryCode", min_length=6, max_length=6
|
||||
)
|
||||
gua_name: str = Field(alias="guaName", min_length=2)
|
||||
upper_name: str = Field(alias="upperName", min_length=1)
|
||||
lower_name: str = Field(alias="lowerName", min_length=1)
|
||||
target_gua_name: str = Field(alias="targetGuaName", min_length=2)
|
||||
world_position: int = Field(alias="worldPosition", ge=1, le=6)
|
||||
response_position: int = Field(alias="responsePosition", ge=1, le=6)
|
||||
has_changing_yao: bool = Field(alias="hasChangingYao")
|
||||
ganzhi: GanzhiDetail
|
||||
wu_xing_statuses: dict[str, str] = Field(alias="wuXingStatuses")
|
||||
yao_info_list: list[YaoDetail] = Field(
|
||||
alias="yaoInfoList", min_length=6, max_length=6
|
||||
)
|
||||
target_yao_info_list: list[YaoDetail] = Field(
|
||||
alias="targetYaoInfoList", default_factory=list
|
||||
)
|
||||
fushen_positions: list[int] = Field(alias="fushenPositions", default_factory=list)
|
||||
fushen_info_list: list[FushenDetail] = Field(
|
||||
alias="fushenInfoList", default_factory=list
|
||||
)
|
||||
Reference in New Issue
Block a user