Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/bkywksj_ruoyi-plus-uniapp-docs.json

1 line
152 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "bkywksj/ruoyi-plus-uniapp-docs", "files": {"docs/backend/modules/business/base.md": {"4df4b869cb38268c2e1daeabe96d7979ad70203e": {"t": 1785746525.820662, "n": 27735, "h": "72144b0794344a02", "c": "# 基础服务模块 (base)\n\n基础服务模块提供了系统运行所需的核心基础服务,包括多平台配置管理、支付配置管理、广告配置、账号绑定等功能。\n\n## 模块结构\n\n```text\nbase/\n├── controller/ # 控制器层\n│ ├── AdController.java\n│ ├── BindController.java\n│ ├── PaymentController.java\n│ └── PlatformController.java\n├── service/ # 服务层\n│ ├── IAdService.java\n│ ├── IBindService.java\n│ ├── IPaymentService.java\n│ └── IPlatformService.java\n├── domain/ # 数据模型\n│ ├── entity/ # 实体类\n│ ├── vo/ # 视图对象\n│ └── bo/ # 业务对象\n├── mapper/ # 数据访问层\n└── authStrategy/ # 认证策略\n```\n\n## 核心功能\n\n### 平台配置管理\n\n支持多种平台的统一配置管理:\n\n- **微信小程序** (mp-weixin)\n- **微信公众号** (mp-official-account)\n- **支付宝小程序** (mp-alipay)\n- **QQ小程序** (mp-qq)\n- **其他平台** (mp-jd, mp-kuaishou, mp-lark, mp-baidu, mp-toutiao, mp-xhs)\n\n#### 平台配置实体\n```java\n@Data\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n private Long id; // 平台配置ID\n private String type; // 平台类型\n private String name; // 平台名称\n private String appid; // 应用ID\n private String secret; // 应用密钥\n private String token; // 接口Token\n private String aeskey; // 加密密钥\n private String paymentIds; // 关联支付配置\n private String templateConfigs; // 模板配置\n private String status; // 状态\n}\n```\n\n#### 核心接口\n```java\npublic interface IPlatformService extends IBaseService<Platform, PlatformBo, PlatformVo> {\n // 继承基础CRUD操作\n}\n\n// 全局平台服务\npublic interface PlatformService {\n List<PlatformDTO> listPlatformsByType(String type, String tenantId);\n PlatformDTO getPlatformByAppidAndType(String appid, String type);\n PlatformDTO getPlatformByAppid(String appid, String tenantId);\n}\n```\n\n### 支付配置管理\n\n统一的支付配置管理,支持多种支付方式:\n\n#### 支付配置实体\n```java\n@Data\n@TableName(\"b_payment\") \npublic class Payment extends TenantEntity {\n private Long id; // 支付配置ID\n private String type; // 商户类型\n private String mchName; // 商户名称\n private String mchId; // 商户号\n private String mchKey; // 商户密钥\n private String apiV3Key; // APIv3密钥\n private String certPath; // 证书路径\n private String keyPath; // 密钥路径\n private String certSerialNo; // 证书序列号\n private String status; // 状态\n}\n```\n\n#### 核心服务\n```java\npublic interface PaymentService {\n List<PaymentDTO> listPaymentByType(String type, String tenantId);\n PaymentDTO getByMchId(String mchId);\n PaymentDTO getById(Long paymentId);\n boolean existsValidMchId(String mchId);\n long countPayments();\n}\n```\n\n### 账号绑定管理\n\n管理用户在不同平台的账号绑定关系:\n\n#### 绑定实体\n```java\n@Data\n@TableName(\"b_bind\")\npublic class Bind extends TenantEntity {\n private Long id; // 绑定ID\n private Long userId; // 用户ID\n private String platformType; // 平台类型\n private String appid; // 应用ID\n private String unionid; // 统一标识\n private String openid; // 平台标识\n private String extraData; // 扩展数据\n}\n```\n\n#### 绑定服务\n```java\npublic interface IBindService extends IBaseService<Bind, BindBo, BindVo> {\n /**\n * 根据平台用户信息获取或创建绑定信息\n */\n BindVo getOrCreateBind(PlatformUserInfoVo platformUserInfoVo);\n \n /**\n * 更新绑定信息的用户ID\n */\n void updateBindUserId(BindBo bindBo, Long userId);\n}\n```\n\n### 广告配置管理\n\n提供广告位和广告内容的统一管理:\n\n#### 广告实体\n```java\n@Data\n@TableName(\"b_ad\")\npublic class Ad extends TenantEntity {\n private Long id; // 广告ID\n private String appid; // 应用ID\n private String adUnitId; // 广告位ID\n private String adName; // 广告名称\n private String adType; // 广告类型\n private String position; // 投放位置\n private String img; // 广告图片\n private String description; // 描述\n private String jumpAppid; // 跳转应用ID\n private String jumpPath; // 跳转路径\n private String styleConfig; // 样式配置\n private Long sortOrder; // 排序值\n private String status; // 状态\n}\n```\n\n## 认证策略\n\n### 多平台认证架构\n\n基于策略模式实现多平台登录认证:\n\n#### 认证策略接口\n```java\npublic interface IAuthStrategy {\n String BASE_NAME = \"AuthStrategy\";\n AuthTokenVo login(String body);\n}\n```\n\n#### 小程序认证策略\n```java\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME)\npublic class MiniappAuthStrategy implements IAuthStrategy {\n \n @Override\n public AuthTokenVo login(String body) {\n // 1. 解析请求参数\n PlatformLoginBody loginBody = JsonUtils.parseObject(body, PlatformLoginBody.class);\n \n // 2. 获取平台用户信息\n PlatformUserInfoVo platformUserInfo = getMiniappUserIdentity(loginBody);\n \n // 3. 加载或创建用户\n SysUserVo user = loadOrCreateUser(platformUserInfo);\n \n // 4. 生成登录令牌\n LoginUser loginUser = loginService.createLoginUser(user);\n loginUser.setPlatform(platformUserInfo.getPlatform());\n loginUser.setAppid(platformUserInfo.getAppid());\n loginUser.setOpenid(platformUserInfo.getOpenid());\n loginUser.setUnionid(platformUserInfo.getUnionid());\n \n // 5. 完成登录\n LoginHelper.login(loginUser, loginParameter);\n \n // 6. 返回认证结果\n AuthTokenVo authTokenVo = new AuthTokenVo();\n authTokenVo.setAccessToken(StpUtil.getTokenValue());\n authTokenVo.setExpireIn(StpUtil.getTokenTimeout());\n return authTokenVo;\n }\n}\n```\n\n#### 公众号认证策略\n```java\n@Service(\"mp\" + IAuthStrategy.BASE_NAME)\npublic class MpAuthStrategy implements IAuthStrategy {\n // 公众号OAuth2.0认证流程实现\n // 支持网页授权登录场景\n}\n```\n\n### 认证流程\n\n1. **前端授权**:用户在前端完成平台授权,获取授权码\n2. **策略选择**:后端根据平台类型自动选择对应认证策略\n3. **信息获取**:通过授权码换取用户基本信息\n4. **账号绑定**:查找或创建用户账号绑定关系\n5. **令牌生成**:生成JWT访问令牌\n6. **登录完成**:返回令牌和用户信息\n\n## 手机号绑定\n\n### 微信小程序手机号获取\n```java\n@PostMapping(\"/bindPhone\")\npublic R<PhoneBindVo> bindPhone(@RequestBody PhoneBindBo bo) {\n LoginUser loginUser = LoginHelper.getLoginUser();\n wxMaService.switchover(loginUser.getAppid());\n \n try {\n WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(bo.getCode());\n String phone = phoneInfo.getPhoneNumber();\n \n // 更新用户手机号\n SysUser sysUser = userMapper.selectById(loginUser.getUserId());\n sysUser.setPhone(phone);\n userMapper.updateById(sysUser);\n \n return R.ok(\"绑定成功\", PhoneBindVo.of(phone));\n } catch (WxErrorException e) {\n return R.fail(\"获取手机号出错\");\n }\n}\n```\n\n## 数据字典服务\n\n### 支付方式字典\n```java\n@GetMapping(\"getPaymentDict\")\npublic R<List<DictItemVo>> getPaymentDict() {\n // 查询所有可用的支付方式\n List<PaymentVo> paymentVoList = paymentService.list(\n PlusLambdaQuery.of(Payment.class)\n .eq(Payment::getStatus, DictEnableStatus.ENABLE.getValue()));\n \n // 构建字典项列表\n List<DictItemVo> dictItems = StreamUtils.toList(paymentVoList, payment ->\n DictItemVo.of(payment.getMchName(), payment.getId().toString(), \"success\")\n );\n return R.ok(dictItems);\n}\n```\n\n## 配置管理\n\n### 平台配置热更新\n```java\nprivate void reloadPlatformConfig() {\n String tenantId = TenantHelper.getTenantId();\n \n // 重新初始化微信小程序配置\n SpringUtils.getBean(WxMaApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化微信公众号配置 \n SpringUtils.getBean(WxMpApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化支付配置\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n### 支付配置热更新\n```java\nprivate void reloadPaymentConfig() {\n String tenantId = TenantHelper.getTenantId();\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n## 使用示例\n\n### 配置微信小程序\n```java\n// 1. 创建平台配置\nPlatformBo platformBo = new PlatformBo();\nplatformBo.setType(\"mp-weixin\");\nplatformBo.setName(\"我的小程序\");\nplatformBo.setAppid(\"wx1234567890\");\nplatformBo.setSecret(\"your-secret\");\nplatformBo.setStatus(\"1\");\nplatformService.add(platformBo);\n\n// 2. 配置支付信息\nPaymentBo paymentBo = new PaymentBo();\npaymentBo.setType(\"wechat\");\npaymentBo.setMchName(\"我的商户\");\npaymentBo.setMchId(\"1234567890\");\npaymentBo.setMchKey(\"your-mch-key\");\npaymentBo.setStatus(\"1\");\npaymentService.add(paymentBo);\n```\n\n### 用户登录认证\n```java\n// 前端调用登录接口\nPOST /auth/login\n{\n \"platform\": \"miniapp\",\n \"body\": {\n \"platform\": \"mp-weixin\",\n \"appid\": \"wx1234567890\",\n \"platformCode\": \"授权码\"\n }\n}\n\n// 返回结果\n{\n \"code\": 200,\n \"msg\": \"登录成功\",\n \"data\": {\n \"accessToken\": \"eyJ0eXAiOiJKV1Q...\",\n \"expireIn\": 7200\n }\n}\n```\n\n## AI助手功能\n\n### 功能概述\n\n基础服务模块集成了强大的AI助手功能,基于 **LangChain4j** 框架实现,支持多种大语言模型(如 DeepSeek、通义千问、OpenAI、Claude等),为业务系统提供智能化能力。\n\n**核心特性:**\n- **多模型支持** - 灵活切换不同的AI模型提供商\n- **多场景应用** - 对话、优化、生成、审核、翻译等场景\n- **条件启用** - 通过配置开关控制功能启用\n- **权限控制** - 完善的权限校验机制\n- **上下文传递** - 支持业务上下文信息传递\n\n### AI服务接口\n\n#### AiController 控制器\n\n```java\n@RestController\n@RequestMapping(\"/base/ai\")\n@ConditionalOnProperty(\n prefix = \"langchain4j\",\n name = \"enabled\",\n havingValue = \"true\",\n matchIfMissing = true\n)\npublic class AiController {\n private final IAiService aiService;\n}\n```\n\n**条件启用说明:**\n- 需要在配置文件中设置 `langchain4j.enabled=true`\n- 如果配置项不存在,默认启用 (`matchIfMissing = true`)\n\n### 1. AI对话功能\n\n通用的AI对话接口,支持自由对话场景。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiChat\")\n@OpenApi(value = \"AI对话\")\npublic R<AiChatVo> aiChat(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiChat(bo));\n}\n```\n\n#### 请求示例\n\n```java\n// 创建对话请求\nAiChatBo chatBo = new AiChatBo();\nchatBo.setMessage(\"请帮我解释一下什么是微服务架构\");\nchatBo.setProvider(\"deepseek\");\nchatBo.setModelName(\"deepseek-chat\");\nchatBo.setTemperature(0.7);\nchatBo.setMaxTokens(2000);\n\n// 调用接口\nR<AiChatVo> result = aiController.aiChat(chatBo);\nAiChatVo response = result.getData();\nSystem.out.println(\"AI回复: \" + response.getMessage());\n```\n\n#### HTTP 调用示例\n\n```bash\nPOST /base/ai/aiChat\nContent-Type: application/json\n\n{\n \"message\": \"请帮我解释一下什么是微服务架构\",\n \"provider\": \"deepseek\",\n \"modelName\": \"deepseek-chat\",\n \"temperature\": 0.7,\n \"maxTokens\": 2000\n}\n```\n\n### 2. 文本优化功能\n\n对用户输入的文本进行优化,改善表达和文风。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiOptimize\")\n@OpenApi(value = \"AI文本优化\")\npublic R<AiChatVo> aiOptimize(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiOptimize(bo));\n}\n```\n\n#### 使用场景\n\n- 文章润色和改写\n- 产品描述优化\n- 邮件内容优化\n- 广告文案优化\n\n#### 请求示例\n\n```java\nAiChatBo optimizeBo = new AiChatBo();\noptimizeBo.setMessage(\"我们公司是做软件开发的,主要业务是给客户做系统\");\noptimizeBo.setAiFeature(\"optimize\");\noptimizeBo.setSystemPrompt(\"请将下列文本优化为更专业的企业简介\");\n\nR<AiChatVo> result = aiController.aiOptimize(optimizeBo);\n// 优化后: \"我们是一家专业的软件开发公司,致力于为企业客户提供定制化系统解决方案...\"\n```\n\n### 3. 数据生成功能\n\n根据用户需求生成结构化数据或内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiGenerate\")\n@OpenApi(value = \"AI数据生成\")\npublic R<AiChatVo> aiGenerate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiGenerate(bo));\n}\n```\n\n#### 使用场景\n\n- 生成测试数据\n- 生成产品描述\n- 生成代码片段\n- 生成用户画像\n\n#### 请求示例\n\n```java\nAiChatBo generateBo = new AiChatBo();\ngenerateBo.setMessage(\"生成5个用户的测试数据,包含姓名、年龄、邮箱\");\ngenerateBo.setAiFeature(\"generate\");\n\n// 传递表单字段信息作为上下文\nMap<String, Object> context = new HashMap<>();\ncontext.put(\"fields\", Arrays.asList(\"name\", \"age\", \"email\"));\ncontext.put(\"count\", 5);\ngenerateBo.setContext(context);\n\nR<AiChatVo> result = aiController.aiGenerate(generateBo);\n```\n\n**生成结果示例:**\n```json\n[\n {\"name\": \"张三\", \"age\": 28, \"email\": \"zhangsan@example.com\"},\n {\"name\": \"李四\", \"age\": 32, \"email\": \"lisi@example.com\"},\n {\"name\": \"王五\", \"age\": 25, \"email\": \"wangwu@example.com\"},\n {\"name\": \"赵六\", \"age\": 30, \"email\": \"zhaoliu@example.com\"},\n {\"name\": \"钱七\", \"age\": 27, \"email\": \"qianqi@example.com\"}\n]\n```\n\n### 4. 内容审核功能\n\n对用户提交的内容进行智能审核,检测违规内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiReview\")\n@OpenApi(value = \"AI内容审核\")\npublic R<AiChatVo> aiReview(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiReview(bo));\n}\n```\n\n#### 使用场景\n\n- 评论内容审核\n- 文章内容审核\n- 用户昵称审核\n- 敏感词检测\n\n#### 请求示例\n\n```java\nAiChatBo reviewBo = new AiChatBo();\nreviewBo.setMessage(\"待审核的用户评论内容...\");\nreviewBo.setAiFeature(\"review\");\nreviewBo.setSystemPrompt(\"请审核以下内容是否包含违规、敏感、广告等不当信息\");\n\nR<AiChatVo> result = aiController.aiReview(reviewBo);\nAiChatVo response = result.getData();\n\n// 解析审核结果\nif (response.getMessage().contains(\"通过\")) {\n // 内容合规,允许发布\n} else {\n // 内容违规,拒绝发布\n}\n```\n\n### 5. 文本翻译功能\n\n提供多语言翻译服务。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiTranslate\")\n@OpenApi(value = \"AI文本翻译\")\npublic R<AiChatVo> aiTranslate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiTranslate(bo));\n}\n```\n\n#### 使用场景\n\n- 多语言网站内容翻译\n- 用户评论翻译\n- 产品说明翻译\n- 客服消息翻译\n\n#### 请求示例\n\n```java\nAiChatBo translateBo = new AiChatBo();\ntranslateBo.setMessage(\"Hello, how are you today?\");\ntranslateBo.setAiFeature(\"translate\");\ntranslateBo.setSystemPrompt(\"请将以下英文翻译成中文\");\n\nR<AiChatVo> result = aiController.aiTranslate(translateBo);\n// 翻译结果: \"你好,你今天怎么样?\"\n```\n\n### AI配置说明\n\n#### LangChain4j 配置\n\n在 `application.yml` 中配置 LangChain4j:\n\n```yaml\nlangchain4j:\n enabled: true # 启用AI功能\n\n # DeepSeek 配置\n deepseek:\n api-key: ${DEEPSEEK_API_KEY}\n base-url: https://api.deepseek.com/v1\n model-name: deepseek-chat\n temperature: 0.7\n max-tokens: 2000\n timeout: 60s\n\n # 通义千问配置\n qianwen:\n api-key: ${QIANWEN_API_KEY}\n base-url: https://dashscope.aliyuncs.com/api/v1\n model-name: qwen-plus\n temperature: 0.7\n max-tokens: 2000\n\n # OpenAI 配置\n openai:\n api-key: ${OPENAI_API_KEY}\n base-url: https://api.openai.com/v1\n model-name: gpt-3.5-turbo\n temperature: 0.7\n max-tokens: 2000\n```\n\n#### 环境变量配置\n\n推荐使用环境变量管理敏感的API密钥:\n\n```bash\n# .env 文件\nDEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nQIANWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nOPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n#### 权限配置\n\n在菜单管理中配置AI功能权限:\n\n```sql\n-- AI对话权限\nINSERT INTO sys_menu (menu_name, parent_id, perms)\nVALUES ('AI对话', 1000, 'base:ai:chat');\n```\n\n### AI功能集成示例\n\n#### 示例1:智能客服回复\n\n```java\n@Service\npublic class CustomerServiceImpl implements ICustomerService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public String handleCustomerQuestion(String question) {\n AiChatBo chatBo = new AiChatBo();\n chatBo.setMessage(question);\n chatBo.setProvider(\"deepseek\");\n chatBo.setSystemPrompt(\"你是一个友好的客服助手,请专业地回答客户问题\");\n\n AiChatVo response = aiService.aiChat(chatBo);\n return response.getMessage();\n }\n}\n```\n\n#### 示例2:文章内容审核\n\n```java\n@Service\npublic class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public boolean publishArticle(Article article) {\n // 使用AI审核文章内容\n AiChatBo reviewBo = new AiChatBo();\n reviewBo.setMessage(article.getContent());\n reviewBo.setAiFeature(\"review\");\n reviewBo.setSystemPrompt(\"请审核文章内容是否合规,检查是否包含违规、敏感信息\");\n\n AiChatVo reviewResult = aiService.aiReview(reviewBo);\n\n // 判断审核结果\n if (reviewResult.getMessage().contains(\"违规\")) {\n throw new ServiceException(\"文章内容审核未通过: \" + reviewResult.getMessage());\n }\n\n // 审核通过,发布文章\n article.setStatus(\"published\");\n return this.updateById(article);\n }\n}\n```\n\n#### 示例3:数据智能生成\n\n```java\n@Service\npublic class DataGeneratorService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public List<User> generateTestUsers(int count) {\n AiChatBo generateBo = new AiChatBo();\n generateBo.setMessage(\n String.format(\"生成%d个用户测试数据,包含真实的中文姓名、邮箱、手机号\", count)\n );\n generateBo.setAiFeature(\"generate\");\n\n // 传递数据结构上下文\n Map<String, Object> context = new HashMap<>();\n context.put(\"format\", \"json\");\n context.put(\"fields\", Arrays.asList(\"name\", \"email\", \"phone\", \"age\", \"gender\"));\n generateBo.setContext(context);\n\n AiChatVo response = aiService.aiGenerate(generateBo);\n\n // 解析生成的JSON数据\n return JsonUtils.parseArray(response.getMessage(), User.class);\n }\n}\n```\n\n## 数据访问层架构\n\n### DAO模式说明\n\n基础服务模块采用 **DAO(Data Access Object)** 模式,将数据访问逻辑与业务逻辑分离,提供更清晰的架构层次。\n\n#### 架构层次\n\n```text\nController 层\n ↓\nService 层\n ↓\nDAO 层 (IBaseDao)\n ↓\nEntity 层 (数据库实体)\n```\n\n#### IBaseDao 接口\n\n所有 DAO 接口都继承自 `IBaseDao`,提供统一的 CRUD 操作:\n\n```java\npublic interface IBaseDao<T> {\n // 插入\n boolean insert(T entity);\n boolean insertBatch(Collection<T> entityList);\n\n // 更新\n boolean updateById(T entity);\n boolean updateBatchById(Collection<T> entityList);\n\n // 删除\n boolean deleteById(Serializable id);\n boolean deleteBatchIds(Collection<?> idList);\n\n // 查询\n T selectById(Serializable id);\n List<T> selectBatchIds(Collection<? extends Serializable> idList);\n List<T> selectList(Wrapper<T> queryWrapper);\n T selectOne(Wrapper<T> queryWrapper);\n Long selectCount(Wrapper<T> queryWrapper);\n\n // 分页查询\n Page<T> selectPage(Page<T> page, Wrapper<T> queryWrapper);\n}\n```\n\n### 平台配置DAO (IPlatformDao)\n\n```java\npublic interface IPlatformDao extends IBaseDao<Platform> {\n\n /**\n * 根据业务对象构建查询条件\n */\n PlusLambdaQuery<Platform> buildQueryWrapper(PlatformBo bo);\n\n /**\n * 根据appid查询平台配置\n */\n Platform getByAppid(String appid);\n\n /**\n * 根据appid和平台类型查询平台配置\n */\n Platform getByAppidAndType(String appid, String type, String status);\n\n /**\n * 根据平台类型和状态查询配置列表\n */\n List<Platform> listByTypeAndStatus(String type, String status);\n}\n```\n\n### 支付配置DAO (IPaymentDao)\n\n```java\npublic interface IPaymentDao extends IBaseDao<Payment> {\n\n /**\n * 根据商户号查询支付配置\n */\n Payment getByMchId(String mchId, String status);\n\n /**\n * 根据支付类型和状态查询配置列表\n */\n List<Payment> listByTypeAndStatus(String type, String status);\n\n /**\n * 根据状态统计配置数量\n */\n long countByStatus(String status);\n\n /**\n * 根据商户号查询是否存在(排除指定ID)\n */\n boolean existsByMchId(String mchId, Long excludeId);\n\n /**\n * 根据商户号和状态判断是否存在\n */\n boolean existsByMchIdAndStatus(String mchId, String status);\n\n /**\n * 根据状态查询配置列表\n */\n List<Payment> listByStatus(String status);\n}\n```\n\n### DAO层使用示例\n\n```java\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private IPlatformDao platformDao;\n\n @Override\n public PlatformVo getWeixinPlatform(String appid) {\n // 使用DAO查询微信小程序配置\n Platform platform = platformDao.getByAppidAndType(\n appid,\n \"mp-weixin\",\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (platform == null) {\n throw new ServiceException(\"未找到微信小程序配置\");\n }\n\n return BeanUtil.toBean(platform, PlatformVo.class);\n }\n\n @Override\n public List<PlatformVo> listActivePlatforms(String type) {\n // 使用DAO查询所有启用的平台配置\n List<Platform> platforms = platformDao.listByTypeAndStatus(\n type,\n DictEnableStatus.ENABLE.getValue()\n );\n\n return BeanUtil.copyToList(platforms, PlatformVo.class);\n }\n}\n```\n\n## 高级功能\n\n### 多租户支持\n\n基础服务模块所有实体类都继承自 `TenantEntity`,自动支持多租户数据隔离。\n\n#### 租户实体基类\n\n```java\n@Data\npublic class TenantEntity extends BaseEntity {\n\n /**\n * 租户ID\n */\n @TableField(value = \"tenant_id\")\n private String tenantId;\n\n /**\n * 创建部门\n */\n @TableField(value = \"create_dept\")\n private Long createDept;\n}\n```\n\n#### 自动租户隔离\n\n```java\n// 查询时自动添加租户条件\nPlatform platform = platformDao.selectById(platformId);\n// SQL: SELECT * FROM b_platform WHERE id = ? AND tenant_id = '当前租户ID'\n\n// 新增时自动填充租户ID\nPlatform newPlatform = new Platform();\nnewPlatform.setType(\"mp-weixin\");\nplatformDao.insert(newPlatform);\n// SQL: INSERT INTO b_platform (..., tenant_id) VALUES (..., '当前租户ID')\n```\n\n### 数据缓存机制\n\n#### Redis缓存配置\n\n平台配置和支付配置支持Redis缓存,提升查询性能:\n\n```java\n@Service\npublic class PlatformCacheService {\n\n private static final String PLATFORM_CACHE_KEY = \"platform:config:\";\n private static final Duration CACHE_EXPIRE = Duration.ofHours(1);\n\n @Autowired\n private RedisTemplate<String, Platform> redisTemplate;\n\n @Autowired\n private IPlatformDao platformDao;\n\n public Platform getPlatformWithCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n\n // 尝试从缓存获取\n Platform platform = redisTemplate.opsForValue().get(cacheKey);\n if (platform != null) {\n return platform;\n }\n\n // 缓存未命中,查询数据库\n platform = platformDao.getByAppid(appid);\n if (platform != null) {\n // 写入缓存\n redisTemplate.opsForValue().set(cacheKey, platform, CACHE_EXPIRE);\n }\n\n return platform;\n }\n\n public void clearPlatformCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n redisTemplate.delete(cacheKey);\n }\n}\n```\n\n### 事件监听机制\n\n#### 配置变更事件\n\n```java\n@Component\npublic class PlatformConfigEventListener {\n\n @Autowired\n private WxMaApplicationRunner wxMaRunner;\n\n @Autowired\n private WxMpApplicationRunner wxMpRunner;\n\n /**\n * 监听平台配置变更事件\n */\n @EventListener\n public void handlePlatformConfigChange(PlatformConfigChangeEvent event) {\n String tenantId = event.getTenantId();\n String platformType = event.getPlatformType();\n\n // 根据平台类型重新初始化配置\n if (\"mp-weixin\".equals(platformType)) {\n wxMaRunner.initByTenant(tenantId);\n } else if (\"mp-official-account\".equals(platformType)) {\n wxMpRunner.initByTenant(tenantId);\n }\n\n log.info(\"平台配置已更新: tenantId={}, platformType={}\", tenantId, platformType);\n }\n}\n```\n\n#### 自定义事件\n\n```java\n@Data\npublic class PlatformConfigChangeEvent extends ApplicationEvent {\n\n private String tenantId;\n private String platformType;\n private String action; // create, update, delete\n\n public PlatformConfigChangeEvent(Object source, String tenantId, String platformType, String action) {\n super(source);\n this.tenantId = tenantId;\n this.platformType = platformType;\n this.action = action;\n }\n}\n\n// 发布事件\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private ApplicationEventPublisher eventPublisher;\n\n @Override\n @Transactional\n public boolean updatePlatform(PlatformBo bo) {\n boolean result = platformDao.updateById(BeanUtil.toBean(bo, Platform.class));\n\n if (result) {\n // 发布配置变更事件\n eventPublisher.publishEvent(\n new PlatformConfigChangeEvent(this, TenantHelper.getTenantId(), bo.getType(), \"update\")\n );\n }\n\n return result;\n }\n}\n```\n\n## 常见问题\n\n### Q1: 平台配置不生效?\n\n**问题原因:**\n- 配置状态未启用\n- 租户ID不匹配\n- 缓存未更新\n- appid配置错误\n\n**解决方案:**\n\n```java\n// 1. 检查配置状态\nPlatform platform = platformDao.getByAppid(appid);\nif (!\"1\".equals(platform.getStatus())) {\n throw new ServiceException(\"平台配置未启用\");\n}\n\n// 2. 检查租户ID\nString currentTenantId = TenantHelper.getTenantId();\nif (!currentTenantId.equals(platform.getTenantId())) {\n throw new ServiceException(\"平台配置不属于当前租户\");\n}\n\n// 3. 清除缓存重新加载\nwxMaApplicationRunner.initByTenant(currentTenantId);\n```\n\n### Q2: 第三方登录失败?\n\n**问题原因:**\n- appid或secret配置错误\n- 授权码已过期\n- 平台配置未找到\n- 网络连接问题\n\n**解决方案:**\n\n```java\ntry {\n // 使用授权码登录\n AuthTokenVo authToken = authStrategy.login(loginBody);\n} catch (WxErrorException e) {\n // 微信接口调用失败\n log.error(\"微信登录失败: errCode={}, errMsg={}\", e.getError().getErrorCode(), e.getError().getErrorMsg());\n\n if (e.getError().getErrorCode() == 40029) {\n throw new ServiceException(\"授权码无效或已过期,请重新授权\");\n } else if (e.getError().getErrorCode() == 40013) {\n throw new ServiceException(\"appid配置错误\");\n } else {\n throw new ServiceException(\"登录失败: \" + e.getError().getErrorMsg());\n }\n}\n```\n\n### Q3: 支付配置重复?\n\n**问题原因:**\n- 同一商户号被多次配置\n- 未进行唯一性校验\n\n**解决方案:**\n\n```java\n@Service\npublic class PaymentServiceImpl implements IPaymentService {\n\n @Override\n public boolean addPayment(PaymentBo bo) {\n // 检查商户号是否已存在\n boolean exists = paymentDao.existsByMchIdAndStatus(\n bo.getMchId(),\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (exists) {\n throw new ServiceException(\"该商户号已存在有效配置\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.insert(payment);\n }\n\n @Override\n public boolean updatePayment(PaymentBo bo) {\n // 检查商户号是否与其他记录重复(排除当前记录)\n boolean exists = paymentDao.existsByMchId(bo.getMchId(), bo.getId());\n\n if (exists) {\n throw new ServiceException(\"该商户号已被其他配置使用\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.updateById(payment);\n }\n}\n```\n\n### Q4: AI功能无法使用?\n\n**问题原因:**\n- LangChain4j未启用\n- API密钥配置错误\n- 网络连接问题\n- 权限未配置\n\n**解决方案:**\n\n```yaml\n# 1. 确保配置已启用\nlangchain4j:\n enabled: true # 必须为 true\n\n# 2. 检查API密钥\ndeepseek:\n api-key: ${DEEPSEEK_API_KEY} # 确保环境变量已设置\n\n# 3. 测试网络连接\ncurl -X POST https://api.deepseek.com/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'\n\n# 4. 配置权限\nINSERT INTO sys_menu (menu_name, perms) VALUES ('AI对话', 'base:ai:chat');\n```\n\n## 故障排查\n\n### 日志配置\n\n#### 启用详细日志\n\n```yaml\nlogging:\n level:\n plus.ruoyi.business.base: DEBUG\n plus.ruoyi.business.base.controller: DEBUG\n plus.ruoyi.business.base.service: DEBUG\n plus.ruoyi.business.base.dao: DEBUG\n plus.ruoyi.business.base.authStrategy: DEBUG\n```\n\n### 常见错误及解决方案\n\n#### 错误1: 平台配置未找到\n\n```text\n错误信息: ServiceException: 未找到平台配置\n```\n\n**排查步骤:**\n1. 检查数据库中是否存在配置记录\n2. 检查appid是否正确\n3. 检查配置状态是否启用\n4. 检查租户ID是否匹配\n\n```java\n// 调试代码\nPlatform platform = platformDao.selectOne(\n new LambdaQueryWrapper<Platform>()\n .eq(Platform::getAppid, appid)\n);\nSystem.out.println(\"查询到的平台配置: \" + JsonUtils.toJsonString(platform));\n```\n\n#### 错误2: 认证策略未找到\n\n```text\n错误信息: No bean named 'miniappAuthStrategy' available\n```\n\n**排查步骤:**\n1. 检查认证策略类是否标注 `@Service` 注解\n2. 检查策略名称是否正确\n3. 检查Spring扫描路径是否包含策略类\n\n```java\n// 正确的策略命名\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME) // miniappAuthStrategy\npublic class MiniappAuthStrategy implements IAuthStrategy {\n // ...\n}\n```\n\n#### 错误3: 多租户数据泄露\n\n```text\n错误信息: 查询到了其他租户的数据\n```\n\n**排查步骤:**\n1. 检查实体类是否继承 `TenantEntity`\n2. 检查租户拦截器是否生效\n3. 检查数据表是否包含 `tenant_id` 字段\n\n```java\n// 确保实体类正确继承\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n // 自动支持租户隔离\n}\n```\n\n## API参考\n\n### Controller接口清单\n\n| 控制器 | 路径 | 功能说明 |\n|--------|------|----------|\n| PlatformController | `/base/platform/*` | 平台配置管理 |\n| PaymentController | `/base/payment/*` | 支付配置管理 |\n| BindController | `/base/bind/*` | 账号绑定管理 |\n| AdController | `/base/ad/*` | 广告配置管理 |\n| AiController | `/base/ai/*` | AI助手功能 |\n\n### 核心接口详情\n\n#### 平台配置接口\n\n```java\nGET /base/platform/list 查询平台配置列表\nGET /base/platform/{id} 查询平台配置详情\nPOST /base/platform 新增平台配置\nPUT /base/platform 更新平台配置\nDELETE /base/platform/{ids} 删除平台配置\nGET /base/platform/dict 获取平台字典\n```\n\n#### 支付配置接口\n\n```java\nGET /base/payment/list 查询支付配置列表\nGET /base/payment/{id} 查询支付配置详情\nPOST /base/payment 新增支付配置\nPUT /base/payment 更新支付配置\nDELETE /base/payment/{ids} 删除支付配置\nGET /base/payment/dict 获取支付方式字典\n```\n\n#### 账号绑定接口\n\n```java\nGET /base/bind/list 查询绑定列表\nPOST /base/bind/bindPhone 绑定手机号\nPOST /base/bind/unbind 解除绑定\n```\n\n#### AI助手接口\n\n```java\nPOST /base/ai/aiChat AI对话\nPOST /base/ai/aiOptimize 文本优化\nPOST /base/ai/aiGenerate 数据生成\nPOST /base/ai/aiReview 内容审核\nPOST /base/ai/aiTranslate 文本翻译\n```\n\n## 最佳实践\n\n### 配置管理\n- 敏感信息(如密钥)使用环境变量或加密存储\n- 支持配置热更新,通过事件机制通知相关服务\n- 按租户隔离配置,确保数据安全\n- 使用Redis缓存常用配置,提升性能\n\n### 安全考虑\n- 登录令牌设置合理的过期时间(建议2小时)\n- 敏感API添加 `@SaCheckPermission` 权限校验\n- 支付配置访问权限严格控制\n- AI接口调用添加频率限制,防止滥用\n- API密钥使用环境变量管理,不提交到代码仓库\n\n### 性能优化\n- 平台配置和支付配置使用Redis缓存,有效期1小时\n- 异步处理配置更新,使用Spring事件机制\n- 合理使用数据库索引(appid、mchId等字段)\n- AI接口调用使用连接池,复用HTTP连接\n- 批量查询使用 `selectBatchIds` 而不是循环查询\n\n### 扩展建议\n- 新增平台时,实现对应的 `IAuthStrategy` 认证策略\n- 支付方式扩展遵循统一的 DAO 接口规范\n- 配置项变更通过 `ApplicationEventPublisher` 发布事件\n- AI功能扩展可添加新的服务方法,保持接口一致性\n- 建议为每个租户配置独立的平台和支付配置\n"}, "d6768318945b2253c42088175a92e4d6a62be910": {"t": 1785765304.0229049, "n": 27735, "h": "72144b0794344a02", "c": "# 基础服务模块 (base)\n\n基础服务模块提供了系统运行所需的核心基础服务,包括多平台配置管理、支付配置管理、广告配置、账号绑定等功能。\n\n## 模块结构\n\n```text\nbase/\n├── controller/ # 控制器层\n│ ├── AdController.java\n│ ├── BindController.java\n│ ├── PaymentController.java\n│ └── PlatformController.java\n├── service/ # 服务层\n│ ├── IAdService.java\n│ ├── IBindService.java\n│ ├── IPaymentService.java\n│ └── IPlatformService.java\n├── domain/ # 数据模型\n│ ├── entity/ # 实体类\n│ ├── vo/ # 视图对象\n│ └── bo/ # 业务对象\n├── mapper/ # 数据访问层\n└── authStrategy/ # 认证策略\n```\n\n## 核心功能\n\n### 平台配置管理\n\n支持多种平台的统一配置管理:\n\n- **微信小程序** (mp-weixin)\n- **微信公众号** (mp-official-account)\n- **支付宝小程序** (mp-alipay)\n- **QQ小程序** (mp-qq)\n- **其他平台** (mp-jd, mp-kuaishou, mp-lark, mp-baidu, mp-toutiao, mp-xhs)\n\n#### 平台配置实体\n```java\n@Data\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n private Long id; // 平台配置ID\n private String type; // 平台类型\n private String name; // 平台名称\n private String appid; // 应用ID\n private String secret; // 应用密钥\n private String token; // 接口Token\n private String aeskey; // 加密密钥\n private String paymentIds; // 关联支付配置\n private String templateConfigs; // 模板配置\n private String status; // 状态\n}\n```\n\n#### 核心接口\n```java\npublic interface IPlatformService extends IBaseService<Platform, PlatformBo, PlatformVo> {\n // 继承基础CRUD操作\n}\n\n// 全局平台服务\npublic interface PlatformService {\n List<PlatformDTO> listPlatformsByType(String type, String tenantId);\n PlatformDTO getPlatformByAppidAndType(String appid, String type);\n PlatformDTO getPlatformByAppid(String appid, String tenantId);\n}\n```\n\n### 支付配置管理\n\n统一的支付配置管理,支持多种支付方式:\n\n#### 支付配置实体\n```java\n@Data\n@TableName(\"b_payment\") \npublic class Payment extends TenantEntity {\n private Long id; // 支付配置ID\n private String type; // 商户类型\n private String mchName; // 商户名称\n private String mchId; // 商户号\n private String mchKey; // 商户密钥\n private String apiV3Key; // APIv3密钥\n private String certPath; // 证书路径\n private String keyPath; // 密钥路径\n private String certSerialNo; // 证书序列号\n private String status; // 状态\n}\n```\n\n#### 核心服务\n```java\npublic interface PaymentService {\n List<PaymentDTO> listPaymentByType(String type, String tenantId);\n PaymentDTO getByMchId(String mchId);\n PaymentDTO getById(Long paymentId);\n boolean existsValidMchId(String mchId);\n long countPayments();\n}\n```\n\n### 账号绑定管理\n\n管理用户在不同平台的账号绑定关系:\n\n#### 绑定实体\n```java\n@Data\n@TableName(\"b_bind\")\npublic class Bind extends TenantEntity {\n private Long id; // 绑定ID\n private Long userId; // 用户ID\n private String platformType; // 平台类型\n private String appid; // 应用ID\n private String unionid; // 统一标识\n private String openid; // 平台标识\n private String extraData; // 扩展数据\n}\n```\n\n#### 绑定服务\n```java\npublic interface IBindService extends IBaseService<Bind, BindBo, BindVo> {\n /**\n * 根据平台用户信息获取或创建绑定信息\n */\n BindVo getOrCreateBind(PlatformUserInfoVo platformUserInfoVo);\n \n /**\n * 更新绑定信息的用户ID\n */\n void updateBindUserId(BindBo bindBo, Long userId);\n}\n```\n\n### 广告配置管理\n\n提供广告位和广告内容的统一管理:\n\n#### 广告实体\n```java\n@Data\n@TableName(\"b_ad\")\npublic class Ad extends TenantEntity {\n private Long id; // 广告ID\n private String appid; // 应用ID\n private String adUnitId; // 广告位ID\n private String adName; // 广告名称\n private String adType; // 广告类型\n private String position; // 投放位置\n private String img; // 广告图片\n private String description; // 描述\n private String jumpAppid; // 跳转应用ID\n private String jumpPath; // 跳转路径\n private String styleConfig; // 样式配置\n private Long sortOrder; // 排序值\n private String status; // 状态\n}\n```\n\n## 认证策略\n\n### 多平台认证架构\n\n基于策略模式实现多平台登录认证:\n\n#### 认证策略接口\n```java\npublic interface IAuthStrategy {\n String BASE_NAME = \"AuthStrategy\";\n AuthTokenVo login(String body);\n}\n```\n\n#### 小程序认证策略\n```java\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME)\npublic class MiniappAuthStrategy implements IAuthStrategy {\n \n @Override\n public AuthTokenVo login(String body) {\n // 1. 解析请求参数\n PlatformLoginBody loginBody = JsonUtils.parseObject(body, PlatformLoginBody.class);\n \n // 2. 获取平台用户信息\n PlatformUserInfoVo platformUserInfo = getMiniappUserIdentity(loginBody);\n \n // 3. 加载或创建用户\n SysUserVo user = loadOrCreateUser(platformUserInfo);\n \n // 4. 生成登录令牌\n LoginUser loginUser = loginService.createLoginUser(user);\n loginUser.setPlatform(platformUserInfo.getPlatform());\n loginUser.setAppid(platformUserInfo.getAppid());\n loginUser.setOpenid(platformUserInfo.getOpenid());\n loginUser.setUnionid(platformUserInfo.getUnionid());\n \n // 5. 完成登录\n LoginHelper.login(loginUser, loginParameter);\n \n // 6. 返回认证结果\n AuthTokenVo authTokenVo = new AuthTokenVo();\n authTokenVo.setAccessToken(StpUtil.getTokenValue());\n authTokenVo.setExpireIn(StpUtil.getTokenTimeout());\n return authTokenVo;\n }\n}\n```\n\n#### 公众号认证策略\n```java\n@Service(\"mp\" + IAuthStrategy.BASE_NAME)\npublic class MpAuthStrategy implements IAuthStrategy {\n // 公众号OAuth2.0认证流程实现\n // 支持网页授权登录场景\n}\n```\n\n### 认证流程\n\n1. **前端授权**:用户在前端完成平台授权,获取授权码\n2. **策略选择**:后端根据平台类型自动选择对应认证策略\n3. **信息获取**:通过授权码换取用户基本信息\n4. **账号绑定**:查找或创建用户账号绑定关系\n5. **令牌生成**:生成JWT访问令牌\n6. **登录完成**:返回令牌和用户信息\n\n## 手机号绑定\n\n### 微信小程序手机号获取\n```java\n@PostMapping(\"/bindPhone\")\npublic R<PhoneBindVo> bindPhone(@RequestBody PhoneBindBo bo) {\n LoginUser loginUser = LoginHelper.getLoginUser();\n wxMaService.switchover(loginUser.getAppid());\n \n try {\n WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(bo.getCode());\n String phone = phoneInfo.getPhoneNumber();\n \n // 更新用户手机号\n SysUser sysUser = userMapper.selectById(loginUser.getUserId());\n sysUser.setPhone(phone);\n userMapper.updateById(sysUser);\n \n return R.ok(\"绑定成功\", PhoneBindVo.of(phone));\n } catch (WxErrorException e) {\n return R.fail(\"获取手机号出错\");\n }\n}\n```\n\n## 数据字典服务\n\n### 支付方式字典\n```java\n@GetMapping(\"getPaymentDict\")\npublic R<List<DictItemVo>> getPaymentDict() {\n // 查询所有可用的支付方式\n List<PaymentVo> paymentVoList = paymentService.list(\n PlusLambdaQuery.of(Payment.class)\n .eq(Payment::getStatus, DictEnableStatus.ENABLE.getValue()));\n \n // 构建字典项列表\n List<DictItemVo> dictItems = StreamUtils.toList(paymentVoList, payment ->\n DictItemVo.of(payment.getMchName(), payment.getId().toString(), \"success\")\n );\n return R.ok(dictItems);\n}\n```\n\n## 配置管理\n\n### 平台配置热更新\n```java\nprivate void reloadPlatformConfig() {\n String tenantId = TenantHelper.getTenantId();\n \n // 重新初始化微信小程序配置\n SpringUtils.getBean(WxMaApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化微信公众号配置 \n SpringUtils.getBean(WxMpApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化支付配置\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n### 支付配置热更新\n```java\nprivate void reloadPaymentConfig() {\n String tenantId = TenantHelper.getTenantId();\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n## 使用示例\n\n### 配置微信小程序\n```java\n// 1. 创建平台配置\nPlatformBo platformBo = new PlatformBo();\nplatformBo.setType(\"mp-weixin\");\nplatformBo.setName(\"我的小程序\");\nplatformBo.setAppid(\"wx1234567890\");\nplatformBo.setSecret(\"your-secret\");\nplatformBo.setStatus(\"1\");\nplatformService.add(platformBo);\n\n// 2. 配置支付信息\nPaymentBo paymentBo = new PaymentBo();\npaymentBo.setType(\"wechat\");\npaymentBo.setMchName(\"我的商户\");\npaymentBo.setMchId(\"1234567890\");\npaymentBo.setMchKey(\"your-mch-key\");\npaymentBo.setStatus(\"1\");\npaymentService.add(paymentBo);\n```\n\n### 用户登录认证\n```java\n// 前端调用登录接口\nPOST /auth/login\n{\n \"platform\": \"miniapp\",\n \"body\": {\n \"platform\": \"mp-weixin\",\n \"appid\": \"wx1234567890\",\n \"platformCode\": \"授权码\"\n }\n}\n\n// 返回结果\n{\n \"code\": 200,\n \"msg\": \"登录成功\",\n \"data\": {\n \"accessToken\": \"eyJ0eXAiOiJKV1Q...\",\n \"expireIn\": 7200\n }\n}\n```\n\n## AI助手功能\n\n### 功能概述\n\n基础服务模块集成了强大的AI助手功能,基于 **LangChain4j** 框架实现,支持多种大语言模型(如 DeepSeek、通义千问、OpenAI、Claude等),为业务系统提供智能化能力。\n\n**核心特性:**\n- **多模型支持** - 灵活切换不同的AI模型提供商\n- **多场景应用** - 对话、优化、生成、审核、翻译等场景\n- **条件启用** - 通过配置开关控制功能启用\n- **权限控制** - 完善的权限校验机制\n- **上下文传递** - 支持业务上下文信息传递\n\n### AI服务接口\n\n#### AiController 控制器\n\n```java\n@RestController\n@RequestMapping(\"/base/ai\")\n@ConditionalOnProperty(\n prefix = \"langchain4j\",\n name = \"enabled\",\n havingValue = \"true\",\n matchIfMissing = true\n)\npublic class AiController {\n private final IAiService aiService;\n}\n```\n\n**条件启用说明:**\n- 需要在配置文件中设置 `langchain4j.enabled=true`\n- 如果配置项不存在,默认启用 (`matchIfMissing = true`)\n\n### 1. AI对话功能\n\n通用的AI对话接口,支持自由对话场景。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiChat\")\n@OpenApi(value = \"AI对话\")\npublic R<AiChatVo> aiChat(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiChat(bo));\n}\n```\n\n#### 请求示例\n\n```java\n// 创建对话请求\nAiChatBo chatBo = new AiChatBo();\nchatBo.setMessage(\"请帮我解释一下什么是微服务架构\");\nchatBo.setProvider(\"deepseek\");\nchatBo.setModelName(\"deepseek-chat\");\nchatBo.setTemperature(0.7);\nchatBo.setMaxTokens(2000);\n\n// 调用接口\nR<AiChatVo> result = aiController.aiChat(chatBo);\nAiChatVo response = result.getData();\nSystem.out.println(\"AI回复: \" + response.getMessage());\n```\n\n#### HTTP 调用示例\n\n```bash\nPOST /base/ai/aiChat\nContent-Type: application/json\n\n{\n \"message\": \"请帮我解释一下什么是微服务架构\",\n \"provider\": \"deepseek\",\n \"modelName\": \"deepseek-chat\",\n \"temperature\": 0.7,\n \"maxTokens\": 2000\n}\n```\n\n### 2. 文本优化功能\n\n对用户输入的文本进行优化,改善表达和文风。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiOptimize\")\n@OpenApi(value = \"AI文本优化\")\npublic R<AiChatVo> aiOptimize(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiOptimize(bo));\n}\n```\n\n#### 使用场景\n\n- 文章润色和改写\n- 产品描述优化\n- 邮件内容优化\n- 广告文案优化\n\n#### 请求示例\n\n```java\nAiChatBo optimizeBo = new AiChatBo();\noptimizeBo.setMessage(\"我们公司是做软件开发的,主要业务是给客户做系统\");\noptimizeBo.setAiFeature(\"optimize\");\noptimizeBo.setSystemPrompt(\"请将下列文本优化为更专业的企业简介\");\n\nR<AiChatVo> result = aiController.aiOptimize(optimizeBo);\n// 优化后: \"我们是一家专业的软件开发公司,致力于为企业客户提供定制化系统解决方案...\"\n```\n\n### 3. 数据生成功能\n\n根据用户需求生成结构化数据或内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiGenerate\")\n@OpenApi(value = \"AI数据生成\")\npublic R<AiChatVo> aiGenerate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiGenerate(bo));\n}\n```\n\n#### 使用场景\n\n- 生成测试数据\n- 生成产品描述\n- 生成代码片段\n- 生成用户画像\n\n#### 请求示例\n\n```java\nAiChatBo generateBo = new AiChatBo();\ngenerateBo.setMessage(\"生成5个用户的测试数据,包含姓名、年龄、邮箱\");\ngenerateBo.setAiFeature(\"generate\");\n\n// 传递表单字段信息作为上下文\nMap<String, Object> context = new HashMap<>();\ncontext.put(\"fields\", Arrays.asList(\"name\", \"age\", \"email\"));\ncontext.put(\"count\", 5);\ngenerateBo.setContext(context);\n\nR<AiChatVo> result = aiController.aiGenerate(generateBo);\n```\n\n**生成结果示例:**\n```json\n[\n {\"name\": \"张三\", \"age\": 28, \"email\": \"zhangsan@example.com\"},\n {\"name\": \"李四\", \"age\": 32, \"email\": \"lisi@example.com\"},\n {\"name\": \"王五\", \"age\": 25, \"email\": \"wangwu@example.com\"},\n {\"name\": \"赵六\", \"age\": 30, \"email\": \"zhaoliu@example.com\"},\n {\"name\": \"钱七\", \"age\": 27, \"email\": \"qianqi@example.com\"}\n]\n```\n\n### 4. 内容审核功能\n\n对用户提交的内容进行智能审核,检测违规内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiReview\")\n@OpenApi(value = \"AI内容审核\")\npublic R<AiChatVo> aiReview(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiReview(bo));\n}\n```\n\n#### 使用场景\n\n- 评论内容审核\n- 文章内容审核\n- 用户昵称审核\n- 敏感词检测\n\n#### 请求示例\n\n```java\nAiChatBo reviewBo = new AiChatBo();\nreviewBo.setMessage(\"待审核的用户评论内容...\");\nreviewBo.setAiFeature(\"review\");\nreviewBo.setSystemPrompt(\"请审核以下内容是否包含违规、敏感、广告等不当信息\");\n\nR<AiChatVo> result = aiController.aiReview(reviewBo);\nAiChatVo response = result.getData();\n\n// 解析审核结果\nif (response.getMessage().contains(\"通过\")) {\n // 内容合规,允许发布\n} else {\n // 内容违规,拒绝发布\n}\n```\n\n### 5. 文本翻译功能\n\n提供多语言翻译服务。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiTranslate\")\n@OpenApi(value = \"AI文本翻译\")\npublic R<AiChatVo> aiTranslate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiTranslate(bo));\n}\n```\n\n#### 使用场景\n\n- 多语言网站内容翻译\n- 用户评论翻译\n- 产品说明翻译\n- 客服消息翻译\n\n#### 请求示例\n\n```java\nAiChatBo translateBo = new AiChatBo();\ntranslateBo.setMessage(\"Hello, how are you today?\");\ntranslateBo.setAiFeature(\"translate\");\ntranslateBo.setSystemPrompt(\"请将以下英文翻译成中文\");\n\nR<AiChatVo> result = aiController.aiTranslate(translateBo);\n// 翻译结果: \"你好,你今天怎么样?\"\n```\n\n### AI配置说明\n\n#### LangChain4j 配置\n\n在 `application.yml` 中配置 LangChain4j:\n\n```yaml\nlangchain4j:\n enabled: true # 启用AI功能\n\n # DeepSeek 配置\n deepseek:\n api-key: ${DEEPSEEK_API_KEY}\n base-url: https://api.deepseek.com/v1\n model-name: deepseek-chat\n temperature: 0.7\n max-tokens: 2000\n timeout: 60s\n\n # 通义千问配置\n qianwen:\n api-key: ${QIANWEN_API_KEY}\n base-url: https://dashscope.aliyuncs.com/api/v1\n model-name: qwen-plus\n temperature: 0.7\n max-tokens: 2000\n\n # OpenAI 配置\n openai:\n api-key: ${OPENAI_API_KEY}\n base-url: https://api.openai.com/v1\n model-name: gpt-3.5-turbo\n temperature: 0.7\n max-tokens: 2000\n```\n\n#### 环境变量配置\n\n推荐使用环境变量管理敏感的API密钥:\n\n```bash\n# .env 文件\nDEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nQIANWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nOPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n#### 权限配置\n\n在菜单管理中配置AI功能权限:\n\n```sql\n-- AI对话权限\nINSERT INTO sys_menu (menu_name, parent_id, perms)\nVALUES ('AI对话', 1000, 'base:ai:chat');\n```\n\n### AI功能集成示例\n\n#### 示例1:智能客服回复\n\n```java\n@Service\npublic class CustomerServiceImpl implements ICustomerService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public String handleCustomerQuestion(String question) {\n AiChatBo chatBo = new AiChatBo();\n chatBo.setMessage(question);\n chatBo.setProvider(\"deepseek\");\n chatBo.setSystemPrompt(\"你是一个友好的客服助手,请专业地回答客户问题\");\n\n AiChatVo response = aiService.aiChat(chatBo);\n return response.getMessage();\n }\n}\n```\n\n#### 示例2:文章内容审核\n\n```java\n@Service\npublic class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public boolean publishArticle(Article article) {\n // 使用AI审核文章内容\n AiChatBo reviewBo = new AiChatBo();\n reviewBo.setMessage(article.getContent());\n reviewBo.setAiFeature(\"review\");\n reviewBo.setSystemPrompt(\"请审核文章内容是否合规,检查是否包含违规、敏感信息\");\n\n AiChatVo reviewResult = aiService.aiReview(reviewBo);\n\n // 判断审核结果\n if (reviewResult.getMessage().contains(\"违规\")) {\n throw new ServiceException(\"文章内容审核未通过: \" + reviewResult.getMessage());\n }\n\n // 审核通过,发布文章\n article.setStatus(\"published\");\n return this.updateById(article);\n }\n}\n```\n\n#### 示例3:数据智能生成\n\n```java\n@Service\npublic class DataGeneratorService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public List<User> generateTestUsers(int count) {\n AiChatBo generateBo = new AiChatBo();\n generateBo.setMessage(\n String.format(\"生成%d个用户测试数据,包含真实的中文姓名、邮箱、手机号\", count)\n );\n generateBo.setAiFeature(\"generate\");\n\n // 传递数据结构上下文\n Map<String, Object> context = new HashMap<>();\n context.put(\"format\", \"json\");\n context.put(\"fields\", Arrays.asList(\"name\", \"email\", \"phone\", \"age\", \"gender\"));\n generateBo.setContext(context);\n\n AiChatVo response = aiService.aiGenerate(generateBo);\n\n // 解析生成的JSON数据\n return JsonUtils.parseArray(response.getMessage(), User.class);\n }\n}\n```\n\n## 数据访问层架构\n\n### DAO模式说明\n\n基础服务模块采用 **DAO(Data Access Object)** 模式,将数据访问逻辑与业务逻辑分离,提供更清晰的架构层次。\n\n#### 架构层次\n\n```text\nController 层\n ↓\nService 层\n ↓\nDAO 层 (IBaseDao)\n ↓\nEntity 层 (数据库实体)\n```\n\n#### IBaseDao 接口\n\n所有 DAO 接口都继承自 `IBaseDao`,提供统一的 CRUD 操作:\n\n```java\npublic interface IBaseDao<T> {\n // 插入\n boolean insert(T entity);\n boolean insertBatch(Collection<T> entityList);\n\n // 更新\n boolean updateById(T entity);\n boolean updateBatchById(Collection<T> entityList);\n\n // 删除\n boolean deleteById(Serializable id);\n boolean deleteBatchIds(Collection<?> idList);\n\n // 查询\n T selectById(Serializable id);\n List<T> selectBatchIds(Collection<? extends Serializable> idList);\n List<T> selectList(Wrapper<T> queryWrapper);\n T selectOne(Wrapper<T> queryWrapper);\n Long selectCount(Wrapper<T> queryWrapper);\n\n // 分页查询\n Page<T> selectPage(Page<T> page, Wrapper<T> queryWrapper);\n}\n```\n\n### 平台配置DAO (IPlatformDao)\n\n```java\npublic interface IPlatformDao extends IBaseDao<Platform> {\n\n /**\n * 根据业务对象构建查询条件\n */\n PlusLambdaQuery<Platform> buildQueryWrapper(PlatformBo bo);\n\n /**\n * 根据appid查询平台配置\n */\n Platform getByAppid(String appid);\n\n /**\n * 根据appid和平台类型查询平台配置\n */\n Platform getByAppidAndType(String appid, String type, String status);\n\n /**\n * 根据平台类型和状态查询配置列表\n */\n List<Platform> listByTypeAndStatus(String type, String status);\n}\n```\n\n### 支付配置DAO (IPaymentDao)\n\n```java\npublic interface IPaymentDao extends IBaseDao<Payment> {\n\n /**\n * 根据商户号查询支付配置\n */\n Payment getByMchId(String mchId, String status);\n\n /**\n * 根据支付类型和状态查询配置列表\n */\n List<Payment> listByTypeAndStatus(String type, String status);\n\n /**\n * 根据状态统计配置数量\n */\n long countByStatus(String status);\n\n /**\n * 根据商户号查询是否存在(排除指定ID)\n */\n boolean existsByMchId(String mchId, Long excludeId);\n\n /**\n * 根据商户号和状态判断是否存在\n */\n boolean existsByMchIdAndStatus(String mchId, String status);\n\n /**\n * 根据状态查询配置列表\n */\n List<Payment> listByStatus(String status);\n}\n```\n\n### DAO层使用示例\n\n```java\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private IPlatformDao platformDao;\n\n @Override\n public PlatformVo getWeixinPlatform(String appid) {\n // 使用DAO查询微信小程序配置\n Platform platform = platformDao.getByAppidAndType(\n appid,\n \"mp-weixin\",\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (platform == null) {\n throw new ServiceException(\"未找到微信小程序配置\");\n }\n\n return BeanUtil.toBean(platform, PlatformVo.class);\n }\n\n @Override\n public List<PlatformVo> listActivePlatforms(String type) {\n // 使用DAO查询所有启用的平台配置\n List<Platform> platforms = platformDao.listByTypeAndStatus(\n type,\n DictEnableStatus.ENABLE.getValue()\n );\n\n return BeanUtil.copyToList(platforms, PlatformVo.class);\n }\n}\n```\n\n## 高级功能\n\n### 多租户支持\n\n基础服务模块所有实体类都继承自 `TenantEntity`,自动支持多租户数据隔离。\n\n#### 租户实体基类\n\n```java\n@Data\npublic class TenantEntity extends BaseEntity {\n\n /**\n * 租户ID\n */\n @TableField(value = \"tenant_id\")\n private String tenantId;\n\n /**\n * 创建部门\n */\n @TableField(value = \"create_dept\")\n private Long createDept;\n}\n```\n\n#### 自动租户隔离\n\n```java\n// 查询时自动添加租户条件\nPlatform platform = platformDao.selectById(platformId);\n// SQL: SELECT * FROM b_platform WHERE id = ? AND tenant_id = '当前租户ID'\n\n// 新增时自动填充租户ID\nPlatform newPlatform = new Platform();\nnewPlatform.setType(\"mp-weixin\");\nplatformDao.insert(newPlatform);\n// SQL: INSERT INTO b_platform (..., tenant_id) VALUES (..., '当前租户ID')\n```\n\n### 数据缓存机制\n\n#### Redis缓存配置\n\n平台配置和支付配置支持Redis缓存,提升查询性能:\n\n```java\n@Service\npublic class PlatformCacheService {\n\n private static final String PLATFORM_CACHE_KEY = \"platform:config:\";\n private static final Duration CACHE_EXPIRE = Duration.ofHours(1);\n\n @Autowired\n private RedisTemplate<String, Platform> redisTemplate;\n\n @Autowired\n private IPlatformDao platformDao;\n\n public Platform getPlatformWithCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n\n // 尝试从缓存获取\n Platform platform = redisTemplate.opsForValue().get(cacheKey);\n if (platform != null) {\n return platform;\n }\n\n // 缓存未命中,查询数据库\n platform = platformDao.getByAppid(appid);\n if (platform != null) {\n // 写入缓存\n redisTemplate.opsForValue().set(cacheKey, platform, CACHE_EXPIRE);\n }\n\n return platform;\n }\n\n public void clearPlatformCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n redisTemplate.delete(cacheKey);\n }\n}\n```\n\n### 事件监听机制\n\n#### 配置变更事件\n\n```java\n@Component\npublic class PlatformConfigEventListener {\n\n @Autowired\n private WxMaApplicationRunner wxMaRunner;\n\n @Autowired\n private WxMpApplicationRunner wxMpRunner;\n\n /**\n * 监听平台配置变更事件\n */\n @EventListener\n public void handlePlatformConfigChange(PlatformConfigChangeEvent event) {\n String tenantId = event.getTenantId();\n String platformType = event.getPlatformType();\n\n // 根据平台类型重新初始化配置\n if (\"mp-weixin\".equals(platformType)) {\n wxMaRunner.initByTenant(tenantId);\n } else if (\"mp-official-account\".equals(platformType)) {\n wxMpRunner.initByTenant(tenantId);\n }\n\n log.info(\"平台配置已更新: tenantId={}, platformType={}\", tenantId, platformType);\n }\n}\n```\n\n#### 自定义事件\n\n```java\n@Data\npublic class PlatformConfigChangeEvent extends ApplicationEvent {\n\n private String tenantId;\n private String platformType;\n private String action; // create, update, delete\n\n public PlatformConfigChangeEvent(Object source, String tenantId, String platformType, String action) {\n super(source);\n this.tenantId = tenantId;\n this.platformType = platformType;\n this.action = action;\n }\n}\n\n// 发布事件\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private ApplicationEventPublisher eventPublisher;\n\n @Override\n @Transactional\n public boolean updatePlatform(PlatformBo bo) {\n boolean result = platformDao.updateById(BeanUtil.toBean(bo, Platform.class));\n\n if (result) {\n // 发布配置变更事件\n eventPublisher.publishEvent(\n new PlatformConfigChangeEvent(this, TenantHelper.getTenantId(), bo.getType(), \"update\")\n );\n }\n\n return result;\n }\n}\n```\n\n## 常见问题\n\n### Q1: 平台配置不生效?\n\n**问题原因:**\n- 配置状态未启用\n- 租户ID不匹配\n- 缓存未更新\n- appid配置错误\n\n**解决方案:**\n\n```java\n// 1. 检查配置状态\nPlatform platform = platformDao.getByAppid(appid);\nif (!\"1\".equals(platform.getStatus())) {\n throw new ServiceException(\"平台配置未启用\");\n}\n\n// 2. 检查租户ID\nString currentTenantId = TenantHelper.getTenantId();\nif (!currentTenantId.equals(platform.getTenantId())) {\n throw new ServiceException(\"平台配置不属于当前租户\");\n}\n\n// 3. 清除缓存重新加载\nwxMaApplicationRunner.initByTenant(currentTenantId);\n```\n\n### Q2: 第三方登录失败?\n\n**问题原因:**\n- appid或secret配置错误\n- 授权码已过期\n- 平台配置未找到\n- 网络连接问题\n\n**解决方案:**\n\n```java\ntry {\n // 使用授权码登录\n AuthTokenVo authToken = authStrategy.login(loginBody);\n} catch (WxErrorException e) {\n // 微信接口调用失败\n log.error(\"微信登录失败: errCode={}, errMsg={}\", e.getError().getErrorCode(), e.getError().getErrorMsg());\n\n if (e.getError().getErrorCode() == 40029) {\n throw new ServiceException(\"授权码无效或已过期,请重新授权\");\n } else if (e.getError().getErrorCode() == 40013) {\n throw new ServiceException(\"appid配置错误\");\n } else {\n throw new ServiceException(\"登录失败: \" + e.getError().getErrorMsg());\n }\n}\n```\n\n### Q3: 支付配置重复?\n\n**问题原因:**\n- 同一商户号被多次配置\n- 未进行唯一性校验\n\n**解决方案:**\n\n```java\n@Service\npublic class PaymentServiceImpl implements IPaymentService {\n\n @Override\n public boolean addPayment(PaymentBo bo) {\n // 检查商户号是否已存在\n boolean exists = paymentDao.existsByMchIdAndStatus(\n bo.getMchId(),\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (exists) {\n throw new ServiceException(\"该商户号已存在有效配置\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.insert(payment);\n }\n\n @Override\n public boolean updatePayment(PaymentBo bo) {\n // 检查商户号是否与其他记录重复(排除当前记录)\n boolean exists = paymentDao.existsByMchId(bo.getMchId(), bo.getId());\n\n if (exists) {\n throw new ServiceException(\"该商户号已被其他配置使用\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.updateById(payment);\n }\n}\n```\n\n### Q4: AI功能无法使用?\n\n**问题原因:**\n- LangChain4j未启用\n- API密钥配置错误\n- 网络连接问题\n- 权限未配置\n\n**解决方案:**\n\n```yaml\n# 1. 确保配置已启用\nlangchain4j:\n enabled: true # 必须为 true\n\n# 2. 检查API密钥\ndeepseek:\n api-key: ${DEEPSEEK_API_KEY} # 确保环境变量已设置\n\n# 3. 测试网络连接\ncurl -X POST https://api.deepseek.com/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'\n\n# 4. 配置权限\nINSERT INTO sys_menu (menu_name, perms) VALUES ('AI对话', 'base:ai:chat');\n```\n\n## 故障排查\n\n### 日志配置\n\n#### 启用详细日志\n\n```yaml\nlogging:\n level:\n plus.ruoyi.business.base: DEBUG\n plus.ruoyi.business.base.controller: DEBUG\n plus.ruoyi.business.base.service: DEBUG\n plus.ruoyi.business.base.dao: DEBUG\n plus.ruoyi.business.base.authStrategy: DEBUG\n```\n\n### 常见错误及解决方案\n\n#### 错误1: 平台配置未找到\n\n```text\n错误信息: ServiceException: 未找到平台配置\n```\n\n**排查步骤:**\n1. 检查数据库中是否存在配置记录\n2. 检查appid是否正确\n3. 检查配置状态是否启用\n4. 检查租户ID是否匹配\n\n```java\n// 调试代码\nPlatform platform = platformDao.selectOne(\n new LambdaQueryWrapper<Platform>()\n .eq(Platform::getAppid, appid)\n);\nSystem.out.println(\"查询到的平台配置: \" + JsonUtils.toJsonString(platform));\n```\n\n#### 错误2: 认证策略未找到\n\n```text\n错误信息: No bean named 'miniappAuthStrategy' available\n```\n\n**排查步骤:**\n1. 检查认证策略类是否标注 `@Service` 注解\n2. 检查策略名称是否正确\n3. 检查Spring扫描路径是否包含策略类\n\n```java\n// 正确的策略命名\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME) // miniappAuthStrategy\npublic class MiniappAuthStrategy implements IAuthStrategy {\n // ...\n}\n```\n\n#### 错误3: 多租户数据泄露\n\n```text\n错误信息: 查询到了其他租户的数据\n```\n\n**排查步骤:**\n1. 检查实体类是否继承 `TenantEntity`\n2. 检查租户拦截器是否生效\n3. 检查数据表是否包含 `tenant_id` 字段\n\n```java\n// 确保实体类正确继承\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n // 自动支持租户隔离\n}\n```\n\n## API参考\n\n### Controller接口清单\n\n| 控制器 | 路径 | 功能说明 |\n|--------|------|----------|\n| PlatformController | `/base/platform/*` | 平台配置管理 |\n| PaymentController | `/base/payment/*` | 支付配置管理 |\n| BindController | `/base/bind/*` | 账号绑定管理 |\n| AdController | `/base/ad/*` | 广告配置管理 |\n| AiController | `/base/ai/*` | AI助手功能 |\n\n### 核心接口详情\n\n#### 平台配置接口\n\n```java\nGET /base/platform/list 查询平台配置列表\nGET /base/platform/{id} 查询平台配置详情\nPOST /base/platform 新增平台配置\nPUT /base/platform 更新平台配置\nDELETE /base/platform/{ids} 删除平台配置\nGET /base/platform/dict 获取平台字典\n```\n\n#### 支付配置接口\n\n```java\nGET /base/payment/list 查询支付配置列表\nGET /base/payment/{id} 查询支付配置详情\nPOST /base/payment 新增支付配置\nPUT /base/payment 更新支付配置\nDELETE /base/payment/{ids} 删除支付配置\nGET /base/payment/dict 获取支付方式字典\n```\n\n#### 账号绑定接口\n\n```java\nGET /base/bind/list 查询绑定列表\nPOST /base/bind/bindPhone 绑定手机号\nPOST /base/bind/unbind 解除绑定\n```\n\n#### AI助手接口\n\n```java\nPOST /base/ai/aiChat AI对话\nPOST /base/ai/aiOptimize 文本优化\nPOST /base/ai/aiGenerate 数据生成\nPOST /base/ai/aiReview 内容审核\nPOST /base/ai/aiTranslate 文本翻译\n```\n\n## 最佳实践\n\n### 配置管理\n- 敏感信息(如密钥)使用环境变量或加密存储\n- 支持配置热更新,通过事件机制通知相关服务\n- 按租户隔离配置,确保数据安全\n- 使用Redis缓存常用配置,提升性能\n\n### 安全考虑\n- 登录令牌设置合理的过期时间(建议2小时)\n- 敏感API添加 `@SaCheckPermission` 权限校验\n- 支付配置访问权限严格控制\n- AI接口调用添加频率限制,防止滥用\n- API密钥使用环境变量管理,不提交到代码仓库\n\n### 性能优化\n- 平台配置和支付配置使用Redis缓存,有效期1小时\n- 异步处理配置更新,使用Spring事件机制\n- 合理使用数据库索引(appid、mchId等字段)\n- AI接口调用使用连接池,复用HTTP连接\n- 批量查询使用 `selectBatchIds` 而不是循环查询\n\n### 扩展建议\n- 新增平台时,实现对应的 `IAuthStrategy` 认证策略\n- 支付方式扩展遵循统一的 DAO 接口规范\n- 配置项变更通过 `ApplicationEventPublisher` 发布事件\n- AI功能扩展可添加新的服务方法,保持接口一致性\n- 建议为每个租户配置独立的平台和支付配置\n"}, "47c57979a68e81774de5550269109694ce6c5e78": {"t": 1785765309.0300627, "n": 27754, "h": "148f70df045e63ea", "c": "# 基础服务模块 (base)\n\n基础服务模块提供了系统运行所需的核心基础服务,包括多平台配置管理、支付配置管理、广告配置、账号绑定等功能。\n\n## 模块结构\n\n```text\nbase/\n├── controller/ # 控制器层\n│ ├── AdController.java\n│ ├── BindController.java\n│ ├── PaymentController.java\n│ └── PlatformController.java\n├── service/ # 服务层\n│ ├── IAdService.java\n│ ├── IBindService.java\n│ ├── IPaymentService.java\n│ └── IPlatformService.java\n├── domain/ # 数据模型\n│ ├── entity/ # 实体类\n│ ├── vo/ # 视图对象\n│ └── bo/ # 业务对象\n├── mapper/ # 数据访问层\n└── authStrategy/ # 认证策略\n```\n\n## 核心功能\n\n### 🏗️ 平台配置管理\n\n支持多种平台的统一配置管理:\n\n- **微信小程序** (mp-weixin)\n- **微信公众号** (mp-official-account)\n- **支付宝小程序** (mp-alipay)\n- **QQ小程序** (mp-qq)\n- **其他平台** (mp-jd, mp-kuaishou, mp-lark, mp-baidu, mp-toutiao, mp-xhs)\n\n#### 平台配置实体\n```java\n@Data\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n private Long id; // 平台配置ID\n private String type; // 平台类型\n private String name; // 平台名称\n private String appid; // 应用ID\n private String secret; // 应用密钥\n private String token; // 接口Token\n private String aeskey; // 加密密钥\n private String paymentIds; // 关联支付配置\n private String templateConfigs; // 模板配置\n private String status; // 状态\n}\n```\n\n#### 核心接口\n```java\npublic interface IPlatformService extends IBaseService<Platform, PlatformBo, PlatformVo> {\n // 继承基础CRUD操作\n}\n\n// 全局平台服务\npublic interface PlatformService {\n List<PlatformDTO> listPlatformsByType(String type, String tenantId);\n PlatformDTO getPlatformByAppidAndType(String appid, String type);\n PlatformDTO getPlatformByAppid(String appid, String tenantId);\n}\n```\n\n### 💳 支付配置管理\n\n统一的支付配置管理,支持多种支付方式:\n\n#### 支付配置实体\n```java\n@Data\n@TableName(\"b_payment\") \npublic class Payment extends TenantEntity {\n private Long id; // 支付配置ID\n private String type; // 商户类型\n private String mchName; // 商户名称\n private String mchId; // 商户号\n private String mchKey; // 商户密钥\n private String apiV3Key; // APIv3密钥\n private String certPath; // 证书路径\n private String keyPath; // 密钥路径\n private String certSerialNo; // 证书序列号\n private String status; // 状态\n}\n```\n\n#### 核心服务\n```java\npublic interface PaymentService {\n List<PaymentDTO> listPaymentByType(String type, String tenantId);\n PaymentDTO getByMchId(String mchId);\n PaymentDTO getById(Long paymentId);\n boolean existsValidMchId(String mchId);\n long countPayments();\n}\n```\n\n### 📱 账号绑定管理\n\n管理用户在不同平台的账号绑定关系:\n\n#### 绑定实体\n```java\n@Data\n@TableName(\"b_bind\")\npublic class Bind extends TenantEntity {\n private Long id; // 绑定ID\n private Long userId; // 用户ID\n private String platformType; // 平台类型\n private String appid; // 应用ID\n private String unionid; // 统一标识\n private String openid; // 平台标识\n private String extraData; // 扩展数据\n}\n```\n\n#### 绑定服务\n```java\npublic interface IBindService extends IBaseService<Bind, BindBo, BindVo> {\n /**\n * 根据平台用户信息获取或创建绑定信息\n */\n BindVo getOrCreateBind(PlatformUserInfoVo platformUserInfoVo);\n \n /**\n * 更新绑定信息的用户ID\n */\n void updateBindUserId(BindBo bindBo, Long userId);\n}\n```\n\n### 📢 广告配置管理\n\n提供广告位和广告内容的统一管理:\n\n#### 广告实体\n```java\n@Data\n@TableName(\"b_ad\")\npublic class Ad extends TenantEntity {\n private Long id; // 广告ID\n private String appid; // 应用ID\n private String adUnitId; // 广告位ID\n private String adName; // 广告名称\n private String adType; // 广告类型\n private String position; // 投放位置\n private String img; // 广告图片\n private String description; // 描述\n private String jumpAppid; // 跳转应用ID\n private String jumpPath; // 跳转路径\n private String styleConfig; // 样式配置\n private Long sortOrder; // 排序值\n private String status; // 状态\n}\n```\n\n## 认证策略\n\n### 多平台认证架构\n\n基于策略模式实现多平台登录认证:\n\n#### 认证策略接口\n```java\npublic interface IAuthStrategy {\n String BASE_NAME = \"AuthStrategy\";\n AuthTokenVo login(String body);\n}\n```\n\n#### 小程序认证策略\n```java\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME)\npublic class MiniappAuthStrategy implements IAuthStrategy {\n \n @Override\n public AuthTokenVo login(String body) {\n // 1. 解析请求参数\n PlatformLoginBody loginBody = JsonUtils.parseObject(body, PlatformLoginBody.class);\n \n // 2. 获取平台用户信息\n PlatformUserInfoVo platformUserInfo = getMiniappUserIdentity(loginBody);\n \n // 3. 加载或创建用户\n SysUserVo user = loadOrCreateUser(platformUserInfo);\n \n // 4. 生成登录令牌\n LoginUser loginUser = loginService.createLoginUser(user);\n loginUser.setPlatform(platformUserInfo.getPlatform());\n loginUser.setAppid(platformUserInfo.getAppid());\n loginUser.setOpenid(platformUserInfo.getOpenid());\n loginUser.setUnionid(platformUserInfo.getUnionid());\n \n // 5. 完成登录\n LoginHelper.login(loginUser, loginParameter);\n \n // 6. 返回认证结果\n AuthTokenVo authTokenVo = new AuthTokenVo();\n authTokenVo.setAccessToken(StpUtil.getTokenValue());\n authTokenVo.setExpireIn(StpUtil.getTokenTimeout());\n return authTokenVo;\n }\n}\n```\n\n#### 公众号认证策略\n```java\n@Service(\"mp\" + IAuthStrategy.BASE_NAME)\npublic class MpAuthStrategy implements IAuthStrategy {\n // 公众号OAuth2.0认证流程实现\n // 支持网页授权登录场景\n}\n```\n\n### 认证流程\n\n1. **前端授权**:用户在前端完成平台授权,获取授权码\n2. **策略选择**:后端根据平台类型自动选择对应认证策略\n3. **信息获取**:通过授权码换取用户基本信息\n4. **账号绑定**:查找或创建用户账号绑定关系\n5. **令牌生成**:生成JWT访问令牌\n6. **登录完成**:返回令牌和用户信息\n\n## 手机号绑定\n\n### 微信小程序手机号获取\n```java\n@PostMapping(\"/bindPhone\")\npublic R<PhoneBindVo> bindPhone(@RequestBody PhoneBindBo bo) {\n LoginUser loginUser = LoginHelper.getLoginUser();\n wxMaService.switchover(loginUser.getAppid());\n \n try {\n WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(bo.getCode());\n String phone = phoneInfo.getPhoneNumber();\n \n // 更新用户手机号\n SysUser sysUser = userMapper.selectById(loginUser.getUserId());\n sysUser.setPhone(phone);\n userMapper.updateById(sysUser);\n \n return R.ok(\"绑定成功\", PhoneBindVo.of(phone));\n } catch (WxErrorException e) {\n return R.fail(\"获取手机号出错\");\n }\n}\n```\n\n## 数据字典服务\n\n### 支付方式字典\n```java\n@GetMapping(\"getPaymentDict\")\npublic R<List<DictItemVo>> getPaymentDict() {\n // 查询所有可用的支付方式\n List<PaymentVo> paymentVoList = paymentService.list(\n PlusLambdaQuery.of(Payment.class)\n .eq(Payment::getStatus, DictEnableStatus.ENABLE.getValue()));\n \n // 构建字典项列表\n List<DictItemVo> dictItems = StreamUtils.toList(paymentVoList, payment ->\n DictItemVo.of(payment.getMchName(), payment.getId().toString(), \"success\")\n );\n return R.ok(dictItems);\n}\n```\n\n## 配置管理\n\n### 平台配置热更新\n```java\nprivate void reloadPlatformConfig() {\n String tenantId = TenantHelper.getTenantId();\n \n // 重新初始化微信小程序配置\n SpringUtils.getBean(WxMaApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化微信公众号配置 \n SpringUtils.getBean(WxMpApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化支付配置\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n### 支付配置热更新\n```java\nprivate void reloadPaymentConfig() {\n String tenantId = TenantHelper.getTenantId();\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n## 使用示例\n\n### 配置微信小程序\n```java\n// 1. 创建平台配置\nPlatformBo platformBo = new PlatformBo();\nplatformBo.setType(\"mp-weixin\");\nplatformBo.setName(\"我的小程序\");\nplatformBo.setAppid(\"wx1234567890\");\nplatformBo.setSecret(\"your-secret\");\nplatformBo.setStatus(\"1\");\nplatformService.add(platformBo);\n\n// 2. 配置支付信息\nPaymentBo paymentBo = new PaymentBo();\npaymentBo.setType(\"wechat\");\npaymentBo.setMchName(\"我的商户\");\npaymentBo.setMchId(\"1234567890\");\npaymentBo.setMchKey(\"your-mch-key\");\npaymentBo.setStatus(\"1\");\npaymentService.add(paymentBo);\n```\n\n### 用户登录认证\n```java\n// 前端调用登录接口\nPOST /auth/login\n{\n \"platform\": \"miniapp\",\n \"body\": {\n \"platform\": \"mp-weixin\",\n \"appid\": \"wx1234567890\",\n \"platformCode\": \"授权码\"\n }\n}\n\n// 返回结果\n{\n \"code\": 200,\n \"msg\": \"登录成功\",\n \"data\": {\n \"accessToken\": \"eyJ0eXAiOiJKV1Q...\",\n \"expireIn\": 7200\n }\n}\n```\n\n## AI助手功能\n\n### 🤖 功能概述\n\n基础服务模块集成了强大的AI助手功能,基于 **LangChain4j** 框架实现,支持多种大语言模型(如 DeepSeek、通义千问、OpenAI、Claude等),为业务系统提供智能化能力。\n\n**核心特性:**\n- **多模型支持** - 灵活切换不同的AI模型提供商\n- **多场景应用** - 对话、优化、生成、审核、翻译等场景\n- **条件启用** - 通过配置开关控制功能启用\n- **权限控制** - 完善的权限校验机制\n- **上下文传递** - 支持业务上下文信息传递\n\n### AI服务接口\n\n#### AiController 控制器\n\n```java\n@RestController\n@RequestMapping(\"/base/ai\")\n@ConditionalOnProperty(\n prefix = \"langchain4j\",\n name = \"enabled\",\n havingValue = \"true\",\n matchIfMissing = true\n)\npublic class AiController {\n private final IAiService aiService;\n}\n```\n\n**条件启用说明:**\n- 需要在配置文件中设置 `langchain4j.enabled=true`\n- 如果配置项不存在,默认启用 (`matchIfMissing = true`)\n\n### 1. AI对话功能\n\n通用的AI对话接口,支持自由对话场景。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiChat\")\n@OpenApi(value = \"AI对话\")\npublic R<AiChatVo> aiChat(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiChat(bo));\n}\n```\n\n#### 请求示例\n\n```java\n// 创建对话请求\nAiChatBo chatBo = new AiChatBo();\nchatBo.setMessage(\"请帮我解释一下什么是微服务架构\");\nchatBo.setProvider(\"deepseek\");\nchatBo.setModelName(\"deepseek-chat\");\nchatBo.setTemperature(0.7);\nchatBo.setMaxTokens(2000);\n\n// 调用接口\nR<AiChatVo> result = aiController.aiChat(chatBo);\nAiChatVo response = result.getData();\nSystem.out.println(\"AI回复: \" + response.getMessage());\n```\n\n#### HTTP 调用示例\n\n```bash\nPOST /base/ai/aiChat\nContent-Type: application/json\n\n{\n \"message\": \"请帮我解释一下什么是微服务架构\",\n \"provider\": \"deepseek\",\n \"modelName\": \"deepseek-chat\",\n \"temperature\": 0.7,\n \"maxTokens\": 2000\n}\n```\n\n### 2. 文本优化功能\n\n对用户输入的文本进行优化,改善表达和文风。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiOptimize\")\n@OpenApi(value = \"AI文本优化\")\npublic R<AiChatVo> aiOptimize(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiOptimize(bo));\n}\n```\n\n#### 使用场景\n\n- 文章润色和改写\n- 产品描述优化\n- 邮件内容优化\n- 广告文案优化\n\n#### 请求示例\n\n```java\nAiChatBo optimizeBo = new AiChatBo();\noptimizeBo.setMessage(\"我们公司是做软件开发的,主要业务是给客户做系统\");\noptimizeBo.setAiFeature(\"optimize\");\noptimizeBo.setSystemPrompt(\"请将下列文本优化为更专业的企业简介\");\n\nR<AiChatVo> result = aiController.aiOptimize(optimizeBo);\n// 优化后: \"我们是一家专业的软件开发公司,致力于为企业客户提供定制化系统解决方案...\"\n```\n\n### 3. 数据生成功能\n\n根据用户需求生成结构化数据或内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiGenerate\")\n@OpenApi(value = \"AI数据生成\")\npublic R<AiChatVo> aiGenerate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiGenerate(bo));\n}\n```\n\n#### 使用场景\n\n- 生成测试数据\n- 生成产品描述\n- 生成代码片段\n- 生成用户画像\n\n#### 请求示例\n\n```java\nAiChatBo generateBo = new AiChatBo();\ngenerateBo.setMessage(\"生成5个用户的测试数据,包含姓名、年龄、邮箱\");\ngenerateBo.setAiFeature(\"generate\");\n\n// 传递表单字段信息作为上下文\nMap<String, Object> context = new HashMap<>();\ncontext.put(\"fields\", Arrays.asList(\"name\", \"age\", \"email\"));\ncontext.put(\"count\", 5);\ngenerateBo.setContext(context);\n\nR<AiChatVo> result = aiController.aiGenerate(generateBo);\n```\n\n**生成结果示例:**\n```json\n[\n {\"name\": \"张三\", \"age\": 28, \"email\": \"zhangsan@example.com\"},\n {\"name\": \"李四\", \"age\": 32, \"email\": \"lisi@example.com\"},\n {\"name\": \"王五\", \"age\": 25, \"email\": \"wangwu@example.com\"},\n {\"name\": \"赵六\", \"age\": 30, \"email\": \"zhaoliu@example.com\"},\n {\"name\": \"钱七\", \"age\": 27, \"email\": \"qianqi@example.com\"}\n]\n```\n\n### 4. 内容审核功能\n\n对用户提交的内容进行智能审核,检测违规内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiReview\")\n@OpenApi(value = \"AI内容审核\")\npublic R<AiChatVo> aiReview(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiReview(bo));\n}\n```\n\n#### 使用场景\n\n- 评论内容审核\n- 文章内容审核\n- 用户昵称审核\n- 敏感词检测\n\n#### 请求示例\n\n```java\nAiChatBo reviewBo = new AiChatBo();\nreviewBo.setMessage(\"待审核的用户评论内容...\");\nreviewBo.setAiFeature(\"review\");\nreviewBo.setSystemPrompt(\"请审核以下内容是否包含违规、敏感、广告等不当信息\");\n\nR<AiChatVo> result = aiController.aiReview(reviewBo);\nAiChatVo response = result.getData();\n\n// 解析审核结果\nif (response.getMessage().contains(\"通过\")) {\n // 内容合规,允许发布\n} else {\n // 内容违规,拒绝发布\n}\n```\n\n### 5. 文本翻译功能\n\n提供多语言翻译服务。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiTranslate\")\n@OpenApi(value = \"AI文本翻译\")\npublic R<AiChatVo> aiTranslate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiTranslate(bo));\n}\n```\n\n#### 使用场景\n\n- 多语言网站内容翻译\n- 用户评论翻译\n- 产品说明翻译\n- 客服消息翻译\n\n#### 请求示例\n\n```java\nAiChatBo translateBo = new AiChatBo();\ntranslateBo.setMessage(\"Hello, how are you today?\");\ntranslateBo.setAiFeature(\"translate\");\ntranslateBo.setSystemPrompt(\"请将以下英文翻译成中文\");\n\nR<AiChatVo> result = aiController.aiTranslate(translateBo);\n// 翻译结果: \"你好,你今天怎么样?\"\n```\n\n### AI配置说明\n\n#### LangChain4j 配置\n\n在 `application.yml` 中配置 LangChain4j:\n\n```yaml\nlangchain4j:\n enabled: true # 启用AI功能\n\n # DeepSeek 配置\n deepseek:\n api-key: ${DEEPSEEK_API_KEY}\n base-url: https://api.deepseek.com/v1\n model-name: deepseek-chat\n temperature: 0.7\n max-tokens: 2000\n timeout: 60s\n\n # 通义千问配置\n qianwen:\n api-key: ${QIANWEN_API_KEY}\n base-url: https://dashscope.aliyuncs.com/api/v1\n model-name: qwen-plus\n temperature: 0.7\n max-tokens: 2000\n\n # OpenAI 配置\n openai:\n api-key: ${OPENAI_API_KEY}\n base-url: https://api.openai.com/v1\n model-name: gpt-3.5-turbo\n temperature: 0.7\n max-tokens: 2000\n```\n\n#### 环境变量配置\n\n推荐使用环境变量管理敏感的API密钥:\n\n```bash\n# .env 文件\nDEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nQIANWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nOPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n#### 权限配置\n\n在菜单管理中配置AI功能权限:\n\n```sql\n-- AI对话权限\nINSERT INTO sys_menu (menu_name, parent_id, perms)\nVALUES ('AI对话', 1000, 'base:ai:chat');\n```\n\n### AI功能集成示例\n\n#### 示例1:智能客服回复\n\n```java\n@Service\npublic class CustomerServiceImpl implements ICustomerService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public String handleCustomerQuestion(String question) {\n AiChatBo chatBo = new AiChatBo();\n chatBo.setMessage(question);\n chatBo.setProvider(\"deepseek\");\n chatBo.setSystemPrompt(\"你是一个友好的客服助手,请专业地回答客户问题\");\n\n AiChatVo response = aiService.aiChat(chatBo);\n return response.getMessage();\n }\n}\n```\n\n#### 示例2:文章内容审核\n\n```java\n@Service\npublic class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public boolean publishArticle(Article article) {\n // 使用AI审核文章内容\n AiChatBo reviewBo = new AiChatBo();\n reviewBo.setMessage(article.getContent());\n reviewBo.setAiFeature(\"review\");\n reviewBo.setSystemPrompt(\"请审核文章内容是否合规,检查是否包含违规、敏感信息\");\n\n AiChatVo reviewResult = aiService.aiReview(reviewBo);\n\n // 判断审核结果\n if (reviewResult.getMessage().contains(\"违规\")) {\n throw new ServiceException(\"文章内容审核未通过: \" + reviewResult.getMessage());\n }\n\n // 审核通过,发布文章\n article.setStatus(\"published\");\n return this.updateById(article);\n }\n}\n```\n\n#### 示例3:数据智能生成\n\n```java\n@Service\npublic class DataGeneratorService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public List<User> generateTestUsers(int count) {\n AiChatBo generateBo = new AiChatBo();\n generateBo.setMessage(\n String.format(\"生成%d个用户测试数据,包含真实的中文姓名、邮箱、手机号\", count)\n );\n generateBo.setAiFeature(\"generate\");\n\n // 传递数据结构上下文\n Map<String, Object> context = new HashMap<>();\n context.put(\"format\", \"json\");\n context.put(\"fields\", Arrays.asList(\"name\", \"email\", \"phone\", \"age\", \"gender\"));\n generateBo.setContext(context);\n\n AiChatVo response = aiService.aiGenerate(generateBo);\n\n // 解析生成的JSON数据\n return JsonUtils.parseArray(response.getMessage(), User.class);\n }\n}\n```\n\n## 数据访问层架构\n\n### DAO模式说明\n\n基础服务模块采用 **DAO(Data Access Object)** 模式,将数据访问逻辑与业务逻辑分离,提供更清晰的架构层次。\n\n#### 架构层次\n\n```text\nController 层\n ↓\nService 层\n ↓\nDAO 层 (IBaseDao)\n ↓\nEntity 层 (数据库实体)\n```\n\n#### IBaseDao 接口\n\n所有 DAO 接口都继承自 `IBaseDao`,提供统一的 CRUD 操作:\n\n```java\npublic interface IBaseDao<T> {\n // 插入\n boolean insert(T entity);\n boolean insertBatch(Collection<T> entityList);\n\n // 更新\n boolean updateById(T entity);\n boolean updateBatchById(Collection<T> entityList);\n\n // 删除\n boolean deleteById(Serializable id);\n boolean deleteBatchIds(Collection<?> idList);\n\n // 查询\n T selectById(Serializable id);\n List<T> selectBatchIds(Collection<? extends Serializable> idList);\n List<T> selectList(Wrapper<T> queryWrapper);\n T selectOne(Wrapper<T> queryWrapper);\n Long selectCount(Wrapper<T> queryWrapper);\n\n // 分页查询\n Page<T> selectPage(Page<T> page, Wrapper<T> queryWrapper);\n}\n```\n\n### 平台配置DAO (IPlatformDao)\n\n```java\npublic interface IPlatformDao extends IBaseDao<Platform> {\n\n /**\n * 根据业务对象构建查询条件\n */\n PlusLambdaQuery<Platform> buildQueryWrapper(PlatformBo bo);\n\n /**\n * 根据appid查询平台配置\n */\n Platform getByAppid(String appid);\n\n /**\n * 根据appid和平台类型查询平台配置\n */\n Platform getByAppidAndType(String appid, String type, String status);\n\n /**\n * 根据平台类型和状态查询配置列表\n */\n List<Platform> listByTypeAndStatus(String type, String status);\n}\n```\n\n### 支付配置DAO (IPaymentDao)\n\n```java\npublic interface IPaymentDao extends IBaseDao<Payment> {\n\n /**\n * 根据商户号查询支付配置\n */\n Payment getByMchId(String mchId, String status);\n\n /**\n * 根据支付类型和状态查询配置列表\n */\n List<Payment> listByTypeAndStatus(String type, String status);\n\n /**\n * 根据状态统计配置数量\n */\n long countByStatus(String status);\n\n /**\n * 根据商户号查询是否存在(排除指定ID)\n */\n boolean existsByMchId(String mchId, Long excludeId);\n\n /**\n * 根据商户号和状态判断是否存在\n */\n boolean existsByMchIdAndStatus(String mchId, String status);\n\n /**\n * 根据状态查询配置列表\n */\n List<Payment> listByStatus(String status);\n}\n```\n\n### DAO层使用示例\n\n```java\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private IPlatformDao platformDao;\n\n @Override\n public PlatformVo getWeixinPlatform(String appid) {\n // 使用DAO查询微信小程序配置\n Platform platform = platformDao.getByAppidAndType(\n appid,\n \"mp-weixin\",\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (platform == null) {\n throw new ServiceException(\"未找到微信小程序配置\");\n }\n\n return BeanUtil.toBean(platform, PlatformVo.class);\n }\n\n @Override\n public List<PlatformVo> listActivePlatforms(String type) {\n // 使用DAO查询所有启用的平台配置\n List<Platform> platforms = platformDao.listByTypeAndStatus(\n type,\n DictEnableStatus.ENABLE.getValue()\n );\n\n return BeanUtil.copyToList(platforms, PlatformVo.class);\n }\n}\n```\n\n## 高级功能\n\n### 多租户支持\n\n基础服务模块所有实体类都继承自 `TenantEntity`,自动支持多租户数据隔离。\n\n#### 租户实体基类\n\n```java\n@Data\npublic class TenantEntity extends BaseEntity {\n\n /**\n * 租户ID\n */\n @TableField(value = \"tenant_id\")\n private String tenantId;\n\n /**\n * 创建部门\n */\n @TableField(value = \"create_dept\")\n private Long createDept;\n}\n```\n\n#### 自动租户隔离\n\n```java\n// 查询时自动添加租户条件\nPlatform platform = platformDao.selectById(platformId);\n// SQL: SELECT * FROM b_platform WHERE id = ? AND tenant_id = '当前租户ID'\n\n// 新增时自动填充租户ID\nPlatform newPlatform = new Platform();\nnewPlatform.setType(\"mp-weixin\");\nplatformDao.insert(newPlatform);\n// SQL: INSERT INTO b_platform (..., tenant_id) VALUES (..., '当前租户ID')\n```\n\n### 数据缓存机制\n\n#### Redis缓存配置\n\n平台配置和支付配置支持Redis缓存,提升查询性能:\n\n```java\n@Service\npublic class PlatformCacheService {\n\n private static final String PLATFORM_CACHE_KEY = \"platform:config:\";\n private static final Duration CACHE_EXPIRE = Duration.ofHours(1);\n\n @Autowired\n private RedisTemplate<String, Platform> redisTemplate;\n\n @Autowired\n private IPlatformDao platformDao;\n\n public Platform getPlatformWithCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n\n // 尝试从缓存获取\n Platform platform = redisTemplate.opsForValue().get(cacheKey);\n if (platform != null) {\n return platform;\n }\n\n // 缓存未命中,查询数据库\n platform = platformDao.getByAppid(appid);\n if (platform != null) {\n // 写入缓存\n redisTemplate.opsForValue().set(cacheKey, platform, CACHE_EXPIRE);\n }\n\n return platform;\n }\n\n public void clearPlatformCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n redisTemplate.delete(cacheKey);\n }\n}\n```\n\n### 事件监听机制\n\n#### 配置变更事件\n\n```java\n@Component\npublic class PlatformConfigEventListener {\n\n @Autowired\n private WxMaApplicationRunner wxMaRunner;\n\n @Autowired\n private WxMpApplicationRunner wxMpRunner;\n\n /**\n * 监听平台配置变更事件\n */\n @EventListener\n public void handlePlatformConfigChange(PlatformConfigChangeEvent event) {\n String tenantId = event.getTenantId();\n String platformType = event.getPlatformType();\n\n // 根据平台类型重新初始化配置\n if (\"mp-weixin\".equals(platformType)) {\n wxMaRunner.initByTenant(tenantId);\n } else if (\"mp-official-account\".equals(platformType)) {\n wxMpRunner.initByTenant(tenantId);\n }\n\n log.info(\"平台配置已更新: tenantId={}, platformType={}\", tenantId, platformType);\n }\n}\n```\n\n#### 自定义事件\n\n```java\n@Data\npublic class PlatformConfigChangeEvent extends ApplicationEvent {\n\n private String tenantId;\n private String platformType;\n private String action; // create, update, delete\n\n public PlatformConfigChangeEvent(Object source, String tenantId, String platformType, String action) {\n super(source);\n this.tenantId = tenantId;\n this.platformType = platformType;\n this.action = action;\n }\n}\n\n// 发布事件\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private ApplicationEventPublisher eventPublisher;\n\n @Override\n @Transactional\n public boolean updatePlatform(PlatformBo bo) {\n boolean result = platformDao.updateById(BeanUtil.toBean(bo, Platform.class));\n\n if (result) {\n // 发布配置变更事件\n eventPublisher.publishEvent(\n new PlatformConfigChangeEvent(this, TenantHelper.getTenantId(), bo.getType(), \"update\")\n );\n }\n\n return result;\n }\n}\n```\n\n## 常见问题\n\n### Q1: 平台配置不生效?\n\n**问题原因:**\n- 配置状态未启用\n- 租户ID不匹配\n- 缓存未更新\n- appid配置错误\n\n**解决方案:**\n\n```java\n// 1. 检查配置状态\nPlatform platform = platformDao.getByAppid(appid);\nif (!\"1\".equals(platform.getStatus())) {\n throw new ServiceException(\"平台配置未启用\");\n}\n\n// 2. 检查租户ID\nString currentTenantId = TenantHelper.getTenantId();\nif (!currentTenantId.equals(platform.getTenantId())) {\n throw new ServiceException(\"平台配置不属于当前租户\");\n}\n\n// 3. 清除缓存重新加载\nwxMaApplicationRunner.initByTenant(currentTenantId);\n```\n\n### Q2: 第三方登录失败?\n\n**问题原因:**\n- appid或secret配置错误\n- 授权码已过期\n- 平台配置未找到\n- 网络连接问题\n\n**解决方案:**\n\n```java\ntry {\n // 使用授权码登录\n AuthTokenVo authToken = authStrategy.login(loginBody);\n} catch (WxErrorException e) {\n // 微信接口调用失败\n log.error(\"微信登录失败: errCode={}, errMsg={}\", e.getError().getErrorCode(), e.getError().getErrorMsg());\n\n if (e.getError().getErrorCode() == 40029) {\n throw new ServiceException(\"授权码无效或已过期,请重新授权\");\n } else if (e.getError().getErrorCode() == 40013) {\n throw new ServiceException(\"appid配置错误\");\n } else {\n throw new ServiceException(\"登录失败: \" + e.getError().getErrorMsg());\n }\n}\n```\n\n### Q3: 支付配置重复?\n\n**问题原因:**\n- 同一商户号被多次配置\n- 未进行唯一性校验\n\n**解决方案:**\n\n```java\n@Service\npublic class PaymentServiceImpl implements IPaymentService {\n\n @Override\n public boolean addPayment(PaymentBo bo) {\n // 检查商户号是否已存在\n boolean exists = paymentDao.existsByMchIdAndStatus(\n bo.getMchId(),\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (exists) {\n throw new ServiceException(\"该商户号已存在有效配置\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.insert(payment);\n }\n\n @Override\n public boolean updatePayment(PaymentBo bo) {\n // 检查商户号是否与其他记录重复(排除当前记录)\n boolean exists = paymentDao.existsByMchId(bo.getMchId(), bo.getId());\n\n if (exists) {\n throw new ServiceException(\"该商户号已被其他配置使用\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.updateById(payment);\n }\n}\n```\n\n### Q4: AI功能无法使用?\n\n**问题原因:**\n- LangChain4j未启用\n- API密钥配置错误\n- 网络连接问题\n- 权限未配置\n\n**解决方案:**\n\n```yaml\n# 1. 确保配置已启用\nlangchain4j:\n enabled: true # 必须为 true\n\n# 2. 检查API密钥\ndeepseek:\n api-key: ${DEEPSEEK_API_KEY} # 确保环境变量已设置\n\n# 3. 测试网络连接\ncurl -X POST https://api.deepseek.com/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'\n\n# 4. 配置权限\nINSERT INTO sys_menu (menu_name, perms) VALUES ('AI对话', 'base:ai:chat');\n```\n\n## 故障排查\n\n### 日志配置\n\n#### 启用详细日志\n\n```yaml\nlogging:\n level:\n plus.ruoyi.business.base: DEBUG\n plus.ruoyi.business.base.controller: DEBUG\n plus.ruoyi.business.base.service: DEBUG\n plus.ruoyi.business.base.dao: DEBUG\n plus.ruoyi.business.base.authStrategy: DEBUG\n```\n\n### 常见错误及解决方案\n\n#### 错误1: 平台配置未找到\n\n```text\n错误信息: ServiceException: 未找到平台配置\n```\n\n**排查步骤:**\n1. 检查数据库中是否存在配置记录\n2. 检查appid是否正确\n3. 检查配置状态是否启用\n4. 检查租户ID是否匹配\n\n```java\n// 调试代码\nPlatform platform = platformDao.selectOne(\n new LambdaQueryWrapper<Platform>()\n .eq(Platform::getAppid, appid)\n);\nSystem.out.println(\"查询到的平台配置: \" + JsonUtils.toJsonString(platform));\n```\n\n#### 错误2: 认证策略未找到\n\n```text\n错误信息: No bean named 'miniappAuthStrategy' available\n```\n\n**排查步骤:**\n1. 检查认证策略类是否标注 `@Service` 注解\n2. 检查策略名称是否正确\n3. 检查Spring扫描路径是否包含策略类\n\n```java\n// 正确的策略命名\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME) // miniappAuthStrategy\npublic class MiniappAuthStrategy implements IAuthStrategy {\n // ...\n}\n```\n\n#### 错误3: 多租户数据泄露\n\n```text\n错误信息: 查询到了其他租户的数据\n```\n\n**排查步骤:**\n1. 检查实体类是否继承 `TenantEntity`\n2. 检查租户拦截器是否生效\n3. 检查数据表是否包含 `tenant_id` 字段\n\n```java\n// 确保实体类正确继承\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n // 自动支持租户隔离\n}\n```\n\n## API参考\n\n### Controller接口清单\n\n| 控制器 | 路径 | 功能说明 |\n|--------|------|----------|\n| PlatformController | `/base/platform/*` | 平台配置管理 |\n| PaymentController | `/base/payment/*` | 支付配置管理 |\n| BindController | `/base/bind/*` | 账号绑定管理 |\n| AdController | `/base/ad/*` | 广告配置管理 |\n| AiController | `/base/ai/*` | AI助手功能 |\n\n### 核心接口详情\n\n#### 平台配置接口\n\n```java\nGET /base/platform/list 查询平台配置列表\nGET /base/platform/{id} 查询平台配置详情\nPOST /base/platform 新增平台配置\nPUT /base/platform 更新平台配置\nDELETE /base/platform/{ids} 删除平台配置\nGET /base/platform/dict 获取平台字典\n```\n\n#### 支付配置接口\n\n```java\nGET /base/payment/list 查询支付配置列表\nGET /base/payment/{id} 查询支付配置详情\nPOST /base/payment 新增支付配置\nPUT /base/payment 更新支付配置\nDELETE /base/payment/{ids} 删除支付配置\nGET /base/payment/dict 获取支付方式字典\n```\n\n#### 账号绑定接口\n\n```java\nGET /base/bind/list 查询绑定列表\nPOST /base/bind/bindPhone 绑定手机号\nPOST /base/bind/unbind 解除绑定\n```\n\n#### AI助手接口\n\n```java\nPOST /base/ai/aiChat AI对话\nPOST /base/ai/aiOptimize 文本优化\nPOST /base/ai/aiGenerate 数据生成\nPOST /base/ai/aiReview 内容审核\nPOST /base/ai/aiTranslate 文本翻译\n```\n\n## 最佳实践\n\n### 📋 配置管理\n- 敏感信息(如密钥)使用环境变量或加密存储\n- 支持配置热更新,通过事件机制通知相关服务\n- 按租户隔离配置,确保数据安全\n- 使用Redis缓存常用配置,提升性能\n\n### 🔐 安全考虑\n- 登录令牌设置合理的过期时间(建议2小时)\n- 敏感API添加 `@SaCheckPermission` 权限校验\n- 支付配置访问权限严格控制\n- AI接口调用添加频率限制,防止滥用\n- API密钥使用环境变量管理,不提交到代码仓库\n\n### 🚀 性能优化\n- 平台配置和支付配置使用Redis缓存,有效期1小时\n- 异步处理配置更新,使用Spring事件机制\n- 合理使用数据库索引(appid、mchId等字段)\n- AI接口调用使用连接池,复用HTTP连接\n- 批量查询使用 `selectBatchIds` 而不是循环查询\n\n### 🔧 扩展建议\n- 新增平台时,实现对应的 `IAuthStrategy` 认证策略\n- 支付方式扩展遵循统一的 DAO 接口规范\n- 配置项变更通过 `ApplicationEventPublisher` 发布事件\n- AI功能扩展可添加新的服务方法,保持接口一致性\n- 建议为每个租户配置独立的平台和支付配置\n"}, "8cef6e1763c6cbc62e674a97d1c5afd41db7cf92": {"t": 1785765313.250317, "n": 27734, "h": "fd4edfde84b29047", "c": "# 基础服务模块 (base)\n\n基础服务模块提供了系统运行所需的核心基础服务,包括多平台配置管理、支付配置管理、广告配置、账号绑定等功能。\n\n## 模块结构\n\n```\nbase/\n├── controller/ # 控制器层\n│ ├── AdController.java\n│ ├── BindController.java\n│ ├── PaymentController.java\n│ └── PlatformController.java\n├── service/ # 服务层\n│ ├── IAdService.java\n│ ├── IBindService.java\n│ ├── IPaymentService.java\n│ └── IPlatformService.java\n├── domain/ # 数据模型\n│ ├── entity/ # 实体类\n│ ├── vo/ # 视图对象\n│ └── bo/ # 业务对象\n├── mapper/ # 数据访问层\n└── authStrategy/ # 认证策略\n```\n\n## 核心功能\n\n### 🏗️ 平台配置管理\n\n支持多种平台的统一配置管理:\n\n- **微信小程序** (mp-weixin)\n- **微信公众号** (mp-official-account)\n- **支付宝小程序** (mp-alipay)\n- **QQ小程序** (mp-qq)\n- **其他平台** (mp-jd, mp-kuaishou, mp-lark, mp-baidu, mp-toutiao, mp-xhs)\n\n#### 平台配置实体\n```java\n@Data\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n private Long id; // 平台配置ID\n private String type; // 平台类型\n private String name; // 平台名称\n private String appid; // 应用ID\n private String secret; // 应用密钥\n private String token; // 接口Token\n private String aeskey; // 加密密钥\n private String paymentIds; // 关联支付配置\n private String templateConfigs; // 模板配置\n private String status; // 状态\n}\n```\n\n#### 核心接口\n```java\npublic interface IPlatformService extends IBaseService<Platform, PlatformBo, PlatformVo> {\n // 继承基础CRUD操作\n}\n\n// 全局平台服务\npublic interface PlatformService {\n List<PlatformDTO> listPlatformsByType(String type, String tenantId);\n PlatformDTO getPlatformByAppidAndType(String appid, String type);\n PlatformDTO getPlatformByAppid(String appid, String tenantId);\n}\n```\n\n### 💳 支付配置管理\n\n统一的支付配置管理,支持多种支付方式:\n\n#### 支付配置实体\n```java\n@Data\n@TableName(\"b_payment\") \npublic class Payment extends TenantEntity {\n private Long id; // 支付配置ID\n private String type; // 商户类型\n private String mchName; // 商户名称\n private String mchId; // 商户号\n private String mchKey; // 商户密钥\n private String apiV3Key; // APIv3密钥\n private String certPath; // 证书路径\n private String keyPath; // 密钥路径\n private String certSerialNo; // 证书序列号\n private String status; // 状态\n}\n```\n\n#### 核心服务\n```java\npublic interface PaymentService {\n List<PaymentDTO> listPaymentByType(String type, String tenantId);\n PaymentDTO getByMchId(String mchId);\n PaymentDTO getById(Long paymentId);\n boolean existsValidMchId(String mchId);\n long countPayments();\n}\n```\n\n### 📱 账号绑定管理\n\n管理用户在不同平台的账号绑定关系:\n\n#### 绑定实体\n```java\n@Data\n@TableName(\"b_bind\")\npublic class Bind extends TenantEntity {\n private Long id; // 绑定ID\n private Long userId; // 用户ID\n private String platformType; // 平台类型\n private String appid; // 应用ID\n private String unionid; // 统一标识\n private String openid; // 平台标识\n private String extraData; // 扩展数据\n}\n```\n\n#### 绑定服务\n```java\npublic interface IBindService extends IBaseService<Bind, BindBo, BindVo> {\n /**\n * 根据平台用户信息获取或创建绑定信息\n */\n BindVo getOrCreateBind(PlatformUserInfoVo platformUserInfoVo);\n \n /**\n * 更新绑定信息的用户ID\n */\n void updateBindUserId(BindBo bindBo, Long userId);\n}\n```\n\n### 📢 广告配置管理\n\n提供广告位和广告内容的统一管理:\n\n#### 广告实体\n```java\n@Data\n@TableName(\"b_ad\")\npublic class Ad extends TenantEntity {\n private Long id; // 广告ID\n private String appid; // 应用ID\n private String adUnitId; // 广告位ID\n private String adName; // 广告名称\n private String adType; // 广告类型\n private String position; // 投放位置\n private String img; // 广告图片\n private String description; // 描述\n private String jumpAppid; // 跳转应用ID\n private String jumpPath; // 跳转路径\n private String styleConfig; // 样式配置\n private Long sortOrder; // 排序值\n private String status; // 状态\n}\n```\n\n## 认证策略\n\n### 多平台认证架构\n\n基于策略模式实现多平台登录认证:\n\n#### 认证策略接口\n```java\npublic interface IAuthStrategy {\n String BASE_NAME = \"AuthStrategy\";\n AuthTokenVo login(String body);\n}\n```\n\n#### 小程序认证策略\n```java\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME)\npublic class MiniappAuthStrategy implements IAuthStrategy {\n \n @Override\n public AuthTokenVo login(String body) {\n // 1. 解析请求参数\n PlatformLoginBody loginBody = JsonUtils.parseObject(body, PlatformLoginBody.class);\n \n // 2. 获取平台用户信息\n PlatformUserInfoVo platformUserInfo = getMiniappUserIdentity(loginBody);\n \n // 3. 加载或创建用户\n SysUserVo user = loadOrCreateUser(platformUserInfo);\n \n // 4. 生成登录令牌\n LoginUser loginUser = loginService.createLoginUser(user);\n loginUser.setPlatform(platformUserInfo.getPlatform());\n loginUser.setAppid(platformUserInfo.getAppid());\n loginUser.setOpenid(platformUserInfo.getOpenid());\n loginUser.setUnionid(platformUserInfo.getUnionid());\n \n // 5. 完成登录\n LoginHelper.login(loginUser, loginParameter);\n \n // 6. 返回认证结果\n AuthTokenVo authTokenVo = new AuthTokenVo();\n authTokenVo.setAccessToken(StpUtil.getTokenValue());\n authTokenVo.setExpireIn(StpUtil.getTokenTimeout());\n return authTokenVo;\n }\n}\n```\n\n#### 公众号认证策略\n```java\n@Service(\"mp\" + IAuthStrategy.BASE_NAME)\npublic class MpAuthStrategy implements IAuthStrategy {\n // 公众号OAuth2.0认证流程实现\n // 支持网页授权登录场景\n}\n```\n\n### 认证流程\n\n1. **前端授权**:用户在前端完成平台授权,获取授权码\n2. **策略选择**:后端根据平台类型自动选择对应认证策略\n3. **信息获取**:通过授权码换取用户基本信息\n4. **账号绑定**:查找或创建用户账号绑定关系\n5. **令牌生成**:生成JWT访问令牌\n6. **登录完成**:返回令牌和用户信息\n\n## 手机号绑定\n\n### 微信小程序手机号获取\n```java\n@PostMapping(\"/bindPhone\")\npublic R<PhoneBindVo> bindPhone(@RequestBody PhoneBindBo bo) {\n LoginUser loginUser = LoginHelper.getLoginUser();\n wxMaService.switchover(loginUser.getAppid());\n \n try {\n WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(bo.getCode());\n String phone = phoneInfo.getPhoneNumber();\n \n // 更新用户手机号\n SysUser sysUser = userMapper.selectById(loginUser.getUserId());\n sysUser.setPhone(phone);\n userMapper.updateById(sysUser);\n \n return R.ok(\"绑定成功\", PhoneBindVo.of(phone));\n } catch (WxErrorException e) {\n return R.fail(\"获取手机号出错\");\n }\n}\n```\n\n## 数据字典服务\n\n### 支付方式字典\n```java\n@GetMapping(\"getPaymentDict\")\npublic R<List<DictItemVo>> getPaymentDict() {\n // 查询所有可用的支付方式\n List<PaymentVo> paymentVoList = paymentService.list(\n PlusLambdaQuery.of(Payment.class)\n .eq(Payment::getStatus, DictEnableStatus.ENABLE.getValue()));\n \n // 构建字典项列表\n List<DictItemVo> dictItems = StreamUtils.toList(paymentVoList, payment ->\n DictItemVo.of(payment.getMchName(), payment.getId().toString(), \"success\")\n );\n return R.ok(dictItems);\n}\n```\n\n## 配置管理\n\n### 平台配置热更新\n```java\nprivate void reloadPlatformConfig() {\n String tenantId = TenantHelper.getTenantId();\n \n // 重新初始化微信小程序配置\n SpringUtils.getBean(WxMaApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化微信公众号配置 \n SpringUtils.getBean(WxMpApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化支付配置\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n### 支付配置热更新\n```java\nprivate void reloadPaymentConfig() {\n String tenantId = TenantHelper.getTenantId();\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n## 使用示例\n\n### 配置微信小程序\n```java\n// 1. 创建平台配置\nPlatformBo platformBo = new PlatformBo();\nplatformBo.setType(\"mp-weixin\");\nplatformBo.setName(\"我的小程序\");\nplatformBo.setAppid(\"wx1234567890\");\nplatformBo.setSecret(\"your-secret\");\nplatformBo.setStatus(\"1\");\nplatformService.add(platformBo);\n\n// 2. 配置支付信息\nPaymentBo paymentBo = new PaymentBo();\npaymentBo.setType(\"wechat\");\npaymentBo.setMchName(\"我的商户\");\npaymentBo.setMchId(\"1234567890\");\npaymentBo.setMchKey(\"your-mch-key\");\npaymentBo.setStatus(\"1\");\npaymentService.add(paymentBo);\n```\n\n### 用户登录认证\n```java\n// 前端调用登录接口\nPOST /auth/login\n{\n \"platform\": \"miniapp\",\n \"body\": {\n \"platform\": \"mp-weixin\",\n \"appid\": \"wx1234567890\",\n \"platformCode\": \"授权码\"\n }\n}\n\n// 返回结果\n{\n \"code\": 200,\n \"msg\": \"登录成功\",\n \"data\": {\n \"accessToken\": \"eyJ0eXAiOiJKV1Q...\",\n \"expireIn\": 7200\n }\n}\n```\n\n## AI助手功能\n\n### 🤖 功能概述\n\n基础服务模块集成了强大的AI助手功能,基于 **LangChain4j** 框架实现,支持多种大语言模型(如 DeepSeek、通义千问、OpenAI、Claude等),为业务系统提供智能化能力。\n\n**核心特性:**\n- **多模型支持** - 灵活切换不同的AI模型提供商\n- **多场景应用** - 对话、优化、生成、审核、翻译等场景\n- **条件启用** - 通过配置开关控制功能启用\n- **权限控制** - 完善的权限校验机制\n- **上下文传递** - 支持业务上下文信息传递\n\n### AI服务接口\n\n#### AiController 控制器\n\n```java\n@RestController\n@RequestMapping(\"/base/ai\")\n@ConditionalOnProperty(\n prefix = \"langchain4j\",\n name = \"enabled\",\n havingValue = \"true\",\n matchIfMissing = true\n)\npublic class AiController {\n private final IAiService aiService;\n}\n```\n\n**条件启用说明:**\n- 需要在配置文件中设置 `langchain4j.enabled=true`\n- 如果配置项不存在,默认启用 (`matchIfMissing = true`)\n\n### 1. AI对话功能\n\n通用的AI对话接口,支持自由对话场景。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiChat\")\n@OpenApi(value = \"AI对话\")\npublic R<AiChatVo> aiChat(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiChat(bo));\n}\n```\n\n#### 请求示例\n\n```java\n// 创建对话请求\nAiChatBo chatBo = new AiChatBo();\nchatBo.setMessage(\"请帮我解释一下什么是微服务架构\");\nchatBo.setProvider(\"deepseek\");\nchatBo.setModelName(\"deepseek-chat\");\nchatBo.setTemperature(0.7);\nchatBo.setMaxTokens(2000);\n\n// 调用接口\nR<AiChatVo> result = aiController.aiChat(chatBo);\nAiChatVo response = result.getData();\nSystem.out.println(\"AI回复: \" + response.getMessage());\n```\n\n#### HTTP 调用示例\n\n```bash\nPOST /base/ai/aiChat\nContent-Type: application/json\n\n{\n \"message\": \"请帮我解释一下什么是微服务架构\",\n \"provider\": \"deepseek\",\n \"modelName\": \"deepseek-chat\",\n \"temperature\": 0.7,\n \"maxTokens\": 2000\n}\n```\n\n### 2. 文本优化功能\n\n对用户输入的文本进行优化,改善表达和文风。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiOptimize\")\n@OpenApi(value = \"AI文本优化\")\npublic R<AiChatVo> aiOptimize(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiOptimize(bo));\n}\n```\n\n#### 使用场景\n\n- 文章润色和改写\n- 产品描述优化\n- 邮件内容优化\n- 广告文案优化\n\n#### 请求示例\n\n```java\nAiChatBo optimizeBo = new AiChatBo();\noptimizeBo.setMessage(\"我们公司是做软件开发的,主要业务是给客户做系统\");\noptimizeBo.setAiFeature(\"optimize\");\noptimizeBo.setSystemPrompt(\"请将下列文本优化为更专业的企业简介\");\n\nR<AiChatVo> result = aiController.aiOptimize(optimizeBo);\n// 优化后: \"我们是一家专业的软件开发公司,致力于为企业客户提供定制化系统解决方案...\"\n```\n\n### 3. 数据生成功能\n\n根据用户需求生成结构化数据或内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiGenerate\")\n@OpenApi(value = \"AI数据生成\")\npublic R<AiChatVo> aiGenerate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiGenerate(bo));\n}\n```\n\n#### 使用场景\n\n- 生成测试数据\n- 生成产品描述\n- 生成代码片段\n- 生成用户画像\n\n#### 请求示例\n\n```java\nAiChatBo generateBo = new AiChatBo();\ngenerateBo.setMessage(\"生成5个用户的测试数据,包含姓名、年龄、邮箱\");\ngenerateBo.setAiFeature(\"generate\");\n\n// 传递表单字段信息作为上下文\nMap<String, Object> context = new HashMap<>();\ncontext.put(\"fields\", Arrays.asList(\"name\", \"age\", \"email\"));\ncontext.put(\"count\", 5);\ngenerateBo.setContext(context);\n\nR<AiChatVo> result = aiController.aiGenerate(generateBo);\n```\n\n**生成结果示例:**\n```json\n[\n {\"name\": \"张三\", \"age\": 28, \"email\": \"zhangsan@example.com\"},\n {\"name\": \"李四\", \"age\": 32, \"email\": \"lisi@example.com\"},\n {\"name\": \"王五\", \"age\": 25, \"email\": \"wangwu@example.com\"},\n {\"name\": \"赵六\", \"age\": 30, \"email\": \"zhaoliu@example.com\"},\n {\"name\": \"钱七\", \"age\": 27, \"email\": \"qianqi@example.com\"}\n]\n```\n\n### 4. 内容审核功能\n\n对用户提交的内容进行智能审核,检测违规内容。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiReview\")\n@OpenApi(value = \"AI内容审核\")\npublic R<AiChatVo> aiReview(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiReview(bo));\n}\n```\n\n#### 使用场景\n\n- 评论内容审核\n- 文章内容审核\n- 用户昵称审核\n- 敏感词检测\n\n#### 请求示例\n\n```java\nAiChatBo reviewBo = new AiChatBo();\nreviewBo.setMessage(\"待审核的用户评论内容...\");\nreviewBo.setAiFeature(\"review\");\nreviewBo.setSystemPrompt(\"请审核以下内容是否包含违规、敏感、广告等不当信息\");\n\nR<AiChatVo> result = aiController.aiReview(reviewBo);\nAiChatVo response = result.getData();\n\n// 解析审核结果\nif (response.getMessage().contains(\"通过\")) {\n // 内容合规,允许发布\n} else {\n // 内容违规,拒绝发布\n}\n```\n\n### 5. 文本翻译功能\n\n提供多语言翻译服务。\n\n#### 接口定义\n\n```java\n@PostMapping(\"/aiTranslate\")\n@OpenApi(value = \"AI文本翻译\")\npublic R<AiChatVo> aiTranslate(@Valid @RequestBody AiChatBo bo) {\n return R.ok(aiService.aiTranslate(bo));\n}\n```\n\n#### 使用场景\n\n- 多语言网站内容翻译\n- 用户评论翻译\n- 产品说明翻译\n- 客服消息翻译\n\n#### 请求示例\n\n```java\nAiChatBo translateBo = new AiChatBo();\ntranslateBo.setMessage(\"Hello, how are you today?\");\ntranslateBo.setAiFeature(\"translate\");\ntranslateBo.setSystemPrompt(\"请将以下英文翻译成中文\");\n\nR<AiChatVo> result = aiController.aiTranslate(translateBo);\n// 翻译结果: \"你好,你今天怎么样?\"\n```\n\n### AI配置说明\n\n#### LangChain4j 配置\n\n在 `application.yml` 中配置 LangChain4j:\n\n```yaml\nlangchain4j:\n enabled: true # 启用AI功能\n\n # DeepSeek 配置\n deepseek:\n api-key: ${DEEPSEEK_API_KEY}\n base-url: https://api.deepseek.com/v1\n model-name: deepseek-chat\n temperature: 0.7\n max-tokens: 2000\n timeout: 60s\n\n # 通义千问配置\n qianwen:\n api-key: ${QIANWEN_API_KEY}\n base-url: https://dashscope.aliyuncs.com/api/v1\n model-name: qwen-plus\n temperature: 0.7\n max-tokens: 2000\n\n # OpenAI 配置\n openai:\n api-key: ${OPENAI_API_KEY}\n base-url: https://api.openai.com/v1\n model-name: gpt-3.5-turbo\n temperature: 0.7\n max-tokens: 2000\n```\n\n#### 环境变量配置\n\n推荐使用环境变量管理敏感的API密钥:\n\n```bash\n# .env 文件\nDEEPSEEK_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nQIANWEN_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\nOPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n#### 权限配置\n\n在菜单管理中配置AI功能权限:\n\n```sql\n-- AI对话权限\nINSERT INTO sys_menu (menu_name, parent_id, perms)\nVALUES ('AI对话', 1000, 'base:ai:chat');\n```\n\n### AI功能集成示例\n\n#### 示例1:智能客服回复\n\n```java\n@Service\npublic class CustomerServiceImpl implements ICustomerService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public String handleCustomerQuestion(String question) {\n AiChatBo chatBo = new AiChatBo();\n chatBo.setMessage(question);\n chatBo.setProvider(\"deepseek\");\n chatBo.setSystemPrompt(\"你是一个友好的客服助手,请专业地回答客户问题\");\n\n AiChatVo response = aiService.aiChat(chatBo);\n return response.getMessage();\n }\n}\n```\n\n#### 示例2:文章内容审核\n\n```java\n@Service\npublic class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public boolean publishArticle(Article article) {\n // 使用AI审核文章内容\n AiChatBo reviewBo = new AiChatBo();\n reviewBo.setMessage(article.getContent());\n reviewBo.setAiFeature(\"review\");\n reviewBo.setSystemPrompt(\"请审核文章内容是否合规,检查是否包含违规、敏感信息\");\n\n AiChatVo reviewResult = aiService.aiReview(reviewBo);\n\n // 判断审核结果\n if (reviewResult.getMessage().contains(\"违规\")) {\n throw new ServiceException(\"文章内容审核未通过: \" + reviewResult.getMessage());\n }\n\n // 审核通过,发布文章\n article.setStatus(\"published\");\n return this.updateById(article);\n }\n}\n```\n\n#### 示例3:数据智能生成\n\n```java\n@Service\npublic class DataGeneratorService {\n\n @Autowired\n private IAiService aiService;\n\n @Override\n public List<User> generateTestUsers(int count) {\n AiChatBo generateBo = new AiChatBo();\n generateBo.setMessage(\n String.format(\"生成%d个用户测试数据,包含真实的中文姓名、邮箱、手机号\", count)\n );\n generateBo.setAiFeature(\"generate\");\n\n // 传递数据结构上下文\n Map<String, Object> context = new HashMap<>();\n context.put(\"format\", \"json\");\n context.put(\"fields\", Arrays.asList(\"name\", \"email\", \"phone\", \"age\", \"gender\"));\n generateBo.setContext(context);\n\n AiChatVo response = aiService.aiGenerate(generateBo);\n\n // 解析生成的JSON数据\n return JsonUtils.parseArray(response.getMessage(), User.class);\n }\n}\n```\n\n## 数据访问层架构\n\n### DAO模式说明\n\n基础服务模块采用 **DAO(Data Access Object)** 模式,将数据访问逻辑与业务逻辑分离,提供更清晰的架构层次。\n\n#### 架构层次\n\n```\nController 层\n ↓\nService 层\n ↓\nDAO 层 (IBaseDao)\n ↓\nEntity 层 (数据库实体)\n```\n\n#### IBaseDao 接口\n\n所有 DAO 接口都继承自 `IBaseDao`,提供统一的 CRUD 操作:\n\n```java\npublic interface IBaseDao<T> {\n // 插入\n boolean insert(T entity);\n boolean insertBatch(Collection<T> entityList);\n\n // 更新\n boolean updateById(T entity);\n boolean updateBatchById(Collection<T> entityList);\n\n // 删除\n boolean deleteById(Serializable id);\n boolean deleteBatchIds(Collection<?> idList);\n\n // 查询\n T selectById(Serializable id);\n List<T> selectBatchIds(Collection<? extends Serializable> idList);\n List<T> selectList(Wrapper<T> queryWrapper);\n T selectOne(Wrapper<T> queryWrapper);\n Long selectCount(Wrapper<T> queryWrapper);\n\n // 分页查询\n Page<T> selectPage(Page<T> page, Wrapper<T> queryWrapper);\n}\n```\n\n### 平台配置DAO (IPlatformDao)\n\n```java\npublic interface IPlatformDao extends IBaseDao<Platform> {\n\n /**\n * 根据业务对象构建查询条件\n */\n PlusLambdaQuery<Platform> buildQueryWrapper(PlatformBo bo);\n\n /**\n * 根据appid查询平台配置\n */\n Platform getByAppid(String appid);\n\n /**\n * 根据appid和平台类型查询平台配置\n */\n Platform getByAppidAndType(String appid, String type, String status);\n\n /**\n * 根据平台类型和状态查询配置列表\n */\n List<Platform> listByTypeAndStatus(String type, String status);\n}\n```\n\n### 支付配置DAO (IPaymentDao)\n\n```java\npublic interface IPaymentDao extends IBaseDao<Payment> {\n\n /**\n * 根据商户号查询支付配置\n */\n Payment getByMchId(String mchId, String status);\n\n /**\n * 根据支付类型和状态查询配置列表\n */\n List<Payment> listByTypeAndStatus(String type, String status);\n\n /**\n * 根据状态统计配置数量\n */\n long countByStatus(String status);\n\n /**\n * 根据商户号查询是否存在(排除指定ID)\n */\n boolean existsByMchId(String mchId, Long excludeId);\n\n /**\n * 根据商户号和状态判断是否存在\n */\n boolean existsByMchIdAndStatus(String mchId, String status);\n\n /**\n * 根据状态查询配置列表\n */\n List<Payment> listByStatus(String status);\n}\n```\n\n### DAO层使用示例\n\n```java\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private IPlatformDao platformDao;\n\n @Override\n public PlatformVo getWeixinPlatform(String appid) {\n // 使用DAO查询微信小程序配置\n Platform platform = platformDao.getByAppidAndType(\n appid,\n \"mp-weixin\",\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (platform == null) {\n throw new ServiceException(\"未找到微信小程序配置\");\n }\n\n return BeanUtil.toBean(platform, PlatformVo.class);\n }\n\n @Override\n public List<PlatformVo> listActivePlatforms(String type) {\n // 使用DAO查询所有启用的平台配置\n List<Platform> platforms = platformDao.listByTypeAndStatus(\n type,\n DictEnableStatus.ENABLE.getValue()\n );\n\n return BeanUtil.copyToList(platforms, PlatformVo.class);\n }\n}\n```\n\n## 高级功能\n\n### 多租户支持\n\n基础服务模块所有实体类都继承自 `TenantEntity`,自动支持多租户数据隔离。\n\n#### 租户实体基类\n\n```java\n@Data\npublic class TenantEntity extends BaseEntity {\n\n /**\n * 租户ID\n */\n @TableField(value = \"tenant_id\")\n private String tenantId;\n\n /**\n * 创建部门\n */\n @TableField(value = \"create_dept\")\n private Long createDept;\n}\n```\n\n#### 自动租户隔离\n\n```java\n// 查询时自动添加租户条件\nPlatform platform = platformDao.selectById(platformId);\n// SQL: SELECT * FROM b_platform WHERE id = ? AND tenant_id = '当前租户ID'\n\n// 新增时自动填充租户ID\nPlatform newPlatform = new Platform();\nnewPlatform.setType(\"mp-weixin\");\nplatformDao.insert(newPlatform);\n// SQL: INSERT INTO b_platform (..., tenant_id) VALUES (..., '当前租户ID')\n```\n\n### 数据缓存机制\n\n#### Redis缓存配置\n\n平台配置和支付配置支持Redis缓存,提升查询性能:\n\n```java\n@Service\npublic class PlatformCacheService {\n\n private static final String PLATFORM_CACHE_KEY = \"platform:config:\";\n private static final Duration CACHE_EXPIRE = Duration.ofHours(1);\n\n @Autowired\n private RedisTemplate<String, Platform> redisTemplate;\n\n @Autowired\n private IPlatformDao platformDao;\n\n public Platform getPlatformWithCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n\n // 尝试从缓存获取\n Platform platform = redisTemplate.opsForValue().get(cacheKey);\n if (platform != null) {\n return platform;\n }\n\n // 缓存未命中,查询数据库\n platform = platformDao.getByAppid(appid);\n if (platform != null) {\n // 写入缓存\n redisTemplate.opsForValue().set(cacheKey, platform, CACHE_EXPIRE);\n }\n\n return platform;\n }\n\n public void clearPlatformCache(String appid) {\n String cacheKey = PLATFORM_CACHE_KEY + appid;\n redisTemplate.delete(cacheKey);\n }\n}\n```\n\n### 事件监听机制\n\n#### 配置变更事件\n\n```java\n@Component\npublic class PlatformConfigEventListener {\n\n @Autowired\n private WxMaApplicationRunner wxMaRunner;\n\n @Autowired\n private WxMpApplicationRunner wxMpRunner;\n\n /**\n * 监听平台配置变更事件\n */\n @EventListener\n public void handlePlatformConfigChange(PlatformConfigChangeEvent event) {\n String tenantId = event.getTenantId();\n String platformType = event.getPlatformType();\n\n // 根据平台类型重新初始化配置\n if (\"mp-weixin\".equals(platformType)) {\n wxMaRunner.initByTenant(tenantId);\n } else if (\"mp-official-account\".equals(platformType)) {\n wxMpRunner.initByTenant(tenantId);\n }\n\n log.info(\"平台配置已更新: tenantId={}, platformType={}\", tenantId, platformType);\n }\n}\n```\n\n#### 自定义事件\n\n```java\n@Data\npublic class PlatformConfigChangeEvent extends ApplicationEvent {\n\n private String tenantId;\n private String platformType;\n private String action; // create, update, delete\n\n public PlatformConfigChangeEvent(Object source, String tenantId, String platformType, String action) {\n super(source);\n this.tenantId = tenantId;\n this.platformType = platformType;\n this.action = action;\n }\n}\n\n// 发布事件\n@Service\npublic class PlatformServiceImpl implements IPlatformService {\n\n @Autowired\n private ApplicationEventPublisher eventPublisher;\n\n @Override\n @Transactional\n public boolean updatePlatform(PlatformBo bo) {\n boolean result = platformDao.updateById(BeanUtil.toBean(bo, Platform.class));\n\n if (result) {\n // 发布配置变更事件\n eventPublisher.publishEvent(\n new PlatformConfigChangeEvent(this, TenantHelper.getTenantId(), bo.getType(), \"update\")\n );\n }\n\n return result;\n }\n}\n```\n\n## 常见问题\n\n### Q1: 平台配置不生效?\n\n**问题原因:**\n- 配置状态未启用\n- 租户ID不匹配\n- 缓存未更新\n- appid配置错误\n\n**解决方案:**\n\n```java\n// 1. 检查配置状态\nPlatform platform = platformDao.getByAppid(appid);\nif (!\"1\".equals(platform.getStatus())) {\n throw new ServiceException(\"平台配置未启用\");\n}\n\n// 2. 检查租户ID\nString currentTenantId = TenantHelper.getTenantId();\nif (!currentTenantId.equals(platform.getTenantId())) {\n throw new ServiceException(\"平台配置不属于当前租户\");\n}\n\n// 3. 清除缓存重新加载\nwxMaApplicationRunner.initByTenant(currentTenantId);\n```\n\n### Q2: 第三方登录失败?\n\n**问题原因:**\n- appid或secret配置错误\n- 授权码已过期\n- 平台配置未找到\n- 网络连接问题\n\n**解决方案:**\n\n```java\ntry {\n // 使用授权码登录\n AuthTokenVo authToken = authStrategy.login(loginBody);\n} catch (WxErrorException e) {\n // 微信接口调用失败\n log.error(\"微信登录失败: errCode={}, errMsg={}\", e.getError().getErrorCode(), e.getError().getErrorMsg());\n\n if (e.getError().getErrorCode() == 40029) {\n throw new ServiceException(\"授权码无效或已过期,请重新授权\");\n } else if (e.getError().getErrorCode() == 40013) {\n throw new ServiceException(\"appid配置错误\");\n } else {\n throw new ServiceException(\"登录失败: \" + e.getError().getErrorMsg());\n }\n}\n```\n\n### Q3: 支付配置重复?\n\n**问题原因:**\n- 同一商户号被多次配置\n- 未进行唯一性校验\n\n**解决方案:**\n\n```java\n@Service\npublic class PaymentServiceImpl implements IPaymentService {\n\n @Override\n public boolean addPayment(PaymentBo bo) {\n // 检查商户号是否已存在\n boolean exists = paymentDao.existsByMchIdAndStatus(\n bo.getMchId(),\n DictEnableStatus.ENABLE.getValue()\n );\n\n if (exists) {\n throw new ServiceException(\"该商户号已存在有效配置\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.insert(payment);\n }\n\n @Override\n public boolean updatePayment(PaymentBo bo) {\n // 检查商户号是否与其他记录重复(排除当前记录)\n boolean exists = paymentDao.existsByMchId(bo.getMchId(), bo.getId());\n\n if (exists) {\n throw new ServiceException(\"该商户号已被其他配置使用\");\n }\n\n Payment payment = BeanUtil.toBean(bo, Payment.class);\n return paymentDao.updateById(payment);\n }\n}\n```\n\n### Q4: AI功能无法使用?\n\n**问题原因:**\n- LangChain4j未启用\n- API密钥配置错误\n- 网络连接问题\n- 权限未配置\n\n**解决方案:**\n\n```yaml\n# 1. 确保配置已启用\nlangchain4j:\n enabled: true # 必须为 true\n\n# 2. 检查API密钥\ndeepseek:\n api-key: ${DEEPSEEK_API_KEY} # 确保环境变量已设置\n\n# 3. 测试网络连接\ncurl -X POST https://api.deepseek.com/v1/chat/completions \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"Hello\"}]}'\n\n# 4. 配置权限\nINSERT INTO sys_menu (menu_name, perms) VALUES ('AI对话', 'base:ai:chat');\n```\n\n## 故障排查\n\n### 日志配置\n\n#### 启用详细日志\n\n```yaml\nlogging:\n level:\n plus.ruoyi.business.base: DEBUG\n plus.ruoyi.business.base.controller: DEBUG\n plus.ruoyi.business.base.service: DEBUG\n plus.ruoyi.business.base.dao: DEBUG\n plus.ruoyi.business.base.authStrategy: DEBUG\n```\n\n### 常见错误及解决方案\n\n#### 错误1: 平台配置未找到\n\n```\n错误信息: ServiceException: 未找到平台配置\n```\n\n**排查步骤:**\n1. 检查数据库中是否存在配置记录\n2. 检查appid是否正确\n3. 检查配置状态是否启用\n4. 检查租户ID是否匹配\n\n```java\n// 调试代码\nPlatform platform = platformDao.selectOne(\n new LambdaQueryWrapper<Platform>()\n .eq(Platform::getAppid, appid)\n);\nSystem.out.println(\"查询到的平台配置: \" + JsonUtils.toJsonString(platform));\n```\n\n#### 错误2: 认证策略未找到\n\n```\n错误信息: No bean named 'miniappAuthStrategy' available\n```\n\n**排查步骤:**\n1. 检查认证策略类是否标注 `@Service` 注解\n2. 检查策略名称是否正确\n3. 检查Spring扫描路径是否包含策略类\n\n```java\n// 正确的策略命名\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME) // miniappAuthStrategy\npublic class MiniappAuthStrategy implements IAuthStrategy {\n // ...\n}\n```\n\n#### 错误3: 多租户数据泄露\n\n```\n错误信息: 查询到了其他租户的数据\n```\n\n**排查步骤:**\n1. 检查实体类是否继承 `TenantEntity`\n2. 检查租户拦截器是否生效\n3. 检查数据表是否包含 `tenant_id` 字段\n\n```java\n// 确保实体类正确继承\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n // 自动支持租户隔离\n}\n```\n\n## API参考\n\n### Controller接口清单\n\n| 控制器 | 路径 | 功能说明 |\n|--------|------|----------|\n| PlatformController | `/base/platform/*` | 平台配置管理 |\n| PaymentController | `/base/payment/*` | 支付配置管理 |\n| BindController | `/base/bind/*` | 账号绑定管理 |\n| AdController | `/base/ad/*` | 广告配置管理 |\n| AiController | `/base/ai/*` | AI助手功能 |\n\n### 核心接口详情\n\n#### 平台配置接口\n\n```java\nGET /base/platform/list 查询平台配置列表\nGET /base/platform/{id} 查询平台配置详情\nPOST /base/platform 新增平台配置\nPUT /base/platform 更新平台配置\nDELETE /base/platform/{ids} 删除平台配置\nGET /base/platform/dict 获取平台字典\n```\n\n#### 支付配置接口\n\n```java\nGET /base/payment/list 查询支付配置列表\nGET /base/payment/{id} 查询支付配置详情\nPOST /base/payment 新增支付配置\nPUT /base/payment 更新支付配置\nDELETE /base/payment/{ids} 删除支付配置\nGET /base/payment/dict 获取支付方式字典\n```\n\n#### 账号绑定接口\n\n```java\nGET /base/bind/list 查询绑定列表\nPOST /base/bind/bindPhone 绑定手机号\nPOST /base/bind/unbind 解除绑定\n```\n\n#### AI助手接口\n\n```java\nPOST /base/ai/aiChat AI对话\nPOST /base/ai/aiOptimize 文本优化\nPOST /base/ai/aiGenerate 数据生成\nPOST /base/ai/aiReview 内容审核\nPOST /base/ai/aiTranslate 文本翻译\n```\n\n## 最佳实践\n\n### 📋 配置管理\n- 敏感信息(如密钥)使用环境变量或加密存储\n- 支持配置热更新,通过事件机制通知相关服务\n- 按租户隔离配置,确保数据安全\n- 使用Redis缓存常用配置,提升性能\n\n### 🔐 安全考虑\n- 登录令牌设置合理的过期时间(建议2小时)\n- 敏感API添加 `@SaCheckPermission` 权限校验\n- 支付配置访问权限严格控制\n- AI接口调用添加频率限制,防止滥用\n- API密钥使用环境变量管理,不提交到代码仓库\n\n### 🚀 性能优化\n- 平台配置和支付配置使用Redis缓存,有效期1小时\n- 异步处理配置更新,使用Spring事件机制\n- 合理使用数据库索引(appid、mchId等字段)\n- AI接口调用使用连接池,复用HTTP连接\n- 批量查询使用 `selectBatchIds` 而不是循环查询\n\n### 🔧 扩展建议\n- 新增平台时,实现对应的 `IAuthStrategy` 认证策略\n- 支付方式扩展遵循统一的 DAO 接口规范\n- 配置项变更通过 `ApplicationEventPublisher` 发布事件\n- AI功能扩展可添加新的服务方法,保持接口一致性\n- 建议为每个租户配置独立的平台和支付配置\n"}, "3a08cad78b6d3370115044894b57554304e28199": {"t": 1785765316.668726, "n": 8440, "h": "1b41b9353a9f5514", "c": "# 基础服务模块 (base)\n\n基础服务模块提供了系统运行所需的核心基础服务,包括多平台配置管理、支付配置管理、广告配置、账号绑定等功能。\n\n## 模块结构\n\n```\nbase/\n├── controller/ # 控制器层\n│ ├── AdController.java\n│ ├── BindController.java\n│ ├── PaymentController.java\n│ └── PlatformController.java\n├── service/ # 服务层\n│ ├── IAdService.java\n│ ├── IBindService.java\n│ ├── IPaymentService.java\n│ └── IPlatformService.java\n├── domain/ # 数据模型\n│ ├── entity/ # 实体类\n│ ├── vo/ # 视图对象\n│ └── bo/ # 业务对象\n├── mapper/ # 数据访问层\n└── authStrategy/ # 认证策略\n```\n\n## 核心功能\n\n### 🏗️ 平台配置管理\n\n支持多种平台的统一配置管理:\n\n- **微信小程序** (mp-weixin)\n- **微信公众号** (mp-official-account)\n- **支付宝小程序** (mp-alipay)\n- **QQ小程序** (mp-qq)\n- **其他平台** (mp-jd, mp-kuaishou, mp-lark, mp-baidu, mp-toutiao, mp-xhs)\n\n#### 平台配置实体\n```java\n@Data\n@TableName(\"b_platform\")\npublic class Platform extends TenantEntity {\n private Long id; // 平台配置ID\n private String type; // 平台类型\n private String name; // 平台名称\n private String appid; // 应用ID\n private String secret; // 应用密钥\n private String token; // 接口Token\n private String aeskey; // 加密密钥\n private String paymentIds; // 关联支付配置\n private String templateConfigs; // 模板配置\n private String status; // 状态\n}\n```\n\n#### 核心接口\n```java\npublic interface IPlatformService extends IBaseService<Platform, PlatformBo, PlatformVo> {\n // 继承基础CRUD操作\n}\n\n// 全局平台服务\npublic interface PlatformService {\n List<PlatformDTO> listPlatformsByType(String type, String tenantId);\n PlatformDTO getPlatformByAppidAndType(String appid, String type);\n PlatformDTO getPlatformByAppid(String appid, String tenantId);\n}\n```\n\n### 💳 支付配置管理\n\n统一的支付配置管理,支持多种支付方式:\n\n#### 支付配置实体\n```java\n@Data\n@TableName(\"b_payment\") \npublic class Payment extends TenantEntity {\n private Long id; // 支付配置ID\n private String type; // 商户类型\n private String mchName; // 商户名称\n private String mchId; // 商户号\n private String mchKey; // 商户密钥\n private String apiV3Key; // APIv3密钥\n private String certPath; // 证书路径\n private String keyPath; // 密钥路径\n private String certSerialNo; // 证书序列号\n private String status; // 状态\n}\n```\n\n#### 核心服务\n```java\npublic interface PaymentService {\n List<PaymentDTO> listPaymentByType(String type, String tenantId);\n PaymentDTO getByMchId(String mchId);\n PaymentDTO getById(Long paymentId);\n boolean existsValidMchId(String mchId);\n long countPayments();\n}\n```\n\n### 📱 账号绑定管理\n\n管理用户在不同平台的账号绑定关系:\n\n#### 绑定实体\n```java\n@Data\n@TableName(\"b_bind\")\npublic class Bind extends TenantEntity {\n private Long id; // 绑定ID\n private Long userId; // 用户ID\n private String platformType; // 平台类型\n private String appid; // 应用ID\n private String unionid; // 统一标识\n private String openid; // 平台标识\n private String extraData; // 扩展数据\n}\n```\n\n#### 绑定服务\n```java\npublic interface IBindService extends IBaseService<Bind, BindBo, BindVo> {\n /**\n * 根据平台用户信息获取或创建绑定信息\n */\n BindVo getOrCreateBind(PlatformUserInfoVo platformUserInfoVo);\n \n /**\n * 更新绑定信息的用户ID\n */\n void updateBindUserId(BindBo bindBo, Long userId);\n}\n```\n\n### 📢 广告配置管理\n\n提供广告位和广告内容的统一管理:\n\n#### 广告实体\n```java\n@Data\n@TableName(\"b_ad\")\npublic class Ad extends TenantEntity {\n private Long id; // 广告ID\n private String appid; // 应用ID\n private String adUnitId; // 广告位ID\n private String adName; // 广告名称\n private String adType; // 广告类型\n private String position; // 投放位置\n private String img; // 广告图片\n private String description; // 描述\n private String jumpAppid; // 跳转应用ID\n private String jumpPath; // 跳转路径\n private String styleConfig; // 样式配置\n private Long sortOrder; // 排序值\n private String status; // 状态\n}\n```\n\n## 认证策略\n\n### 多平台认证架构\n\n基于策略模式实现多平台登录认证:\n\n#### 认证策略接口\n```java\npublic interface IAuthStrategy {\n String BASE_NAME = \"AuthStrategy\";\n AuthTokenVo login(String body);\n}\n```\n\n#### 小程序认证策略\n```java\n@Service(\"miniapp\" + IAuthStrategy.BASE_NAME)\npublic class MiniappAuthStrategy implements IAuthStrategy {\n \n @Override\n public AuthTokenVo login(String body) {\n // 1. 解析请求参数\n PlatformLoginBody loginBody = JsonUtils.parseObject(body, PlatformLoginBody.class);\n \n // 2. 获取平台用户信息\n PlatformUserInfoVo platformUserInfo = getMiniappUserIdentity(loginBody);\n \n // 3. 加载或创建用户\n SysUserVo user = loadOrCreateUser(platformUserInfo);\n \n // 4. 生成登录令牌\n LoginUser loginUser = loginService.createLoginUser(user);\n loginUser.setPlatform(platformUserInfo.getPlatform());\n loginUser.setAppid(platformUserInfo.getAppid());\n loginUser.setOpenid(platformUserInfo.getOpenid());\n loginUser.setUnionid(platformUserInfo.getUnionid());\n \n // 5. 完成登录\n LoginHelper.login(loginUser, loginParameter);\n \n // 6. 返回认证结果\n AuthTokenVo authTokenVo = new AuthTokenVo();\n authTokenVo.setAccessToken(StpUtil.getTokenValue());\n authTokenVo.setExpireIn(StpUtil.getTokenTimeout());\n return authTokenVo;\n }\n}\n```\n\n#### 公众号认证策略\n```java\n@Service(\"mp\" + IAuthStrategy.BASE_NAME)\npublic class MpAuthStrategy implements IAuthStrategy {\n // 公众号OAuth2.0认证流程实现\n // 支持网页授权登录场景\n}\n```\n\n### 认证流程\n\n1. **前端授权**:用户在前端完成平台授权,获取授权码\n2. **策略选择**:后端根据平台类型自动选择对应认证策略\n3. **信息获取**:通过授权码换取用户基本信息\n4. **账号绑定**:查找或创建用户账号绑定关系\n5. **令牌生成**:生成JWT访问令牌\n6. **登录完成**:返回令牌和用户信息\n\n## 手机号绑定\n\n### 微信小程序手机号获取\n```java\n@PostMapping(\"/bindPhone\")\npublic R<PhoneBindVo> bindPhone(@RequestBody PhoneBindBo bo) {\n LoginUser loginUser = LoginHelper.getLoginUser();\n wxMaService.switchover(loginUser.getAppid());\n \n try {\n WxMaPhoneNumberInfo phoneInfo = wxMaService.getUserService().getPhoneNumber(bo.getCode());\n String phone = phoneInfo.getPhoneNumber();\n \n // 更新用户手机号\n SysUser sysUser = userMapper.selectById(loginUser.getUserId());\n sysUser.setPhone(phone);\n userMapper.updateById(sysUser);\n \n return R.ok(\"绑定成功\", PhoneBindVo.of(phone));\n } catch (WxErrorException e) {\n return R.fail(\"获取手机号出错\");\n }\n}\n```\n\n## 数据字典服务\n\n### 支付方式字典\n```java\n@GetMapping(\"getPaymentDict\")\npublic R<List<DictItemVo>> getPaymentDict() {\n // 查询所有可用的支付方式\n List<PaymentVo> paymentVoList = paymentService.list(\n PlusLambdaQuery.of(Payment.class)\n .eq(Payment::getStatus, DictEnableStatus.ENABLE.getValue()));\n \n // 构建字典项列表\n List<DictItemVo> dictItems = StreamUtils.toList(paymentVoList, payment ->\n DictItemVo.of(payment.getMchName(), payment.getId().toString(), \"success\")\n );\n return R.ok(dictItems);\n}\n```\n\n## 配置管理\n\n### 平台配置热更新\n```java\nprivate void reloadPlatformConfig() {\n String tenantId = TenantHelper.getTenantId();\n \n // 重新初始化微信小程序配置\n SpringUtils.getBean(WxMaApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化微信公众号配置 \n SpringUtils.getBean(WxMpApplicationRunner.class).initByTenant(tenantId);\n \n // 重新初始化支付配置\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n### 支付配置热更新\n```java\nprivate void reloadPaymentConfig() {\n String tenantId = TenantHelper.getTenantId();\n SpringUtils.getBean(PayApplicationRunner.class).initByTenant(tenantId);\n}\n```\n\n## 使用示例\n\n### 配置微信小程序\n```java\n// 1. 创建平台配置\nPlatformBo platformBo = new PlatformBo();\nplatformBo.setType(\"mp-weixin\");\nplatformBo.setName(\"我的小程序\");\nplatformBo.setAppid(\"wx1234567890\");\nplatformBo.setSecret(\"your-secret\");\nplatformBo.setStatus(\"1\");\nplatformService.add(platformBo);\n\n// 2. 配置支付信息\nPaymentBo paymentBo = new PaymentBo();\npaymentBo.setType(\"wechat\");\npaymentBo.setMchName(\"我的商户\");\npaymentBo.setMchId(\"1234567890\");\npaymentBo.setMchKey(\"your-mch-key\");\npaymentBo.setStatus(\"1\");\npaymentService.add(paymentBo);\n```\n\n### 用户登录认证\n```java\n// 前端调用登录接口\nPOST /auth/login\n{\n \"platform\": \"miniapp\",\n \"body\": {\n \"platform\": \"mp-weixin\",\n \"appid\": \"wx1234567890\",\n \"platformCode\": \"授权码\"\n }\n}\n\n// 返回结果\n{\n \"code\": 200,\n \"msg\": \"登录成功\",\n \"data\": {\n \"accessToken\": \"eyJ0eXAiOiJKV1Q...\",\n \"expireIn\": 7200\n }\n}\n```\n\n## 最佳实践\n\n### 📋 配置管理\n- 敏感信息(如密钥)加密存储\n- 支持配置热更新,无需重启服务\n- 按租户隔离配置,避免数据混淆\n\n### 🔐 安全考虑\n- 登录令牌设置合理的过期时间\n- 敏感API添加权限校验\n- 支付配置访问权限严格控制\n\n### 🚀 性能优化\n- 平台配置缓存,减少数据库查询\n- 异步处理配置更新,提升响应速度\n- 合理使用数据库索引\n\n### 🔧 扩展建议\n- 新增平台时,实现对应的认证策略\n- 支付方式扩展遵循统一接口规范\n- 配置项变更通过事件机制通知相关服务\n"}}}}