Ver Fonte

结构调整,增加角色应用区分,增加agent 提示模板

1811872455@163.com há 3 semanas atrás
pai
commit
9e13426a32
35 ficheiros alterados com 515 adições e 30 exclusões
  1. 1 1
      java/storlead-api/src/main/java/com/storlead/login/AuthCaptchaApiController.java
  2. 1 1
      java/storlead-api/src/main/java/com/storlead/system/CorpWeChatController.java
  3. 1 1
      java/storlead-api/src/main/java/com/storlead/system/controller/FileResourceController.java
  4. 1 1
      java/storlead-api/src/main/java/com/storlead/system/controller/LoginApiController.java
  5. 1 1
      java/storlead-api/src/main/java/com/storlead/system/controller/LoginController.java
  6. 1 1
      java/storlead-api/src/main/java/com/storlead/system/controller/OrganizDataSyncApiController.java
  7. 1 1
      java/storlead-api/src/main/java/com/storlead/system/controller/UserController.java
  8. 8 0
      java/storlead-system/sql/20260519_role_add_app_id.sql
  9. 19 0
      java/storlead-system/sql/agent_prompt_template.sql
  10. 85 0
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/AgentPromptTemplateApiController.java
  11. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/CompanyApiController.java
  12. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/CompanyCustomSettingsController.java
  13. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/DeptApiController.java
  14. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/DeptController.java
  15. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/FileResourceController.java
  16. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/JobApiController.java
  17. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/JobController.java
  18. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/MenuApiController.java
  19. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/PermissionResApiController.java
  20. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/QuickMenuApiController.java
  21. 12 5
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/RoleApiController.java
  22. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SubCompanyApiController.java
  23. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SubCompanyController.java
  24. 12 3
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SysAppApiController.java
  25. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SysDictApiController.java
  26. 1 1
      java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/ThumbnailPreviewController.java
  27. 10 0
      java/storlead-system/storlead-system-biz/src/main/java/com/storlead/system/mapper/AgentPromptTemplateMapper.java
  28. 184 0
      java/storlead-system/storlead-system-biz/src/main/java/com/storlead/system/service/impl/AgentPromptTemplateServiceImpl.java
  29. 2 1
      java/storlead-system/storlead-system-biz/src/main/resources/mapper/RoleMapper.xml
  30. 32 0
      java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/dto/AgentPromptTemplatePageDTO.java
  31. 49 0
      java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/dto/AgentPromptTemplateQueryDTO.java
  32. 40 0
      java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/entity/AgentPromptTemplateEntity.java
  33. 3 0
      java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/entity/RoleEntity.java
  34. 35 0
      java/storlead-system/storlead-system-spi/src/main/java/com/storlead/system/service/AgentPromptTemplateService.java
  35. 3 0
      java/storlead-user/storlead-user-core/src/main/java/com/storlead/user/pojo/dto/RoleParam.java

+ 1 - 1
java/storlead-api/src/main/java/com/storlead/login/AuthCaptchaApiController.java

@@ -19,7 +19,7 @@ import javax.annotation.Resource;
  */
 @RestController
 @RequestMapping("/sys/auth/captcha")
-@Api(tags = "系统: 验证码")
+@Api(tags = "平台中心 - 系统: 验证码")
 public class AuthCaptchaApiController {
 
     @Resource

+ 1 - 1
java/storlead-api/src/main/java/com/storlead/system/CorpWeChatController.java

@@ -47,7 +47,7 @@ import java.util.concurrent.TimeUnit;
  * @author blank
  * @date 2021-3-8 下午 12:06
  */
-@Api(tags = "系统: 企业微信管理")
+@Api(tags = "平台中心 - 系统: 企业微信管理")
 @RestController
 @RequestMapping("/xwork")
 @Log4j2

+ 1 - 1
java/storlead-api/src/main/java/com/storlead/system/controller/FileResourceController.java

@@ -40,7 +40,7 @@ import java.util.Objects;
 @Log4j2
 @RestController
 @RequestMapping("/oss/file")
-@Api(tags="系统: 公共接口")
+@Api(tags="平台中心 - 系统: 公共接口")
 public class FileResourceController {
 
     @Resource

+ 1 - 1
java/storlead-api/src/main/java/com/storlead/system/controller/LoginApiController.java

@@ -57,7 +57,7 @@ import java.util.stream.Collectors;
  */
 @RestController
 @RequestMapping("/sys/auth")
-@Api(tags="系统: 认证接口")
+@Api(tags="平台中心 - 系统: 认证接口")
 @Slf4j
 public class LoginApiController {
 

+ 1 - 1
java/storlead-api/src/main/java/com/storlead/system/controller/LoginController.java

@@ -40,7 +40,7 @@ import java.util.concurrent.TimeUnit;
  */
 @RestController
 @RequestMapping("/lingcun")
-@Api(tags="系统: 公共接口")
+@Api(tags="平台中心 - 系统: 公共接口")
 @Slf4j
 public class LoginController {
 	@Resource

+ 1 - 1
java/storlead-api/src/main/java/com/storlead/system/controller/OrganizDataSyncApiController.java

@@ -41,7 +41,7 @@ import java.util.stream.Collectors;
  * @create: 2022-07-15 15:55
  */
 
-@Api(tags = "系统: 角色管理")
+@Api(tags = "平台中心 - 系统: 角色管理")
 @RestController
 @RequestMapping("/sys/data/sync")
 public class OrganizDataSyncApiController {

+ 1 - 1
java/storlead-api/src/main/java/com/storlead/system/controller/UserController.java

@@ -35,7 +35,7 @@ import java.util.stream.Collectors;
 @Slf4j
 @RestController
 @RequestMapping("/lingcun/user")
-@Api(tags="系统: 公共接口")
+@Api(tags="平台中心 - 系统: 公共接口")
 public class UserController {
 
 	@Resource

+ 8 - 0
java/storlead-system/sql/20260519_role_add_app_id.sql

@@ -0,0 +1,8 @@
+-- 角色表增加所属应用标记(对应 RoleEntity.appId / sys_app.id)
+ALTER TABLE `role`
+    ADD COLUMN `app_id` BIGINT NULL DEFAULT NULL COMMENT '所属应用ID,对应 sys_app.id' AFTER `remark`;
+
+-- 历史数据:可按业务将已有角色归属主应用(0),需要时再执行
+-- UPDATE `role` SET `app_id` = 0 WHERE `app_id` IS NULL;
+
+CREATE INDEX `idx_role_app_id` ON `role` (`app_id`);

+ 19 - 0
java/storlead-system/sql/agent_prompt_template.sql

@@ -0,0 +1,19 @@
+-- AI 提示词模板表
+CREATE TABLE IF NOT EXISTS `agent_prompt_template` (
+  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',
+  `template_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '模板名称',
+  `template_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '模板code',
+  `app_id` bigint DEFAULT NULL COMMENT '所属应用ID,对应 sys_app.id',
+  `prompt_content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT 'prompt 内容',
+  `create_by` bigint DEFAULT NULL COMMENT '创建者',
+  `owner_by` bigint DEFAULT '0' COMMENT '拥有者',
+  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
+  `update_by` bigint DEFAULT NULL COMMENT '更新者',
+  `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
+  `is_delete` int DEFAULT '0' COMMENT '是否删除:0未删除,1已删除',
+  `enabled` int NOT NULL DEFAULT '1' COMMENT '是否启用:1:启用,0:不启用',
+  `sort` int NOT NULL DEFAULT '0' COMMENT '显示顺序',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_agent_prompt_template_code` (`template_code`),
+  KEY `idx_agent_prompt_template_app_id` (`app_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='ai提示词模板';

+ 85 - 0
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/AgentPromptTemplateApiController.java

@@ -0,0 +1,85 @@
+package com.storlead.system.controller;
+
+import com.storlead.framework.common.result.Result;
+import com.storlead.system.pojo.dto.AgentPromptTemplatePageDTO;
+import com.storlead.system.pojo.dto.AgentPromptTemplateQueryDTO;
+import com.storlead.system.pojo.entity.AgentPromptTemplateEntity;
+import com.storlead.system.service.AgentPromptTemplateService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * AI 提示词模板管理
+ */
+@Api(tags = "平台中心 - 系统: AI提示词模板")
+@RestController
+@RequestMapping("/sys/agent/prompt")
+public class AgentPromptTemplateApiController {
+
+    @Resource
+    private AgentPromptTemplateService agentPromptTemplateService;
+
+    @ApiOperation("保存提示词模板")
+    @PostMapping("/save")
+    public Result<?> save(@RequestBody AgentPromptTemplateEntity body) {
+        return agentPromptTemplateService.saveTemplate(body);
+    }
+
+    @ApiOperation("分页查询")
+    @PostMapping("/pagelist")
+    public Result<?> pagelist(@RequestBody AgentPromptTemplatePageDTO dto) {
+        return Result.result(agentPromptTemplateService.pageQuery(dto));
+    }
+
+    @ApiOperation("列表查询(可按编码批量)")
+    @PostMapping("/list")
+    public Result<?> list(@RequestBody AgentPromptTemplateQueryDTO dto) {
+        return Result.result(agentPromptTemplateService.listQuery(dto));
+    }
+
+    @ApiOperation("详情")
+    @PostMapping("/detail")
+    public Result<?> detail(@RequestParam Long id) {
+        AgentPromptTemplateEntity one = agentPromptTemplateService.getDetail(id);
+        if (one == null) {
+            return Result.error("模板不存在或已删除");
+        }
+        return Result.ok(one);
+    }
+
+    @ApiOperation("按模板编码查询(启用且未删除)")
+    @PostMapping("/getByCode")
+    public Result<?> getByCode(@RequestParam String templateCode,
+                               @RequestParam(required = false) Long appId) {
+        AgentPromptTemplateEntity one = agentPromptTemplateService.getByTemplateCode(templateCode, appId);
+        if (one == null) {
+            return Result.error("未找到对应的AI提示词模板");
+        }
+        return Result.ok(one);
+    }
+
+    @ApiOperation("获取渲染后的 prompt 内容")
+    @PostMapping("/getPromptContent")
+    public Result<?> getPromptContent(@RequestBody AgentPromptTemplateQueryDTO dto) {
+        return agentPromptTemplateService.getPromptContent(dto);
+    }
+
+    @ApiOperation("启用/禁用")
+    @PostMapping("/enable")
+    public Result<?> enable(@RequestParam Long id, @RequestParam Boolean enabled) {
+        return agentPromptTemplateService.enableTemplate(id, enabled);
+    }
+
+    @ApiOperation("逻辑删除")
+    @PostMapping("/delete")
+    public Result<?> delete(@RequestParam Long id) {
+        return agentPromptTemplateService.deleteTemplate(id);
+    }
+}

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/CompanyApiController.java

@@ -28,7 +28,7 @@ import java.util.Objects;
  * @create: 2022-06-29 17:33
  */
 
-@Api(tags = "系统: 公司数据维护")
+@Api(tags = "平台中心 - 系统: 公司数据维护")
 @RestController
 @RequestMapping("/sys/company")
 public class CompanyApiController {

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/CompanyCustomSettingsController.java

@@ -28,7 +28,7 @@ import java.util.Objects;
  */
 @RestController
 @RequestMapping("/sys/custom/settings")
-@Api(tags = "系统: 企业个性化设置")
+@Api(tags = "平台中心 - 系统: 企业个性化设置")
 public class CompanyCustomSettingsController {
 
 

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/DeptApiController.java

@@ -40,7 +40,7 @@ import java.util.stream.Collectors;
  * @author: chenkq
  * @create: 2022-06-29 17:46
  */
-@Api(tags = "系统: 公司部门数据维护")
+@Api(tags = "平台中心 - 系统: 公司部门数据维护")
 @RestController
 @RequestMapping("/sys/dept")
 @Log4j2

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/DeptController.java

@@ -20,7 +20,7 @@ import java.util.List;
 @RestController
 @RequestMapping("/lingcun/dept")
 @Slf4j
-@Api(tags="系统: 公共接口")
+@Api(tags="平台中心 - 系统: 公共接口")
 public class DeptController {
 
 	@Resource

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/FileResourceController.java

@@ -41,7 +41,7 @@ import java.util.Objects;
 @Log4j2
 @RestController
 @RequestMapping("/oss/file")
-@Api(tags="系统: 公共接口")
+@Api(tags="平台中心 - 系统: 公共接口")
 public class FileResourceController {
 
     @Resource

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/JobApiController.java

@@ -27,7 +27,7 @@ import java.util.Objects;
  * @author: chenkq
  * @create: 2022-05-24 11:03
  */
-@Api(tags = "系统: 角色管理")
+@Api(tags = "平台中心 - 系统: 角色管理")
 @RestController
 @RequestMapping("/sys/job/manage")
 public class JobApiController {

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/JobController.java

@@ -19,7 +19,7 @@ import java.util.List;
 @RestController
 @RequestMapping("/lingcun/job")
 @Slf4j
-@Api(tags="系统: 公共接口")
+@Api(tags="平台中心 - 系统: 公共接口")
 public class JobController {
 
 	@Resource

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/MenuApiController.java

@@ -46,7 +46,7 @@ import java.util.stream.Collectors;
  * @author: chenkq
  * @create: 2022-05-20 10:37
  */
-@Api(tags = "系统: 菜单管理")
+@Api(tags = "平台中心 - 系统: 菜单管理")
 @Log4j2
 @RestController
 @RequestMapping("sys/menu")

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/PermissionResApiController.java

@@ -29,7 +29,7 @@ import java.util.*;
  * @create: 2024-04-09 10:02
  */
 
-@Api(tags = "系统: 权限菜单")
+@Api(tags = "平台中心 - 系统: 权限菜单")
 @Log4j2
 @RestController
 @RequestMapping("/sys/permission")

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/QuickMenuApiController.java

@@ -30,7 +30,7 @@ import java.util.stream.Collectors;
  * @author: chenkq
  * @create: 2024-04-08 17:14
  */
-@Api(tags = "系统: 快捷菜单设置")
+@Api(tags = "平台中心 - 系统: 快捷菜单设置")
 @RestController
 @RequestMapping("/sys/quick/menu")
 public class QuickMenuApiController {

+ 12 - 5
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/RoleApiController.java

@@ -38,7 +38,7 @@ import java.util.stream.Collectors;
  * @author: chenkq
  * @create: 2022-05-20 10:11
  */
-@Api(tags = "系统: 角色管理")
+@Api(tags = "平台中心 - 系统: 角色管理")
 @RestController
 @RequestMapping("/sys/role/manage")
 public class RoleApiController {
@@ -64,9 +64,12 @@ public class RoleApiController {
     @PostMapping("/pagelist")
     public Result<?> list(@RequestBody RoleParam param) {
         IPage<RoleEntity> page = new Page<>(param.getPageIndex(),param.getPageSize());
-        LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper();
+        LambdaQueryWrapper<RoleEntity> queryWrapper = new LambdaQueryWrapper<>();
         if (StrUtil.isNotBlank(param.getName())) {
-            queryWrapper.likeRight("name",param.getName());
+            queryWrapper.likeRight(RoleEntity::getName, param.getName());
+        }
+        if (param.getAppId() != null) {
+            queryWrapper.eq(RoleEntity::getAppId, param.getAppId());
         }
         IPage<RoleEntity> roles = roleService.page(page,queryWrapper);
         if (!CollectionUtils.isEmpty(roles.getRecords())) {
@@ -85,13 +88,17 @@ public class RoleApiController {
         if (Objects.isNull(info) || StrUtil.isBlank(info.getName())) {
             return Result.error("参数错误");
         }
+        LambdaQueryWrapper<RoleEntity> nameWrapper = new LambdaQueryWrapper<RoleEntity>().eq(RoleEntity::getName, info.getName());
+        if (info.getAppId() != null) {
+            nameWrapper.eq(RoleEntity::getAppId, info.getAppId());
+        }
         if (Objects.isNull(info.getId())) {
-            Integer exit = roleService.count(new LambdaQueryWrapper<RoleEntity>().eq(RoleEntity::getName,info.getName()));
+            Integer exit = roleService.count(nameWrapper);
             if (exit > 0) {
                 return Result.error("角色'"+ info.getName() +"'已存在!");
             }
         } else {
-            RoleEntity oldAccount = roleService.getOne(new LambdaQueryWrapper<RoleEntity>().eq(RoleEntity::getName,info.getName()));
+            RoleEntity oldAccount = roleService.getOne(nameWrapper);
             if (Objects.nonNull(oldAccount)) {
                 if (!oldAccount.getId().equals(info.getId())) {
                     return Result.error("角色'"+ info.getName() +"'已存在,无法修改!");

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SubCompanyApiController.java

@@ -35,7 +35,7 @@ import java.util.Objects;
  */
 
 
-@Api(tags = "系统: 子公司数据维护")
+@Api(tags = "平台中心 - 系统: 子公司数据维护")
 @RestController
 @RequestMapping("/sys/subcompany")
 public class SubCompanyApiController {

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SubCompanyController.java

@@ -22,7 +22,7 @@ import java.util.List;
 
 @RestController
 @RequestMapping("/lingcun")
-@Api(tags="系统: 公共接口")
+@Api(tags="平台中心 - 系统: 公共接口")
 public class SubCompanyController {
 
     @Resource

+ 12 - 3
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SysAppApiController.java

@@ -18,7 +18,7 @@ import javax.annotation.Resource;
 /**
  * 系统应用管理
  */
-@Api(tags = "系统: 应用管理")
+@Api(tags = "平台中心 - 系统: 应用管理")
 @RestController
 @RequestMapping("/sys/app")
 public class SysAppApiController {
@@ -26,16 +26,25 @@ public class SysAppApiController {
     @Resource
     private SysAppService sysAppService;
 
+    @ApiOperation("获取应用")
+    @PostMapping("/list")
+    public Result<?> list(@RequestBody SysAppPageDTO dto) {
+        return Result.result(
+                sysAppService.listEnabled()
+        );
+    }
+
+
     @ApiOperation("应用分页")
     @PostMapping("/pagelist")
     public Result<?> pagelist(@RequestBody SysAppPageDTO dto) {
-        return Result.ok(sysAppService.pageQuery(dto));
+        return Result.result(sysAppService.pageQuery(dto));
     }
 
     @ApiOperation("已启用应用列表(下拉等)")
     @PostMapping("/listEnabled")
     public Result<?> listEnabled() {
-        return Result.ok(sysAppService.listEnabled());
+        return Result.result(sysAppService.listEnabled());
     }
 
     @ApiOperation("详情")

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/SysDictApiController.java

@@ -31,7 +31,7 @@ import java.util.Objects;
  */
 @RestController
 @RequestMapping("/sys/dict")
-@Api(tags="系统: 数据字典")
+@Api(tags="平台中心 - 系统: 数据字典")
 public class SysDictApiController {
 
     @Resource

+ 1 - 1
java/storlead-system/storlead-system-api/src/main/java/com/storlead/system/controller/ThumbnailPreviewController.java

@@ -30,7 +30,7 @@ import java.util.Iterator;
  */
 @RestController
 @RequestMapping("/view")
-@Api(tags = "系统: 图片显示")
+@Api(tags = "平台中心 - 系统: 图片显示")
 @Log4j2
 public class ThumbnailPreviewController {
 

+ 10 - 0
java/storlead-system/storlead-system-biz/src/main/java/com/storlead/system/mapper/AgentPromptTemplateMapper.java

@@ -0,0 +1,10 @@
+package com.storlead.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.storlead.system.pojo.entity.AgentPromptTemplateEntity;
+
+/**
+ * AI 提示词模板 Mapper
+ */
+public interface AgentPromptTemplateMapper extends BaseMapper<AgentPromptTemplateEntity> {
+}

+ 184 - 0
java/storlead-system/storlead-system-biz/src/main/java/com/storlead/system/service/impl/AgentPromptTemplateServiceImpl.java

@@ -0,0 +1,184 @@
+package com.storlead.system.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.storlead.framework.common.constant.CommonConstant;
+import com.storlead.framework.common.result.Result;
+import com.storlead.system.mapper.AgentPromptTemplateMapper;
+import com.storlead.system.pojo.dto.AgentPromptTemplatePageDTO;
+import com.storlead.system.pojo.dto.AgentPromptTemplateQueryDTO;
+import com.storlead.system.pojo.entity.AgentPromptTemplateEntity;
+import com.storlead.system.service.AgentPromptTemplateService;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * AI 提示词模板服务实现
+ */
+@Service
+public class AgentPromptTemplateServiceImpl
+        extends ServiceImpl<AgentPromptTemplateMapper, AgentPromptTemplateEntity>
+        implements AgentPromptTemplateService {
+
+    @Override
+    public IPage<AgentPromptTemplateEntity> pageQuery(AgentPromptTemplatePageDTO dto) {
+        IPage<AgentPromptTemplateEntity> page = new Page<>(dto.getPageIndex(), dto.getPageSize());
+        return page(page, buildListWrapper(dto.getTemplateName(), dto.getTemplateCode(), dto.getAppId(), dto.getEnabled()));
+    }
+
+    @Override
+    public List<AgentPromptTemplateEntity> listQuery(AgentPromptTemplateQueryDTO dto) {
+        LambdaQueryWrapper<AgentPromptTemplateEntity> w = buildListWrapper(null, null, dto.getAppId(), null);
+        if (StrUtil.isNotBlank(dto.getTemplateCode())) {
+            w.eq(AgentPromptTemplateEntity::getTemplateCode, dto.getTemplateCode().trim());
+        }
+        if (!CollectionUtils.isEmpty(dto.getTemplateCodes())) {
+            w.in(AgentPromptTemplateEntity::getTemplateCode, dto.getTemplateCodes());
+        }
+        w.orderByAsc(AgentPromptTemplateEntity::getSort).orderByDesc(AgentPromptTemplateEntity::getId);
+        return list(w);
+    }
+
+    @Override
+    public AgentPromptTemplateEntity getDetail(Long id) {
+        if (id == null) {
+            return null;
+        }
+        return getOne(new LambdaQueryWrapper<AgentPromptTemplateEntity>()
+                .eq(AgentPromptTemplateEntity::getId, id)
+                .eq(AgentPromptTemplateEntity::getIsDelete, CommonConstant.DEL_FLAG_0));
+    }
+
+    @Override
+    public AgentPromptTemplateEntity getByTemplateCode(String templateCode, Long appId) {
+        if (StrUtil.isBlank(templateCode)) {
+            return null;
+        }
+        LambdaQueryWrapper<AgentPromptTemplateEntity> w = new LambdaQueryWrapper<>();
+        w.eq(AgentPromptTemplateEntity::getTemplateCode, templateCode.trim());
+        w.eq(AgentPromptTemplateEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        w.eq(AgentPromptTemplateEntity::getEnabled, true);
+        if (appId != null) {
+            w.eq(AgentPromptTemplateEntity::getAppId, appId);
+        }
+        w.last(" limit 1");
+        return getOne(w);
+    }
+
+    @Override
+    public Result<?> saveTemplate(AgentPromptTemplateEntity body) {
+        if (body == null || StrUtil.isBlank(body.getTemplateCode())) {
+            return Result.error("模板编码不能为空");
+        }
+        if (StrUtil.isBlank(body.getTemplateName())) {
+            return Result.error("模板名称不能为空");
+        }
+        body.setTemplateCode(body.getTemplateCode().trim());
+        body.setTemplateName(body.getTemplateName().trim());
+
+        LambdaQueryWrapper<AgentPromptTemplateEntity> codeWrapper = new LambdaQueryWrapper<>();
+        codeWrapper.eq(AgentPromptTemplateEntity::getTemplateCode, body.getTemplateCode());
+        codeWrapper.eq(AgentPromptTemplateEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        if (body.getAppId() != null) {
+            codeWrapper.eq(AgentPromptTemplateEntity::getAppId, body.getAppId());
+        }
+        if (body.getId() == null) {
+            if (count(codeWrapper) > 0) {
+                return Result.error("模板编码'" + body.getTemplateCode() + "'已存在");
+            }
+        } else {
+            AgentPromptTemplateEntity exists = getOne(codeWrapper);
+            if (exists != null && !exists.getId().equals(body.getId())) {
+                return Result.error("模板编码'" + body.getTemplateCode() + "'已存在,无法修改");
+            }
+        }
+        if (body.getIsDelete() == null) {
+            body.setIsDelete(CommonConstant.DEL_FLAG_0);
+        }
+        if (body.getEnabled() == null) {
+            body.setEnabled(true);
+        }
+        if (body.getSort() == null) {
+            body.setSort(0);
+        }
+        saveOrUpdate(body);
+        return Result.ok(body.getId());
+    }
+
+    @Override
+    public Result<?> enableTemplate(Long id, Boolean enabled) {
+        if (id == null || enabled == null) {
+            return Result.error("参数错误");
+        }
+        boolean ok = update(new LambdaUpdateWrapper<AgentPromptTemplateEntity>()
+                .set(AgentPromptTemplateEntity::getEnabled, enabled)
+                .eq(AgentPromptTemplateEntity::getId, id)
+                .eq(AgentPromptTemplateEntity::getIsDelete, CommonConstant.DEL_FLAG_0));
+        return ok ? Result.ok() : Result.error("记录不存在或已删除");
+    }
+
+    @Override
+    public Result<?> deleteTemplate(Long id) {
+        if (id == null) {
+            return Result.error("参数错误");
+        }
+        boolean ok = update(new LambdaUpdateWrapper<AgentPromptTemplateEntity>()
+                .set(AgentPromptTemplateEntity::getIsDelete, CommonConstant.DEL_FLAG_1)
+                .eq(AgentPromptTemplateEntity::getId, id)
+                .eq(AgentPromptTemplateEntity::getIsDelete, CommonConstant.DEL_FLAG_0));
+        return ok ? Result.ok() : Result.error("记录不存在或已删除");
+    }
+
+    @Override
+    public Result<?> getPromptContent(AgentPromptTemplateQueryDTO dto) {
+        if (dto == null || StrUtil.isBlank(dto.getTemplateCode())) {
+            return Result.error("模板编码不能为空");
+        }
+        AgentPromptTemplateEntity entity = getByTemplateCode(dto.getTemplateCode(), dto.getAppId());
+        if (entity == null || StrUtil.isBlank(entity.getPromptContent())) {
+            return Result.error("未找到对应的AI提示词,请联系管理员进行配置");
+        }
+        String content = entity.getPromptContent();
+        content = replaceIfPresent(content, "$subject$", dto.getSubject());
+        content = replaceIfPresent(content, "$content$", dto.getContent());
+        content = replaceIfPresent(content, "$customerName$", dto.getCustomerName());
+        content = replaceIfPresent(content, "$liaisonName$", dto.getLiaisonName());
+        content = replaceIfPresent(content, "$continent$", dto.getContinent());
+        content = replaceIfPresent(content, "$country$", dto.getCountry());
+        return Result.ok(content);
+    }
+
+    private LambdaQueryWrapper<AgentPromptTemplateEntity> buildListWrapper(
+            String templateName, String templateCode, Long appId, Integer enabled) {
+        LambdaQueryWrapper<AgentPromptTemplateEntity> w = new LambdaQueryWrapper<>();
+        w.eq(AgentPromptTemplateEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+        if (StrUtil.isNotBlank(templateName)) {
+            w.like(AgentPromptTemplateEntity::getTemplateName, templateName.trim());
+        }
+        if (StrUtil.isNotBlank(templateCode)) {
+            w.like(AgentPromptTemplateEntity::getTemplateCode, templateCode.trim());
+        }
+        if (appId != null) {
+            w.eq(AgentPromptTemplateEntity::getAppId, appId);
+        }
+        if (enabled != null) {
+            w.eq(AgentPromptTemplateEntity::getEnabled, Objects.equals(enabled, CommonConstant.STATUS_NORMAL));
+        }
+        w.orderByAsc(AgentPromptTemplateEntity::getSort).orderByDesc(AgentPromptTemplateEntity::getId);
+        return w;
+    }
+
+    private String replaceIfPresent(String content, String placeholder, String value) {
+        if (StrUtil.isBlank(value)) {
+            return content;
+        }
+        return content.replace(placeholder, value);
+    }
+}

+ 2 - 1
java/storlead-system/storlead-system-biz/src/main/resources/mapper/RoleMapper.xml

@@ -9,11 +9,12 @@
         <result column="desc" property="desc"/>
         <result column="data_scope" property="dataScope"/>
         <result column="remark" property="remark"/>
+        <result column="app_id" property="appId"/>
     </resultMap>
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, `name`, `desc`, data_scope, remark, <include refid="com.storlead.framework.mybatis.mapper.SysBaseFieldMapper.Base_Column_List"></include>
+        id, `name`, `desc`, data_scope, remark, app_id, <include refid="com.storlead.framework.mybatis.mapper.SysBaseFieldMapper.Base_Column_List"></include>
     </sql>
 
     <!-- 根据用户ID 查询所有的全部菜单权限 也就是用户角色所有的菜单的 permission 字段 -->

+ 32 - 0
java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/dto/AgentPromptTemplatePageDTO.java

@@ -0,0 +1,32 @@
+package com.storlead.system.pojo.dto;
+
+import com.storlead.framework.mybatis.page.Page;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * AI 提示词模板分页查询
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "AgentPromptTemplatePageDTO", description = "AI提示词模板分页查询")
+public class AgentPromptTemplatePageDTO extends Page {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "模板名称(模糊)")
+    private String templateName;
+
+    @ApiModelProperty(value = "模板编码(模糊)")
+    private String templateCode;
+
+    @ApiModelProperty(value = "所属应用 ID")
+    private Long appId;
+
+    @ApiModelProperty(value = "是否启用:1 启用,0 禁用")
+    private Integer enabled;
+}

+ 49 - 0
java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/dto/AgentPromptTemplateQueryDTO.java

@@ -0,0 +1,49 @@
+package com.storlead.system.pojo.dto;
+
+import com.storlead.framework.mybatis.page.Page;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * AI 提示词模板列表/按编码查询
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "AgentPromptTemplateQueryDTO", description = "AI提示词模板查询")
+public class AgentPromptTemplateQueryDTO extends Page {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "模板编码(单条查询)")
+    private String templateCode;
+
+    @ApiModelProperty(value = "模板编码列表")
+    private List<String> templateCodes;
+
+    @ApiModelProperty(value = "所属应用 ID")
+    private Long appId;
+
+    @ApiModelProperty(value = "邮件主题,占位符 $subject$")
+    private String subject;
+
+    @ApiModelProperty(value = "邮件正文,占位符 $content$")
+    private String content;
+
+    @ApiModelProperty(value = "客户名称,占位符 $customerName$")
+    private String customerName;
+
+    @ApiModelProperty(value = "联系人名称,占位符 $liaisonName$")
+    private String liaisonName;
+
+    @ApiModelProperty(value = "大洲,占位符 $continent$")
+    private String continent;
+
+    @ApiModelProperty(value = "国家,占位符 $country$")
+    private String country;
+}

+ 40 - 0
java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/entity/AgentPromptTemplateEntity.java

@@ -0,0 +1,40 @@
+package com.storlead.system.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.storlead.framework.mybatis.entity.SysBaseField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * AI 提示词模板(agent_prompt_template)
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Accessors(chain = true)
+@TableName("agent_prompt_template")
+@ApiModel(value = "AgentPromptTemplateEntity", description = "AI提示词模板")
+public class AgentPromptTemplateEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
+    @ApiModelProperty(value = "模板名称")
+    private String templateName;
+
+    @ApiModelProperty(value = "模板编码,同应用下唯一")
+    private String templateCode;
+
+    @ApiModelProperty(value = "所属应用 ID,对应 sys_app.id")
+    private Long appId;
+
+    @ApiModelProperty(value = "prompt 内容")
+    private String promptContent;
+}

+ 3 - 0
java/storlead-system/storlead-system-core/src/main/java/com/storlead/system/pojo/entity/RoleEntity.java

@@ -48,6 +48,9 @@ public class RoleEntity extends SysBaseField {
     @ApiModelProperty(value = "备注")
     private String remark;
 
+    @ApiModelProperty(value = "所属应用 ID,对应 sys_app.id")
+    private Long appId;
+
     @TableField(exist = false)
     private String userNames = "";
     /**

+ 35 - 0
java/storlead-system/storlead-system-spi/src/main/java/com/storlead/system/service/AgentPromptTemplateService.java

@@ -0,0 +1,35 @@
+package com.storlead.system.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.storlead.framework.common.result.Result;
+import com.storlead.system.pojo.dto.AgentPromptTemplatePageDTO;
+import com.storlead.system.pojo.dto.AgentPromptTemplateQueryDTO;
+import com.storlead.system.pojo.entity.AgentPromptTemplateEntity;
+
+import java.util.List;
+
+/**
+ * AI 提示词模板服务
+ */
+public interface AgentPromptTemplateService extends IService<AgentPromptTemplateEntity> {
+
+    IPage<AgentPromptTemplateEntity> pageQuery(AgentPromptTemplatePageDTO dto);
+
+    List<AgentPromptTemplateEntity> listQuery(AgentPromptTemplateQueryDTO dto);
+
+    AgentPromptTemplateEntity getDetail(Long id);
+
+    AgentPromptTemplateEntity getByTemplateCode(String templateCode, Long appId);
+
+    Result<?> saveTemplate(AgentPromptTemplateEntity body);
+
+    Result<?> enableTemplate(Long id, Boolean enabled);
+
+    Result<?> deleteTemplate(Long id);
+
+    /**
+     * 按模板编码获取 prompt 内容,并替换占位符
+     */
+    Result<?> getPromptContent(AgentPromptTemplateQueryDTO dto);
+}

+ 3 - 0
java/storlead-user/storlead-user-core/src/main/java/com/storlead/user/pojo/dto/RoleParam.java

@@ -37,6 +37,9 @@ public class RoleParam extends Page {
     @ApiModelProperty(value = "备注")
     private String remark;
 
+    @ApiModelProperty(value = "所属应用 ID,对应 sys_app.id")
+    private Long appId;
+
     @ApiModelProperty(value = "菜单列表")
     private Set<Long> menus;