From 55ae8b2acddfc8432526725053e356bba73936ba Mon Sep 17 00:00:00 2001 From: Austin Date: Thu, 8 Oct 2026 12:47:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(cultivate-flower):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=AD=89=E5=BE=85=E6=97=B6=E9=95=BF=E5=AD=97=E6=AE=B5=E5=B9=B6?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=98=B6=E6=AE=B5=E8=A7=84=E5=88=99=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...vate-Server管理后台内部接口开发对接文档.md | 3 +- server/internal/logic/sys/cultivate_flower.go | 5 ++-- .../model/input/sysin/cultivate_flower.go | 5 ++-- web/src/views/cultivate/flowers/edit.vue | 5 ++-- web/src/views/cultivate/flowers/model.ts | 30 ++++++++++++++----- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/docs/im/Cultivate-Server管理后台内部接口开发对接文档.md b/docs/im/Cultivate-Server管理后台内部接口开发对接文档.md index 81d63ca..e1550cf 100644 --- a/docs/im/Cultivate-Server管理后台内部接口开发对接文档.md +++ b/docs/im/Cultivate-Server管理后台内部接口开发对接文档.md @@ -292,6 +292,7 @@ Query 参数: "required_points": 10, "water_points": 2, "fertilize_points": 3, + "wait_hours": 36, "allowed_actions": ["water", "fertilize"], "image_file_id": "file_xxx", "animation_file_id": "file_xxx", @@ -329,7 +330,7 @@ Query 参数: - 状态枚举:`online`、`offline`、`activity_only`、`maintenance`。 - 阶段枚举:`seed`、`sprout`、`bud`、`bloom`。 - 阶段链必须从 `seed` 连续配置并以 `bloom` 结束,不能重复或成环。 -- 非 `bloom` 阶段 `required_points > 0`,且至少允许一个动作。 +- 非 `bloom` 阶段 `required_points` 与 `wait_hours` 不能同时为 0(2026-10-08 起:升级条件 = 积分就绪 AND 等待就绪,允许纯积分或纯等待阶段),且至少允许一个动作。 - 动作枚举:`water`、`fertilize`。 - 文件 ID 必须通过 IM 内部文件校验,风险或待审核素材不能保存。 - 花种和阶段规则必须在一个数据库事务内保存。 diff --git a/server/internal/logic/sys/cultivate_flower.go b/server/internal/logic/sys/cultivate_flower.go index 9aad44b..1ab3bf7 100644 --- a/server/internal/logic/sys/cultivate_flower.go +++ b/server/internal/logic/sys/cultivate_flower.go @@ -51,6 +51,7 @@ type cultivateStageRuleDTO struct { RequiredPoints uint `json:"requiredPoints"` WaterPoints uint `json:"waterPoints"` FertilizePoints uint `json:"fertilizePoints"` + WaitHours uint `json:"waitHours"` AllowedActions []string `json:"allowedActions"` ImageFileID string `json:"imageFileId"` AnimationFileID string `json:"animationFileId"` @@ -182,7 +183,7 @@ func flowerPayload(in *sysin.CultivateFlowerEditInp) map[string]any { rules = append(rules, map[string]any{ "id": strconv.FormatUint(rule.Id, 10), "stage": rule.Stage, "next_stage": rule.NextStage, "required_points": rule.RequiredPoints, "water_points": rule.WaterPoints, "fertilize_points": rule.FertilizePoints, - "allowed_actions": rule.AllowedActions, "image_file_id": rule.ImageFileId, "animation_file_id": rule.AnimationFileId, + "wait_hours": rule.WaitHours, "allowed_actions": rule.AllowedActions, "image_file_id": rule.ImageFileId, "animation_file_id": rule.AnimationFileId, "progress_text_template": rule.ProgressTextTemplate, "completion_text": rule.CompletionText, "sort_no": rule.SortNo, }) } @@ -227,7 +228,7 @@ func flowerViewModel(item *cultivateFlowerDTO) (*sysin.CultivateFlowerViewModel, } result.StageRules = append(result.StageRules, &sysin.CultivateStageRuleEditInp{ Id: id, Stage: rule.Stage, NextStage: rule.NextStage, RequiredPoints: rule.RequiredPoints, - WaterPoints: rule.WaterPoints, FertilizePoints: rule.FertilizePoints, AllowedActions: rule.AllowedActions, + WaterPoints: rule.WaterPoints, FertilizePoints: rule.FertilizePoints, WaitHours: rule.WaitHours, AllowedActions: rule.AllowedActions, ImageFileId: rule.ImageFileID, AnimationFileId: rule.AnimationFileID, ProgressTextTemplate: rule.ProgressTextTemplate, CompletionText: rule.CompletionText, SortNo: rule.SortNo, }) diff --git a/server/internal/model/input/sysin/cultivate_flower.go b/server/internal/model/input/sysin/cultivate_flower.go index c0764b7..95fad84 100644 --- a/server/internal/model/input/sysin/cultivate_flower.go +++ b/server/internal/model/input/sysin/cultivate_flower.go @@ -18,6 +18,7 @@ type CultivateStageRuleEditInp struct { RequiredPoints uint `json:"requiredPoints"` WaterPoints uint `json:"waterPoints"` FertilizePoints uint `json:"fertilizePoints"` + WaitHours uint `json:"waitHours"` AllowedActions []string `json:"allowedActions"` ImageFileId string `json:"imageFileId"` AnimationFileId string `json:"animationFileId"` @@ -64,8 +65,8 @@ func (in *CultivateFlowerEditInp) Filter(ctx context.Context) error { return gerror.New("成长阶段不能重复") } seen[rule.Stage] = true - if rule.Stage != "bloom" && rule.RequiredPoints == 0 { - return gerror.New("非开花阶段升级阈值必须大于0") + if rule.Stage != "bloom" && rule.RequiredPoints == 0 && rule.WaitHours == 0 { + return gerror.New("非开花阶段必须配置升级阈值或等待时长") } if rule.NextStage != "" && !validStage[rule.NextStage] { return gerror.New("下一阶段不正确") diff --git a/web/src/views/cultivate/flowers/edit.vue b/web/src/views/cultivate/flowers/edit.vue index a24da02..8e07473 100644 --- a/web/src/views/cultivate/flowers/edit.vue +++ b/web/src/views/cultivate/flowers/edit.vue @@ -17,6 +17,7 @@ + @@ -35,10 +36,10 @@ import { ref } from 'vue'; import { useMessage } from 'naive-ui'; import { Edit, View } from '@/api/cultivate/flowers'; -import { actionOptions, newState, rules, State, statusOptions } from './model'; +import { actionOptions, newState, rules, State, statusOptions, validateStageRules } from './model'; const emit=defineEmits(['reloadTable']);const message=useMessage();const showModal=ref(false);const loading=ref(false);const submitting=ref(false);const formRef=ref();const formValue=ref(newState(null)); function openModal(state:State|null){showModal.value=true;formValue.value=newState(null);if(!state?.id)return;loading.value=true;View({id:state.id}).then((res)=>formValue.value=newState(res)).finally(()=>loading.value=false)} -function submit(){formRef.value?.validate((errors)=>{if(errors){message.error('请检查配置内容');return}submitting.value=true;Edit(formValue.value).then(()=>{message.success('配置已保存');showModal.value=false;emit('reloadTable')}).finally(()=>submitting.value=false)})} +function submit(){formRef.value?.validate((errors)=>{if(errors){message.error('请检查配置内容');return}const stageError=validateStageRules(formValue.value.stageRules);if(stageError){message.error(stageError);return}submitting.value=true;Edit(formValue.value).then(()=>{message.success('配置已保存');showModal.value=false;emit('reloadTable')}).finally(()=>submitting.value=false)})} defineExpose({openModal}); diff --git a/web/src/views/cultivate/flowers/model.ts b/web/src/views/cultivate/flowers/model.ts index 715accc..acbfe07 100644 --- a/web/src/views/cultivate/flowers/model.ts +++ b/web/src/views/cultivate/flowers/model.ts @@ -13,6 +13,7 @@ export interface StageRule { requiredPoints: number; waterPoints: number; fertilizePoints: number; + waitHours: number; allowedActions: string[]; imageFileId: string; animationFileId: string; @@ -41,16 +42,31 @@ export class State { export function defaultStageRules(): StageRule[] { return [ - stageRule('seed', 'sprout', 12, 1, 0, ['water'], 10), - stageRule('sprout', 'bud', 60, 1, 0, ['water'], 20), - stageRule('bud', 'bloom', 90, 1, 5, ['water', 'fertilize'], 30), - stageRule('bloom', '', 0, 0, 0, [], 40), + stageRule('seed', 'sprout', 12, 1, 0, 36, ['water'], 10), + stageRule('sprout', 'bud', 18, 1, 0, 60, ['water'], 20), + stageRule('bud', 'bloom', 24, 1, 6, 72, ['water', 'fertilize'], 30), + stageRule('bloom', '', 0, 0, 0, 0, [], 40), ]; } -function stageRule(stage: string, nextStage: string, requiredPoints: number, waterPoints: number, fertilizePoints: number, allowedActions: string[], sortNo: number): StageRule { - return { stage, nextStage, requiredPoints, waterPoints, fertilizePoints, allowedActions, imageFileId: '', animationFileId: '', progressTextTemplate: '', completionText: '', sortNo }; +function stageRule(stage: string, nextStage: string, requiredPoints: number, waterPoints: number, fertilizePoints: number, waitHours: number, allowedActions: string[], sortNo: number): StageRule { + return { stage, nextStage, requiredPoints, waterPoints, fertilizePoints, waitHours, allowedActions, imageFileId: '', animationFileId: '', progressTextTemplate: '', completionText: '', sortNo }; +} + +// 非 bloom 阶段升级阈值与等待时长不能同时为 0(与 cultivate_server 校验一致) +export function validateStageRules(stageRules: StageRule[]): string | null { + for (const rule of stageRules) { + if (rule.stage !== 'bloom' && rule.requiredPoints === 0 && rule.waitHours === 0) { + return `阶段 ${rule.stage} 的升级成长值与等待时长不能同时为 0`; + } + } + return null; +} +export function newState(state: State | Record | null): State { + const result = state ? new State(cloneDeep(state)) : new State(); + // 兼容旧版后端未返回 waitHours 的数据 + for (const rule of result.stageRules) { rule.waitHours = Number(rule.waitHours ?? 0) || 0; } + return result; } -export function newState(state: State | Record | null): State { return state ? new State(cloneDeep(state)) : new State(); } export const rules = { flowerCode: { required: true, trigger: ['blur', 'input'], message: '请输入花种编码' },