package com.zy.ai.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.zy.ai.entity.AiPromptTemplate; import com.zy.ai.enums.AiPromptScene; import com.zy.ai.mapper.AiPromptTemplateMapper; import com.zy.ai.service.AiPromptTemplateService; import com.zy.ai.utils.AiPromptUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @Service("aiPromptTemplateService") @RequiredArgsConstructor public class AiPromptTemplateServiceImpl extends ServiceImpl implements AiPromptTemplateService { private final AiPromptUtils aiPromptUtils; @Override public AiPromptTemplate resolvePublished(String sceneCode) { AiPromptScene scene = requireScene(sceneCode); AiPromptTemplate prompt = findPublished(scene.getCode()); if (prompt == null) { synchronized (("ai_prompt_scene_init_" + scene.getCode()).intern()) { prompt = findPublished(scene.getCode()); if (prompt == null) { if (findLatest(scene.getCode()) == null) { prompt = ensurePublishedScene(scene); } } } } if (prompt == null) { throw new IllegalStateException("当前场景没有已发布 Prompt,sceneCode=" + scene.getCode()); } return prompt; } @Override @Transactional(rollbackFor = Exception.class) public AiPromptTemplate savePrompt(AiPromptTemplate template, Long operatorUserId) { if (template == null) { throw new IllegalArgumentException("Prompt 不能为空"); } AiPromptScene scene = requireScene(template.getSceneCode()); String content = template.getContent(); if (content == null || content.trim().isEmpty()) { throw new IllegalArgumentException("Prompt 内容不能为空"); } if (template.getId() == null) { AiPromptTemplate entity = new AiPromptTemplate(); int version = nextVersion(scene.getCode()); entity.setName(defaultName(scene, version, template.getName())); entity.setSceneCode(scene.getCode()); entity.setVersion(version); entity.setContent(content); entity.setStatus(normalizeStatus(template.getStatus())); entity.setPublished((short) 0); entity.setCreatedBy(operatorUserId); entity.setMemo(trim(template.getMemo())); this.save(entity); return entity; } AiPromptTemplate db = this.getById(template.getId()); if (db == null) { throw new IllegalArgumentException("Prompt 不存在"); } if (!scene.getCode().equals(db.getSceneCode())) { throw new IllegalArgumentException("不允许修改 Prompt 所属场景"); } if (Short.valueOf((short) 1).equals(db.getPublished())) { throw new IllegalArgumentException("已发布 Prompt 不允许直接修改,请新建版本后再发布"); } db.setName(defaultName(scene, db.getVersion() == null ? 1 : db.getVersion(), template.getName())); db.setContent(content); db.setStatus(normalizeStatus(template.getStatus())); db.setMemo(trim(template.getMemo())); this.updateById(db); return db; } @Override @Transactional(rollbackFor = Exception.class) public AiPromptTemplate publishPrompt(Long id, Long operatorUserId) { if (id == null) { throw new IllegalArgumentException("id 不能为空"); } AiPromptTemplate db = this.getById(id); if (db == null) { throw new IllegalArgumentException("Prompt 不存在"); } if (db.getContent() == null || db.getContent().trim().isEmpty()) { throw new IllegalArgumentException("Prompt 内容不能为空"); } UpdateWrapper clearWrapper = new UpdateWrapper<>(); clearWrapper.eq("scene_code", db.getSceneCode()).set("published", 0); this.update(clearWrapper); db.setPublished((short) 1); db.setStatus((short) 1); db.setPublishedBy(operatorUserId); db.setPublishedTime(new Date()); if (db.getVersion() == null || db.getVersion() <= 0) { db.setVersion(nextVersion(db.getSceneCode())); } if (db.getName() == null || db.getName().trim().isEmpty()) { AiPromptScene scene = requireScene(db.getSceneCode()); db.setName(defaultName(scene, db.getVersion(), null)); } this.updateById(db); return db; } @Override @Transactional(rollbackFor = Exception.class) public AiPromptTemplate cancelPublish(Long id, Long operatorUserId) { if (id == null) { throw new IllegalArgumentException("id 不能为空"); } AiPromptTemplate db = this.getById(id); if (db == null) { throw new IllegalArgumentException("Prompt 不存在"); } if (!Short.valueOf((short) 1).equals(db.getPublished())) { throw new IllegalArgumentException("当前 Prompt 不是已发布状态"); } db.setPublished((short) 0); db.setPublishedBy(operatorUserId); db.setPublishedTime(null); this.updateById(db); return db; } @Override @Transactional(rollbackFor = Exception.class) public boolean deletePrompt(Long id) { if (id == null) { return false; } AiPromptTemplate db = this.getById(id); if (db == null) { return false; } if (Short.valueOf((short) 1).equals(db.getPublished())) { throw new IllegalArgumentException("已发布 Prompt 不允许删除,请先发布其他版本"); } return this.removeById(id); } @Override @Transactional(rollbackFor = Exception.class) public int initDefaultsIfMissing() { int changed = 0; for (AiPromptScene scene : AiPromptScene.values()) { AiPromptTemplate latest = findLatest(scene.getCode()); if (latest == null) { ensurePublishedScene(scene); changed++; } } return changed; } @Override public List> listSupportedScenes() { List> result = new ArrayList<>(); for (AiPromptScene scene : AiPromptScene.values()) { HashMap item = new HashMap<>(); item.put("code", scene.getCode()); item.put("label", scene.getLabel()); result.add(item); } return result; } private AiPromptTemplate ensurePublishedScene(AiPromptScene scene) { AiPromptTemplate latest = findLatest(scene.getCode()); if (latest == null) { AiPromptTemplate seed = new AiPromptTemplate(); seed.setName(defaultName(scene, 1, null)); seed.setSceneCode(scene.getCode()); seed.setVersion(1); seed.setContent(aiPromptUtils.getDefaultPrompt(scene.getCode())); seed.setStatus((short) 1); seed.setPublished((short) 1); seed.setPublishedTime(new Date()); seed.setMemo("系统初始化默认 Prompt"); this.save(seed); log.info("Initialized default AI prompt, sceneCode={}, version={}", scene.getCode(), seed.getVersion()); return seed; } UpdateWrapper clearWrapper = new UpdateWrapper<>(); clearWrapper.eq("scene_code", scene.getCode()).set("published", 0); this.update(clearWrapper); latest.setStatus((short) 1); latest.setPublished((short) 1); if (latest.getPublishedTime() == null) { latest.setPublishedTime(new Date()); } this.updateById(latest); return latest; } private AiPromptTemplate findPublished(String sceneCode) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("scene_code", sceneCode) .eq("status", 1) .eq("published", 1) .orderByDesc("version") .orderByDesc("id") .last("limit 1"); return this.getOne(wrapper, false); } private AiPromptTemplate findLatest(String sceneCode) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("scene_code", sceneCode) .orderByDesc("version") .orderByDesc("id") .last("limit 1"); return this.getOne(wrapper, false); } private int nextVersion(String sceneCode) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("scene_code", sceneCode) .select("max(version) as version"); Map row = this.getMap(wrapper); if (row == null || row.get("version") == null) { return 1; } Object value = row.get("version"); if (value instanceof Number) { return ((Number) value).intValue() + 1; } return Integer.parseInt(String.valueOf(value)) + 1; } private Short normalizeStatus(Short status) { return status != null && status == 0 ? (short) 0 : (short) 1; } private String defaultName(AiPromptScene scene, Integer version, String name) { String value = trim(name); if (value != null && !value.isEmpty()) { return value; } return scene.getLabel() + " v" + version; } private AiPromptScene requireScene(String sceneCode) { String code = trim(sceneCode); AiPromptScene scene = AiPromptScene.ofCode(code); if (scene == null) { throw new IllegalArgumentException("不支持的 Prompt 场景: " + sceneCode); } return scene; } private String trim(String value) { if (value == null) { return null; } String trimmed = value.trim(); return trimmed.isEmpty() ? null : trimmed; } }