diff --git a/Dockerfile b/Dockerfile index 037d30c..d8c29c2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,6 +42,14 @@ ENV KAFKA_VERSION=2.4.0 ENV KAFKA_USERNAME=kafka-external ENV KAFKA_PASSWORD=gr58tNnlZOVGW3AmMbL2 ENV KAFKA_SASL_MECHANISM=SCRAM-SHA-512 +ENV IM_ADMIN_API_BASE_URL=http://im-server:6060 +ENV IM_ADMIN_API_SERVICE_ID=hotgo-admin +ENV IM_ADMIN_API_SECRET=8569f5626a54950539eece9f731c9e3bf073daa74af8d23735d19afacac40f4b +ENV IM_INTERNAL_API_BASE_URL=http://im-server:6060 +ENV IM_INTERNAL_API_SERVICE_NAME=hotgo-admin +ENV IM_INTERNAL_API_SECRET=8569f5626a54950539eece9f731c9e3bf073daa74af8d23735d19afacac40f4b +ENV IM_CONFIG_API_SERVICE_NAME=im-server +ENV IM_CONFIG_API_SECRET=b96832c04dbfb6dd768930ec9f082ecd90d87a1ffdaa493aa070617c48de9097 COPY --from=server-build /src/manifest ./manifest COPY --from=server-build /src/hack ./hack diff --git a/docs/backstage/IM-后台菜单覆盖测试文档.md b/docs/backstage/IM-后台菜单覆盖测试文档.md new file mode 100644 index 0000000..6b5f475 --- /dev/null +++ b/docs/backstage/IM-后台菜单覆盖测试文档.md @@ -0,0 +1,418 @@ +# IM 后台菜单覆盖测试文档 + +## 1. 测试范围 + +本文档用于覆盖 IM 后台菜单从「组织架构」开始,沿左侧菜单向下逐个页面点击验证。 + +当前覆盖菜单顺序: + +1. 组织架构 +2. 文件治理 +3. 注册邀请码 +4. 文件策略 +5. 通知模板 +6. 工作台配置 +7. 外部服务配置 +8. 版本更新 +9. 举报原因 +10. 总经理信箱配置 +11. 意见反馈配置 +12. 任务看板 +13. Kafka 命令 +14. Kafka 死信 +15. Kafka 审计事件 + +## 2. 测试环境 + +| 项目 | 地址 | +| --- | --- | +| 前端 | `http://127.0.0.1:8001/` | +| 后端 | `http://127.0.0.1:8000/admin` | +| 登录账号 | 使用具备 IM 管理权限的后台账号 | +| 浏览器 | Chrome,打开 DevTools Network 和 Console | + +## 3. 通用检查项 + +每进入一个菜单页面,都先执行以下检查: + +| 编号 | 检查项 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| COMMON-001 | 点击左侧菜单 | URL、页签、面包屑、页面标题正确变化 | 待测 | +| COMMON-002 | 页面首次加载 | 无白屏,无永久 loading,无明显样式错乱 | 待测 | +| COMMON-003 | Console | 无新的 JS Error,例如组件方法不存在、字典方法不存在 | 待测 | +| COMMON-004 | Network | 页面主列表接口 HTTP 200,业务响应 `code=0` | 待测 | +| COMMON-005 | 查询按钮 | 点击后列表刷新,请求参数包含搜索表单值 | 待测 | +| COMMON-006 | 重置按钮 | 搜索条件清空,列表回到默认查询 | 待测 | +| COMMON-007 | 展开/收起 | 搜索区域展开、收起正常,不遮挡表格 | 待测 | +| COMMON-008 | 表格刷新图标 | 点击后重新请求列表接口 | 待测 | +| COMMON-009 | 表格密度/列设置 | 可打开设置,切换后表格仍正常显示 | 待测 | +| COMMON-010 | 分页 | 切换页码和每页数量,请求参数正确,页面不报错 | 待测 | + +说明:涉及删除、撤销、重放、清理等副作用操作时,优先使用测试数据。没有测试数据时,至少验证弹窗、参数校验、取消流程;正式执行前确认不会影响线上有效数据。 + +## 4. 组织架构 + +菜单路径:`IM管理 / 组织架构` + +主要区域:部门列表、成员列表。 + +### 4.1 搜索与列表 + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| ORG-001 | 打开「组织架构」 | 页面标题显示「组织架构」,部门列表和成员列表正常渲染 | 待测 | +| ORG-002 | 选择租户后查询部门 | 部门列表请求成功,显示部门 ID、部门名称、状态、成员数等字段 | 待测 | +| ORG-003 | 输入部门名称、状态后点击查询 | 部门列表按条件刷新 | 待测 | +| ORG-004 | 输入成员关键词、在职状态后点击查询 | 成员列表按条件刷新 | 待测 | +| ORG-005 | 点击部门行「成员」 | 成员列表切换到当前部门范围,添加成员按钮可用 | 待测 | + +### 4.2 部门按钮 + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| ORG-010 | 点击「新增部门」 | 打开部门编辑弹窗 | 待测 | +| ORG-011 | 新增部门弹窗点击「取消」 | 弹窗关闭,列表不刷新或数据不变化 | 待测 | +| ORG-012 | 新增部门弹窗直接点击「保存」 | 必填项校验正常展示 | 待测 | +| ORG-013 | 填写部门名称、上级部门、排序、状态后点击「保存」 | 保存成功,部门列表刷新,新部门出现 | 待测 | +| ORG-014 | 点击部门行「编辑」 | 打开编辑弹窗,已有数据正确回填 | 待测 | +| ORG-015 | 修改部门信息后点击「保存」 | 保存成功,列表展示新值 | 待测 | +| ORG-016 | 点击部门行「删除」再点取消 | 弹窗关闭,部门不删除 | 待测 | +| ORG-017 | 点击部门行「删除」并确认 | 删除成功,列表刷新;有子部门或成员时应给出清晰错误 | 待测 | +| ORG-018 | 点击「导出部门」 | 触发文件下载,导出条件与当前查询一致 | 待测 | + +### 4.3 成员按钮 + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| ORG-020 | 未选择部门时观察「添加成员」 | 按钮禁用或提示先选择部门 | 待测 | +| ORG-021 | 选择部门后点击「添加成员」 | 打开成员编辑弹窗,部门信息默认带入 | 待测 | +| ORG-022 | 成员弹窗直接点击「保存」 | 必填项校验正常展示 | 待测 | +| ORG-023 | 填写用户 ID、岗位、排序、可联系等信息后保存 | 保存成功,成员列表刷新 | 待测 | +| ORG-024 | 点击成员行「编辑」 | 打开编辑弹窗,成员信息正确回填 | 待测 | +| ORG-025 | 修改成员信息后保存 | 保存成功,列表展示新值 | 待测 | +| ORG-026 | 点击成员行「移除」再取消 | 弹窗关闭,成员仍保留 | 待测 | +| ORG-027 | 点击成员行「移除」并确认 | 移除成功,成员列表刷新 | 待测 | +| ORG-028 | 点击「导出成员」 | 触发文件下载,导出条件与当前查询一致 | 待测 | + +## 5. 文件治理 + +菜单路径:`IM管理 / 文件治理` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| FILE-001 | 打开页面 | 文件列表正常展示,包含文件 ID、状态、用途、上传用户、MIME、大小、引用数等字段 | 待测 | +| FILE-002 | 按租户、文件 ID、上传用户、状态、用途、MIME、Topic、更新时间查询 | 列表按条件刷新 | 待测 | +| FILE-003 | 点击行操作「详情」 | 打开详情弹窗,展示文件基础信息和引用列表 | 待测 | +| FILE-004 | 详情弹窗关闭 | 弹窗正常关闭,列表状态不丢失 | 待测 | +| FILE-005 | 点击行操作「隔离」再取消 | 确认框正常,取消后文件状态不变 | 待测 | +| FILE-006 | 点击行操作「隔离」并确认 | 文件状态变为隔离或列表刷新后状态正确 | 待测 | +| FILE-007 | 点击行操作「删除」再取消 | 确认框正常,取消后文件不删除 | 待测 | +| FILE-008 | 点击行操作「删除」并确认 | 删除成功,列表刷新 | 待测 | +| FILE-009 | 点击「清理孤儿文件」再取消 | 确认框正常,取消后不触发清理 | 待测 | +| FILE-010 | 点击「清理孤儿文件」并确认 | 清理请求成功,页面给出成功或结果提示 | 待测 | + +## 6. 注册邀请码 + +菜单路径:`IM管理 / 注册邀请码` + +实际菜单路由:`/#/im/registrationInvite` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| INVITE-001 | 打开页面 | 邀请码列表正常展示,包含租户、邀请码、状态、批次 ID、到期时间、使用次数等字段 | 待测 | +| INVITE-002 | 平台管理员不选择租户点击「添加」 | 提示先选择租户 | 待测 | +| INVITE-003 | 选择租户后点击「添加」 | 打开生成邀请码弹窗 | 待测 | +| INVITE-004 | 生成弹窗点击「取消」 | 弹窗关闭,列表不变化 | 待测 | +| INVITE-005 | 生成弹窗清空到期时间后点击「确认」 | 表单校验提示请选择到期时间 | 待测 | +| INVITE-006 | 填写到期时间、备注后点击「确认」 | 生成成功,列表刷新并出现新邀请码 | 待测 | +| INVITE-007 | 点击「批量生成」 | 打开批量生成弹窗,包含生成数量、到期时间、备注 | 待测 | +| INVITE-008 | 批量生成数量小于 1 或大于 1000 | 表单校验拦截 | 待测 | +| INVITE-009 | 输入合法数量后确认 | 批量生成成功,列表出现同一批次的邀请码 | 待测 | +| INVITE-010 | 按邀请码、状态、批次 ID、创建人、创建时间、到期时间查询 | 列表按条件刷新 | 待测 | +| INVITE-011 | 点击行操作「批次」 | 打开批次详情弹窗,展示总数、有效、撤销、过期、使用次数和明细 | 待测 | +| INVITE-012 | 点击有效邀请码行操作「撤销」再取消 | 确认框正常,取消后状态不变 | 待测 | +| INVITE-013 | 点击有效邀请码行操作「撤销」并确认 | 撤销成功,状态变为已撤销 | 待测 | +| INVITE-014 | 点击有效批次行操作「撤销批次」再取消 | 确认框正常,取消后批次状态不变 | 待测 | +| INVITE-015 | 点击有效批次行操作「撤销批次」并确认 | 批次内有效邀请码变为已撤销 | 待测 | +| INVITE-016 | 点击「导出」 | 下载 CSV 文件,内容与当前筛选条件一致 | 待测 | + +## 7. 文件策略 + +菜单路径:`IM管理 / 文件策略` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| FILE-POLICY-001 | 打开页面 | 策略列表正常展示,包含用途、大小上限、保留天数、自动清理、病毒扫描、MIME 白名单等字段 | 待测 | +| FILE-POLICY-002 | 按租户、用途、自动清理、病毒扫描查询 | 列表按条件刷新 | 待测 | +| FILE-POLICY-003 | 点击行操作「编辑」 | 打开编辑弹窗,字段正确回填 | 待测 | +| FILE-POLICY-004 | 编辑弹窗点击「取消」 | 弹窗关闭,数据不变化 | 待测 | +| FILE-POLICY-005 | 修改大小上限、保留天数、开关、MIME 白名单后保存 | 保存成功,列表刷新并展示新值 | 待测 | +| FILE-POLICY-006 | 输入非法大小或保留天数后保存 | 表单校验或后端错误提示清晰 | 待测 | + +## 8. 通知模板 + +菜单路径:`IM管理 / 通知模板` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| NOTIFY-001 | 打开页面 | 模板列表正常展示,包含场景、状态、站内、Push、短信、标题模板、内容模板等字段 | 待测 | +| NOTIFY-002 | 按租户、场景、状态查询 | 列表按条件刷新 | 待测 | +| NOTIFY-003 | 点击行操作「编辑」 | 打开编辑弹窗,模板字段正确回填 | 待测 | +| NOTIFY-004 | 编辑弹窗点击「取消」 | 弹窗关闭,数据不变化 | 待测 | +| NOTIFY-005 | 修改标题模板、内容模板、站内/Push/短信开关后保存 | 保存成功,列表刷新并展示新值 | 待测 | +| NOTIFY-006 | 清空必填字段后保存 | 表单校验或后端错误提示清晰 | 待测 | + +## 9. 工作台配置 + +菜单路径:`IM管理 / 工作台配置` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| WORKBENCH-001 | 打开页面 | 工作台模块列表正常展示,包含编码、名称、路由、排序、图标 ID、角标 Key、状态、权限等字段 | 待测 | +| WORKBENCH-002 | 按租户、编码、名称、状态查询 | 列表按条件刷新 | 待测 | +| WORKBENCH-003 | 点击「新增模块」 | 打开模块编辑弹窗 | 待测 | +| WORKBENCH-004 | 新增弹窗点击「取消」 | 弹窗关闭,列表不变化 | 待测 | +| WORKBENCH-005 | 新增弹窗直接保存 | 必填项校验正常展示 | 待测 | +| WORKBENCH-006 | 填写编码、名称、路由、排序、状态等信息后保存 | 保存成功,列表刷新 | 待测 | +| WORKBENCH-007 | 点击行操作「编辑」 | 打开编辑弹窗,字段正确回填 | 待测 | +| WORKBENCH-008 | 修改模块信息后保存 | 保存成功,列表展示新值 | 待测 | +| WORKBENCH-009 | 点击行操作「禁用」再取消 | 确认框正常,取消后状态不变 | 待测 | +| WORKBENCH-010 | 点击行操作「禁用」并确认 | 禁用成功,列表刷新后状态正确 | 待测 | +| WORKBENCH-011 | 点击「保存排序」 | 排序保存成功;列表刷新后顺序保持一致 | 待测 | + +## 10. 外部服务配置 + +菜单路径:`IM管理 / 外部服务配置` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| EXT-CONFIG-001 | 打开页面 | 配置列表正常展示,包含服务、服务商、端点、启用、配置状态、敏感配置、检查结果等字段 | 待测 | +| EXT-CONFIG-002 | 按租户、服务、服务商、启用状态查询 | 列表按条件刷新 | 待测 | +| EXT-CONFIG-003 | 点击行操作「编辑」 | 打开编辑弹窗,字段正确回填 | 待测 | +| EXT-CONFIG-004 | 编辑弹窗切换「启用」开关 | 开关状态可变更,保存前不应提前提交 | 待测 | +| EXT-CONFIG-005 | 修改服务商、端点、配置内容后保存 | 保存成功,列表刷新并展示新值 | 待测 | +| EXT-CONFIG-006 | 点击行操作「检查」再取消 | 确认框正常,取消后不触发检查 | 待测 | +| EXT-CONFIG-007 | 点击行操作「检查」并确认 | 检查请求成功,检查结果和检查时间刷新 | 待测 | + +## 11. 版本更新 + +菜单路径:`IM管理 / 版本更新` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| RELEASE-001 | 打开页面 | 版本策略列表正常展示,包含平台、渠道、最新版本、最低支持、更新类型、下载地址等字段 | 待测 | +| RELEASE-002 | 按租户、平台、渠道查询 | 列表按条件刷新 | 待测 | +| RELEASE-003 | 点击「新增策略」 | 打开策略编辑弹窗 | 待测 | +| RELEASE-004 | 新增弹窗直接保存 | 必填项校验正常展示 | 待测 | +| RELEASE-005 | 填写平台、渠道、版本号、更新类型、地址、发布时间后保存 | 保存成功,列表刷新 | 待测 | +| RELEASE-006 | 点击行操作「编辑」 | 打开编辑弹窗,字段正确回填 | 待测 | +| RELEASE-007 | 修改版本策略后保存 | 保存成功,列表展示新值 | 待测 | +| RELEASE-008 | 输入非法版本号或 URL 后保存 | 表单校验或后端错误提示清晰 | 待测 | + +## 12. 举报原因 + +菜单路径:`IM管理 / 举报原因` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| ABUSE-001 | 打开页面 | 原因列表正常展示,包含对象、编码、文案、要求描述、允许证据、排序、状态等字段 | 待测 | +| ABUSE-002 | 按租户、对象、编码、状态查询 | 列表按条件刷新 | 待测 | +| ABUSE-003 | 点击「新增原因」 | 打开原因编辑弹窗 | 待测 | +| ABUSE-004 | 新增弹窗直接保存 | 必填项校验正常展示 | 待测 | +| ABUSE-005 | 填写对象、编码、文案、排序、状态等信息后保存 | 保存成功,列表刷新 | 待测 | +| ABUSE-006 | 点击行操作「编辑」 | 打开编辑弹窗,字段正确回填 | 待测 | +| ABUSE-007 | 修改原因配置后保存 | 保存成功,列表展示新值 | 待测 | +| ABUSE-008 | 点击行操作「禁用」再取消 | 确认框正常,取消后状态不变 | 待测 | +| ABUSE-009 | 点击行操作「禁用」并确认 | 禁用成功,列表刷新后状态正确 | 待测 | + +## 13. 总经理信箱配置 + +菜单路径:`IM管理 / 总经理信箱配置` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| MAILBOX-001 | 打开页面 | 配置表单正常展示,租户选择框可用 | 待测 | +| MAILBOX-002 | 选择租户 | 自动加载该租户信箱配置 | 待测 | +| MAILBOX-003 | 点击「刷新」 | 当前租户配置重新加载,表单无异常 | 待测 | +| MAILBOX-004 | 未选择租户时观察「保存」 | 按钮禁用或提示先选择租户 | 待测 | +| MAILBOX-005 | 修改启用状态、接收人、处理策略等配置后点击「保存」 | 保存成功,再次刷新后配置保持一致 | 待测 | +| MAILBOX-006 | 输入非法配置后保存 | 表单校验或后端错误提示清晰 | 待测 | + +## 14. 意见反馈配置 + +菜单路径:`IM管理 / 意见反馈配置` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| FEEDBACK-001 | 打开页面 | 配置表单正常展示,租户选择框可用 | 待测 | +| FEEDBACK-002 | 选择租户 | 自动加载该租户反馈配置 | 待测 | +| FEEDBACK-003 | 点击「刷新」 | 当前租户配置重新加载,表单无异常 | 待测 | +| FEEDBACK-004 | 未选择租户时观察「保存」 | 按钮禁用或提示先选择租户 | 待测 | +| FEEDBACK-005 | 修改启用状态、分类、处理人、限制策略等配置后点击「保存」 | 保存成功,再次刷新后配置保持一致 | 待测 | +| FEEDBACK-006 | 输入非法配置后保存 | 表单校验或后端错误提示清晰 | 待测 | + +## 15. 任务看板 + +菜单路径:`IM管理 / 任务看板` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| TASK-001 | 打开页面 | 看板列表正常展示,包含租户、企业码、状态、DB、业务待投递、业务失败、群待投递、群失败、孤儿文件、待物理清理等字段 | 待测 | +| TASK-002 | 按租户、状态查询 | 列表按条件刷新 | 待测 | +| TASK-003 | 查看建议动作字段 | 异常租户展示可理解的建议动作;正常租户展示正常或为空 | 待测 | +| TASK-004 | 刷新表格 | 统计数据重新加载,无接口报错 | 待测 | + +## 16. Kafka 命令 + +菜单路径:`IM管理 / Kafka命令` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| KAFKA-CMD-001 | 打开页面 | 命令列表正常展示,包含租户、命令 ID、事件类型、业务类型、业务 ID、状态、错误码、消息等字段 | 待测 | +| KAFKA-CMD-002 | 按租户、命令 ID、事件 ID、事件类型、业务 ID、状态、创建时间查询 | 列表按条件刷新 | 待测 | +| KAFKA-CMD-003 | 点击「发送缓存失效测试」 | 请求成功,新增一条缓存失效命令或页面提示成功 | 待测 | +| KAFKA-CMD-004 | 点击「发送工作台测试事件」 | 请求成功,新增一条工作台测试事件命令或页面提示成功 | 待测 | +| KAFKA-CMD-005 | 点击行操作「详情」 | 打开详情弹窗,展示命令 payload、结果、错误原因等信息 | 待测 | +| KAFKA-CMD-006 | 详情弹窗点击「关闭」 | 弹窗正常关闭 | 待测 | +| KAFKA-CMD-007 | 发送测试事件后等待消费结果 | 状态从待发送/已发送变为成功或失败,失败时错误信息可读 | 待测 | + +## 17. Kafka 死信 + +菜单路径:`IM管理 / Kafka死信` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| DEAD-001 | 打开页面 | 死信列表正常展示,包含死信 ID、事件 ID、来源 Topic、消费组、事件类型、业务类型、业务 ID、状态等字段 | 待测 | +| DEAD-002 | 按租户、状态、事件类型、业务类型、业务 ID 查询 | 列表按条件刷新 | 待测 | +| DEAD-003 | 点击行操作「详情」 | 打开详情弹窗,展示死信 payload、错误原因、处理信息 | 待测 | +| DEAD-004 | 详情弹窗点击「关闭」 | 弹窗正常关闭 | 待测 | +| DEAD-005 | 详情弹窗点击「忽略」 | 操作成功,状态变为已忽略或列表刷新后状态正确 | 待测 | +| DEAD-006 | 详情弹窗点击「标记已处理」 | 操作成功,状态变为已处理 | 待测 | +| DEAD-007 | 详情弹窗点击「重放」 | 操作成功,重放次数增加,状态或处理结果正确更新 | 待测 | +| DEAD-008 | 对已处理、已忽略死信重复操作 | 系统应拦截或给出清晰提示,不出现脏状态 | 待测 | + +## 18. Kafka 审计事件 + +菜单路径:`IM管理 / Kafka审计事件` + +| 编号 | 操作 | 预期结果 | 结果 | +| --- | --- | --- | --- | +| KAFKA-AUDIT-001 | 打开页面 | 审计事件列表正常展示,包含租户、事件 ID、事件类型、动作、资源、资源 ID、操作者、结果等字段 | 待测 | +| KAFKA-AUDIT-002 | 按租户编码、事件 ID、事件类型、动作、资源、资源 ID、结果、接收时间查询 | 列表按条件刷新 | 待测 | +| KAFKA-AUDIT-003 | 点击行操作「详情」 | 打开详情弹窗,展示事件详情、请求上下文、结果信息 | 待测 | +| KAFKA-AUDIT-004 | 详情弹窗点击「关闭」 | 弹窗正常关闭 | 待测 | + +## 19. 测试数据建议 + +| 数据类型 | 建议准备 | +| --- | --- | +| 租户 | 至少 1 个正常租户,具备独立业务库 | +| 组织架构 | 至少 1 个根部门、1 个子部门、2 个用户成员 | +| 文件治理 | 至少 1 个正常文件、1 个可隔离文件、1 个孤儿文件 | +| 注册邀请码 | 至少 1 个有效邀请码、1 个过期邀请码、1 个批次邀请码 | +| Kafka | Kafka、消费者、IM Server 正常运行;准备 1 条可产生成功结果的命令和 1 条可产生死信的命令 | +| 配置类 | 文件策略、通知模板、工作台、外部服务、版本更新、举报原因均有初始数据 | + +## 20. 缺陷记录模板 + +| 缺陷编号 | 菜单 | 操作步骤 | 实际结果 | 预期结果 | Console/Network 信息 | 严重级别 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | --- | +| BUG-001 | | | | | | | 待处理 | + +## 21. 第一轮执行记录 + +执行时间:2026-09-03 15:16 - 15:22 + +执行环境: + +| 项目 | 值 | +| --- | --- | +| 前端 | `http://127.0.0.1:8001/` | +| 后端 | Docker 容器 `im-local-admin`,端口 `8000` | +| MySQL | Docker 容器 `relaxed_cori`,库 `hotgo`、`tinode`、`tinode_test` | +| Redis | Docker 容器 `brave_blackburn` | +| Kafka | Docker 容器 `kafka` | + +本轮说明: + +1. 从左侧菜单「组织架构」开始,按菜单顺序逐页点击。 +2. 对查询、重置、展开、刷新、新增、编辑、详情等非破坏性按钮进行了点击验证。 +3. 对删除、隔离、撤销、禁用、重放等有副作用的按钮,本轮只验证入口和取消流程,不确认执行。 +4. 「收起」按钮在自动化脚本里先于「展开」检测,产生过误报,本轮不作为缺陷记录。 +5. 「注册邀请码」菜单点击正常,真实路由为 `/#/im/registrationInvite`;直接访问 `/#/im/registrationInvite/index` 会进入 ErrorPage,测试文档已修正。 + +### 21.1 页面通过项 + +| 菜单 | 本轮结果 | +| --- | --- | +| 组织架构 | 页面可打开,查询/重置/展开/新增部门可点击;添加成员因未先选择部门处于禁用,符合预期 | +| 文件治理 | 页面可打开,查询/重置/展开/详情可点击;列表有数据 | +| 注册邀请码 | 通过左侧菜单可打开,查询/重置/展开/添加/批量生成/导出可见;列表有 2 条历史数据 | +| 工作台配置 | 页面可打开,查询/重置/展开/新增模块/编辑可点击;禁用弹窗可打开并取消 | +| 版本更新 | 页面可打开,查询/重置/展开/新增策略/编辑可点击;列表有数据 | +| 举报原因 | 页面可打开,查询/重置/展开/新增原因/编辑可点击;禁用弹窗可打开并取消 | +| 总经理信箱配置 | 页面可打开,保存/刷新按钮可见,刷新可点击 | +| 意见反馈配置 | 页面可打开,保存/刷新按钮可见,刷新可点击 | +| 任务看板 | 页面可打开,查询/重置/展开可点击 | + +### 21.2 本轮发现的问题 + +| 缺陷编号 | 菜单 | 操作步骤 | 实际结果 | 预期结果 | 证据 | 严重级别 | 状态 | +| --- | --- | --- | --- | --- | --- | --- | --- | +| BUG-IM-001 | 文件策略 | 点击「IM管理 / 文件策略」,或点击查询/重置 | 页面 Console 报 `检查IM文件策略失败`,列表无法加载,行操作「编辑」不可测 | 文件策略列表应正常加载,缺省策略应自动初始化 | 后端日志:`SELECT COUNT(1) FROM im_file_policy ... Error 1146: Table 'hotgo.im_file_policy' doesn't exist`;代码位置:`server/internal/logic/sys/im_file_policy.go:128` | P0 | 待处理 | +| BUG-IM-002 | 通知模板 | 点击「IM管理 / 通知模板」,或点击查询/重置 | 页面 Console 报 `检查IM通知模板失败,请稍后重试!`,列表无法加载,行操作「编辑」不可测 | 通知模板列表应正常加载,缺省模板应自动初始化 | 后端日志:`SELECT COUNT(1) FROM im_notification_template ... Error 1146: Table 'hotgo.im_notification_template' doesn't exist`;代码位置:`server/internal/logic/sys/im_notification.go:123` | P0 | 待处理 | +| BUG-IM-003 | 外部服务配置 | 点击「IM管理 / 外部服务配置」,或点击查询/重置 | 页面 Console 报 `初始化IM外部服务配置失败`,列表无法加载,行操作「编辑」「检查」不可测 | 外部服务配置列表应正常加载,缺省服务配置应自动初始化 | 后端日志:`SELECT COUNT(1) FROM im_external_config ... Error 1146: Table 'hotgo.im_external_config' doesn't exist`;代码位置:`server/internal/logic/sys/im_external_config.go:194` | P0 | 待处理 | +| BUG-IM-004 | Kafka命令 | 点击「IM管理 / Kafka命令」后点击「发送缓存失效测试」 | 页面 toast 显示 `读取IM命令Outbox失败`,Kafka 命令列表仍为 0 条 | 应写入 Outbox 并投递 Kafka,页面能看到新事件或明确状态 | 后端日志:`读取IM命令Outbox失败: element of parameter "pointer" for function Scan should type of struct/*struct/[]struct/[]*struct`;代码位置:`server/internal/library/imkafka/command.go:103` | P0 | 待处理 | +| BUG-IM-005 | Kafka命令 | 点击「发送缓存失效测试」「发送工作台测试事件」后查看数据库 | 正确表 `hotgo.im_admin_outbox` 为 0 条;带前缀表 `hotgo.hg_im_admin_outbox` 新增 3 条 pending 记录 | Admin 新增 IM 表和代码查询应统一使用无前缀 `im_*` 表,避免 `hg_im_*` 和 `im_*` 双表分裂 | MySQL:`SHOW TABLES LIKE 'hg_im_%'` 可见 `hg_im_admin_outbox`、`hg_im_admin_commands`、`hg_im_audit_events`;`hg_im_admin_outbox` 有 pending 数据,`im_admin_outbox` 为空 | P0 | 待处理 | +| BUG-IM-006 | Kafka死信 | 点击「IM管理 / Kafka死信」 | 页面可打开,但列表无数据,行操作「详情」「忽略」「标记已处理」「重放」无法覆盖 | 联调测试库应准备至少 1 条死信数据,才能覆盖处置按钮 | MySQL:`hotgo.im_kafka_dead_letter_events` 计数为 0 | P1 | 待补测试数据 | +| BUG-IM-007 | Kafka审计事件 | 点击「IM管理 / Kafka审计事件」 | 页面可打开,但列表无数据,行操作「详情」无法覆盖 | 联调测试库应准备至少 1 条审计事件数据,才能覆盖详情按钮 | MySQL:`hotgo.im_audit_events` 计数为 0 | P1 | 待补测试数据 | + +### 21.3 数据库核查结果 + +| 库 | 表 | 结果 | +| --- | --- | --- | +| `hotgo` | `im_file_policy` | 不存在 | +| `hotgo` | `im_notification_template` | 不存在 | +| `hotgo` | `im_external_config` | 不存在 | +| `hotgo` | `im_admin_commands` | 存在,0 条 | +| `hotgo` | `im_admin_outbox` | 存在,0 条 | +| `hotgo` | `hg_im_admin_outbox` | 存在,3 条 pending | +| `hotgo` | `im_kafka_dead_letter_events` | 存在,0 条 | +| `hotgo` | `im_audit_events` | 存在,0 条 | + +### 21.4 下一步建议 + +1. 先导入缺失表 SQL:`server/storage/data/generate/im_file_policy_menu.sql`、`server/storage/data/generate/im_notification_menu.sql`、`server/storage/data/generate/im_external_config_menu.sql`。 +2. 修复 Kafka Outbox 表名前缀分裂问题,确保所有 Kafka Admin 表统一访问 `im_*`,不要落到 `hg_im_*`。 +3. 修复 `DispatchOutboxByEvent` 中 `g.DB().GetOne` 触发的 `Scan` 参数类型错误。 +4. 准备 Kafka 死信和 Kafka 审计事件测试数据后,重新覆盖「详情」「忽略」「标记已处理」「重放」等按钮。 +5. 上述 P0 处理后,重新执行本测试文档第 4 到第 18 章。 + +## 22. 第二轮修复记录 + +执行时间:2026-09-03 15:37 - 15:50 + +### 22.1 已处理项 + +| 缺陷编号 | 处理结果 | 复测结果 | +| --- | --- | --- | +| BUG-IM-001 | 已补齐 `hotgo.im_file_policy` 表;访问文件策略列表时可自动初始化默认策略 | `/admin/imFilePolicy/list?tenantId=1` 返回 `code=0`,列表 6 条 | +| BUG-IM-002 | 已补齐 `hotgo.im_notification_template` 表;访问通知模板列表时可自动初始化默认模板 | `/admin/imNotification/templateList` 返回 `code=0`,列表 7 条 | +| BUG-IM-003 | 已补齐 `hotgo.im_external_config` 表;访问外部服务配置列表时可自动初始化默认配置 | `/admin/imExternalConfig/list?tenantId=1` 返回 `code=0`,列表 5 条 | +| BUG-IM-004 | 已修复 Kafka Admin 命令/Outbox 读写 DB,统一改为无前缀 `imRegistry` 连接 | 点击等价接口 `/admin/imKafkaCommand/cacheInvalidate` 返回 `code=0`,不再报 `读取IM命令Outbox失败` | +| BUG-IM-005 | 已修复 `im_admin_commands`、`im_admin_outbox`、`im_audit_events`、`im_kafka_dead_letter_events` 读写前缀分裂 | 新增 Kafka 测试事件写入 `hotgo.im_admin_outbox`,状态为 `sent`;没有继续写入 `hg_im_admin_outbox` | + +### 22.2 额外修复 + +| 问题 | 处理结果 | 复测结果 | +| --- | --- | --- | +| Docker 本地 admin 缺少运行时 MySQL/Redis 环境变量导致启动 panic | 本地容器启动时显式传入 `MYSQL_DSN`、`REDIS_ADDR`、`TOKEN_SECRET_KEY` 等变量 | `im-local-admin` 正常启动,`http://127.0.0.1:8000/admin/` 可访问 | +| admin 容器内 `im-server:6060` 解析到不可用地址,死信内部查询 EOF | `config.template`、`entrypoint.sh` 增加 IM API 环境变量;本地容器使用 `IM_INTERNAL_API_BASE_URL=http://im-local-im:6060` | `/admin/imDeadLetter/list?tenantId=1` 返回 `code=0`,列表 18 条 | +| 测试库 IM 菜单中文标题乱码 | 已在测试库用 UTF-8 连接修复 `hg_admin_menu.title`;新增 `im_menu_title_repair.sql` 可重复修复 | `imManager`、`imOrgIndex`、`imFilePolicyIndex`、`imKafkaCommandIndex` 等标题查询显示正常中文 | +| 部分新增菜单 SQL 使用旧版 `hg_admin_menu` 字段 `route/is_cache/created_by/updated_by` | 已转换相关 `*_menu.sql` 菜单插入字段为当前 HotGo 表结构 | 相关 SQL 在本地 `hotgo` 库重复执行通过,无 `Unknown column 'route'` | + +### 22.3 当前剩余注意项 + +1. 当前浏览器页签仍保存旧 token,页面上可能继续弹「登录身份已失效」;刷新并重新登录后再继续 UI 点击测试。 +2. `hg_im_admin_outbox` 里还保留第一轮测试误写入的 3 条旧数据,仅用于证明旧问题,不影响新链路;后续可按运维需要清理。 +3. Kafka 审计事件列表当前仍无数据,需要 IM Server 产生或导入审计事件后才能覆盖详情弹窗。 diff --git a/server/internal/library/imkafka/command.go b/server/internal/library/imkafka/command.go index 2cfcf85..5b81861 100644 --- a/server/internal/library/imkafka/command.go +++ b/server/internal/library/imkafka/command.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "hotgo/internal/consts" + "hotgo/internal/library/imtenant" "hotgo/internal/library/queue" "time" @@ -60,7 +61,7 @@ func PublishAdminCommand(ctx context.Context, in AdminCommandInput) (res *AdminC return nil, gerror.Wrap(err, "序列化IM命令Envelope失败") } - db := g.DB() + db := adminDB() err = db.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { nowTime := gtime.Now() if _, err := tx.Exec(`INSERT INTO im_admin_commands @@ -101,7 +102,7 @@ func PublishAdminCommand(ctx context.Context, in AdminCommandInput) (res *AdminC } func DispatchOutboxByEvent(ctx context.Context, eventID string) error { - row, err := g.DB().GetOne(ctx, `SELECT * FROM im_admin_outbox WHERE event_id=? AND status=? LIMIT 1`, + row, err := adminDB().GetOne(ctx, `SELECT * FROM im_admin_outbox WHERE event_id=? AND status=? LIMIT 1`, eventID, consts.ImAdminOutboxStatusPending) if err != nil { return gerror.Wrap(err, "读取IM命令Outbox失败") @@ -146,7 +147,7 @@ func PublishConfigEvent(ctx context.Context, in ConfigEventInput) error { return gerror.Wrap(err, "序列化IM配置事件Envelope失败") } nowTime := gtime.Now() - _, err = g.DB().Exec(ctx, `INSERT INTO im_admin_outbox + _, err = adminDB().Exec(ctx, `INSERT INTO im_admin_outbox (event_id,command_id,topic,event_type,biz_type,biz_id,key_value,envelope,status,created_at,updated_at) VALUES(?,?,?,?,?,?,?,CAST(? AS JSON),?,?,?)`, eventID, "", consts.QueueImConfigEventTopic, in.EventType, "config", in.BizID, in.TenantCode, @@ -198,7 +199,7 @@ func PublishEvent(ctx context.Context, in EventInput) (eventID string, err error return "", gerror.Wrap(err, "序列化IM Kafka事件Envelope失败") } nowTime := gtime.Now() - _, err = g.DB().Exec(ctx, `INSERT INTO im_admin_outbox + _, err = adminDB().Exec(ctx, `INSERT INTO im_admin_outbox (event_id,command_id,topic,event_type,biz_type,biz_id,key_value,envelope,status,created_at,updated_at) VALUES(?,?,?,?,?,?,?,CAST(? AS JSON),?,?,?)`, eventID, "", in.Topic, in.EventType, in.BizType, in.BizID, in.BizID, @@ -216,7 +217,7 @@ func DispatchPendingOutbox(ctx context.Context, limit int) (sent int, err error) if limit <= 0 { limit = 100 } - rows, err := g.DB().GetAll(ctx, `SELECT * FROM im_admin_outbox + rows, err := adminDB().GetAll(ctx, `SELECT * FROM im_admin_outbox WHERE status IN (?,?) AND (next_retry_at IS NULL OR next_retry_at <= NOW()) ORDER BY id ASC LIMIT ?`, consts.ImAdminOutboxStatusPending, consts.ImAdminOutboxStatusFailed, limit) if err != nil { @@ -250,14 +251,14 @@ func dispatchOutboxRecord(ctx context.Context, row gdb.Record) error { return err } now := gtime.Now() - _, err := g.DB().Exec(ctx, `UPDATE im_admin_outbox + _, err := adminDB().Exec(ctx, `UPDATE im_admin_outbox SET status=?,attempts=attempts+1,sent_at=?,last_reason='',last_error='',updated_at=? WHERE event_id=?`, consts.ImAdminOutboxStatusSent, now, now, eventID) if err != nil { return gerror.Wrap(err, "更新IM命令Outbox投递状态失败") } if commandID != "" { - _, err = g.DB().Exec(ctx, `UPDATE im_admin_commands + _, err = adminDB().Exec(ctx, `UPDATE im_admin_commands SET status=?,sent_at=?,updated_at=? WHERE command_id=?`, consts.ImAdminCommandStatusRunning, now, now, commandID) if err != nil { @@ -269,7 +270,7 @@ func dispatchOutboxRecord(ctx context.Context, row gdb.Record) error { func markOutboxFailed(ctx context.Context, eventID string, reason string, message string) error { now := gtime.Now() - _, err := g.DB().Exec(ctx, `UPDATE im_admin_outbox + _, err := adminDB().Exec(ctx, `UPDATE im_admin_outbox SET status=?,attempts=attempts+1,next_retry_at=?,last_reason=?,last_error=?,updated_at=? WHERE event_id=?`, consts.ImAdminOutboxStatusFailed, now.Add(30*time.Second), reason, message, now, eventID) if err != nil { @@ -316,9 +317,13 @@ func ApplyCommandResult(ctx context.Context, result CommandResult) error { } sql += ` WHERE ` + whereColumn + `=?` args = append(args, whereValue) - _, err := g.DB().Exec(ctx, sql, args...) + _, err := adminDB().Exec(ctx, sql, args...) if err != nil { return gerror.Wrap(err, "更新IM后台命令结果失败") } return nil } + +func adminDB() gdb.DB { + return imtenant.RegistryDB() +} diff --git a/server/internal/logic/sys/im_kafka_audit.go b/server/internal/logic/sys/im_kafka_audit.go index 1e187a8..59f7bf2 100644 --- a/server/internal/logic/sys/im_kafka_audit.go +++ b/server/internal/logic/sys/im_kafka_audit.go @@ -2,12 +2,12 @@ package sys import ( "context" + "hotgo/internal/library/imtenant" "hotgo/internal/model/input/sysin" "hotgo/internal/service" "strings" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/frame/g" ) type sSysImKafkaAudit struct{} @@ -25,7 +25,8 @@ func (s *sSysImKafkaAudit) List(ctx context.Context, in *sysin.ImKafkaAuditListI return } where, args := buildImKafkaAuditWhere(in) - totalValue, err := g.DB().GetValue(ctx, "SELECT COUNT(*) FROM im_audit_events "+where, args...) + db := imtenant.RegistryDB() + totalValue, err := db.GetValue(ctx, "SELECT COUNT(*) FROM im_audit_events "+where, args...) if err != nil { err = gerror.Wrap(err, "获取IM Kafka审计事件总数失败,请稍后重试!") return @@ -45,7 +46,7 @@ func (s *sSysImKafkaAudit) List(ctx context.Context, in *sysin.ImKafkaAuditListI action,resource,resource_id,result,reason,occurred_at,received_at FROM im_audit_events ` + where + ` ORDER BY id DESC LIMIT ? OFFSET ?` queryArgs := append(append([]any{}, args...), perPage, offset) - rows, err := g.DB().GetAll(ctx, query, queryArgs...) + rows, err := db.GetAll(ctx, query, queryArgs...) if err != nil { err = gerror.Wrap(err, "获取IM Kafka审计事件列表失败,请稍后重试!") return @@ -126,7 +127,7 @@ func (s *sSysImKafkaAudit) View(ctx context.Context, in *sysin.ImKafkaAuditViewI args = append(args, in.EventId) } query += " LIMIT 1" - row, err := g.DB().GetOne(ctx, query, args...) + row, err := imtenant.RegistryDB().GetOne(ctx, query, args...) if err != nil { return nil, gerror.Wrap(err, "获取IM Kafka审计事件详情失败,请稍后重试!") } diff --git a/server/internal/logic/sys/im_kafka_command.go b/server/internal/logic/sys/im_kafka_command.go index 85c3495..ae97609 100644 --- a/server/internal/logic/sys/im_kafka_command.go +++ b/server/internal/logic/sys/im_kafka_command.go @@ -10,12 +10,12 @@ import ( "hotgo/internal/consts" "hotgo/internal/library/contexts" "hotgo/internal/library/imkafka" + "hotgo/internal/library/imtenant" "hotgo/internal/model/input/sysin" "hotgo/internal/service" "strings" "github.com/gogf/gf/v2/errors/gerror" - "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) @@ -34,7 +34,8 @@ func (s *sSysImKafkaCommand) List(ctx context.Context, in *sysin.ImKafkaCommandL return } where, args := buildImKafkaCommandWhere(in) - totalValue, err := g.DB().GetValue(ctx, "SELECT COUNT(*) FROM im_admin_commands "+where, args...) + db := imtenant.RegistryDB() + totalValue, err := db.GetValue(ctx, "SELECT COUNT(*) FROM im_admin_commands "+where, args...) if err != nil { err = gerror.Wrap(err, "获取IM后台命令总数失败,请稍后重试!") return @@ -53,7 +54,7 @@ func (s *sSysImKafkaCommand) List(ctx context.Context, in *sysin.ImKafkaCommandL status,reason,message,sent_at,completed_at,created_by,created_at,updated_at FROM im_admin_commands ` + where + ` ORDER BY id DESC LIMIT ? OFFSET ?` queryArgs := append(append([]any{}, args...), perPage, offset) - rows, err := g.DB().GetAll(ctx, query, queryArgs...) + rows, err := db.GetAll(ctx, query, queryArgs...) if err != nil { err = gerror.Wrap(err, "获取IM后台命令列表失败,请稍后重试!") return @@ -80,7 +81,7 @@ func (s *sSysImKafkaCommand) View(ctx context.Context, in *sysin.ImKafkaCommandV args = append(args, in.CommandId) } query += " LIMIT 1" - row, err := g.DB().GetOne(ctx, query, args...) + row, err := imtenant.RegistryDB().GetOne(ctx, query, args...) if err != nil { return nil, gerror.Wrap(err, "获取IM后台命令详情失败,请稍后重试!") } diff --git a/server/internal/logic/sys/im_org.go b/server/internal/logic/sys/im_org.go index 8ceb6d4..c625f5e 100644 --- a/server/internal/logic/sys/im_org.go +++ b/server/internal/logic/sys/im_org.go @@ -9,6 +9,7 @@ import ( "hotgo/internal/service" "hotgo/utility/convert" "hotgo/utility/excel" + "net/url" "strings" "github.com/gogf/gf/v2/database/gdb" @@ -34,33 +35,28 @@ func (s *sSysImOrg) DepartmentList(ctx context.Context, in *sysin.ImOrgDepartmen if err = in.Filter(ctx); err != nil { return } - db, tenant, err := resolveImTenantDB(ctx, in.TenantId) + tenant, err := resolveImAdminTenant(ctx, in.TenantId) if err != nil { return } - mod := s.departmentModel(ctx, db) + values := addPageQuery(url.Values{}, in.Page, in.PerPage) if in.DepartmentId != "" { - mod = mod.Where("d.department_id", strings.TrimSpace(in.DepartmentId)) + values.Set("department_id", strings.TrimSpace(in.DepartmentId)) } if in.ParentId != "" { - mod = mod.Where("d.parent_id", strings.TrimSpace(in.ParentId)) + values.Set("parent_id", strings.TrimSpace(in.ParentId)) } if in.Name != "" { - mod = mod.WhereLike("d.name", "%"+strings.TrimSpace(in.Name)+"%") + values.Set("name", strings.TrimSpace(in.Name)) } if in.State != "" { - mod = mod.Where("d.state", strings.TrimSpace(in.State)) + values.Set("state", strings.TrimSpace(in.State)) } - mod = mod.Page(in.Page, in.PerPage).OrderAsc("d.sort_order").OrderAsc("d.id") - if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { - err = gerror.Wrap(err, "获取IM组织部门失败,请稍后重试!") - return - } - for _, item := range list { - item.TenantId = tenant.Id - item.TenantName = tenant.Name - } - return + return imAdminQueryList[sysin.ImOrgDepartmentModel](ctx, tenant, + "/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/org/departments", + values, + nil, + ) } func (s *sSysImOrg) DepartmentExport(ctx context.Context, in *sysin.ImOrgDepartmentListInp) (err error) { @@ -195,34 +191,28 @@ func (s *sSysImOrg) MemberList(ctx context.Context, in *sysin.ImOrgMemberListInp if err = in.Filter(ctx); err != nil { return } - db, tenant, err := resolveImTenantDB(ctx, in.TenantId) + tenant, err := resolveImAdminTenant(ctx, in.TenantId) if err != nil { return } - mod := s.memberModel(ctx, db) + values := addPageQuery(url.Values{}, in.Page, in.PerPage) if in.DepartmentId != "" { - mod = mod.Where("m.department_id", strings.TrimSpace(in.DepartmentId)) + values.Set("department_id", strings.TrimSpace(in.DepartmentId)) } if in.UserId > 0 { - mod = mod.Where("m.user_id", in.UserId) + values.Set("user_id", int64ToString(in.UserId)) } if in.EmploymentState != "" { - mod = mod.Where("m.employment_state", strings.TrimSpace(in.EmploymentState)) + values.Set("employment_state", strings.TrimSpace(in.EmploymentState)) } - if q := strings.TrimSpace(in.Query); q != "" { - like := "%" + q + "%" - mod = mod.Where("(m.display_name LIKE ? OR m.mobile LIKE ? OR m.email LIKE ? OR CAST(m.user_id AS CHAR) LIKE ?)", like, like, like, like) + if in.Query != "" { + values.Set("q", strings.TrimSpace(in.Query)) } - mod = mod.Page(in.Page, in.PerPage).OrderAsc("m.sort_order").OrderAsc("m.id") - if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { - err = gerror.Wrap(err, "获取IM组织成员失败,请稍后重试!") - return - } - for _, item := range list { - item.TenantId = tenant.Id - item.TenantName = tenant.Name - } - return + return imAdminQueryList[sysin.ImOrgMemberModel](ctx, tenant, + "/internal/admin-query/tenants/"+url.PathEscape(tenant.Code)+"/org/members", + values, + nil, + ) } func (s *sSysImOrg) MemberExport(ctx context.Context, in *sysin.ImOrgMemberListInp) (err error) { diff --git a/server/internal/queues/im_audit_event.go b/server/internal/queues/im_audit_event.go index dadb6b4..7b2726a 100644 --- a/server/internal/queues/im_audit_event.go +++ b/server/internal/queues/im_audit_event.go @@ -5,9 +5,9 @@ import ( "encoding/json" "hotgo/internal/consts" "hotgo/internal/library/imkafka" + "hotgo/internal/library/imtenant" "hotgo/internal/library/queue" - "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" ) @@ -32,7 +32,7 @@ func (q *qImAuditEvent) Handle(ctx context.Context, mqMsg queue.MqMsg) (err erro if len(envelope.Payload) > 0 { _ = json.Unmarshal(envelope.Payload, &payload) } - _, err = g.DB().Exec(ctx, `INSERT IGNORE INTO im_audit_events + _, err = imtenant.RegistryDB().Exec(ctx, `INSERT IGNORE INTO im_audit_events (event_id,tenant_code,event_type,biz_type,biz_id,actor_type,actor_id,action,resource,resource_id,result,reason,payload,envelope,occurred_at,received_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,CAST(NULLIF(?, '') AS JSON),CAST(? AS JSON),?,?)`, envelope.EventID, envelope.TenantCode, envelope.EventType, envelope.BizType, envelope.BizID, diff --git a/server/internal/queues/im_dead_letter.go b/server/internal/queues/im_dead_letter.go index b1dd6fc..616cf23 100644 --- a/server/internal/queues/im_dead_letter.go +++ b/server/internal/queues/im_dead_letter.go @@ -5,9 +5,9 @@ import ( "encoding/json" "hotgo/internal/consts" "hotgo/internal/library/imkafka" + "hotgo/internal/library/imtenant" "hotgo/internal/library/queue" - "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gtime" ) @@ -32,7 +32,7 @@ func (q *qImDeadLetter) Handle(ctx context.Context, mqMsg queue.MqMsg) (err erro if len(envelope.Payload) > 0 { _ = json.Unmarshal(envelope.Payload, &payload) } - _, err = g.DB().Exec(ctx, `INSERT IGNORE INTO im_kafka_dead_letter_events + _, err = imtenant.RegistryDB().Exec(ctx, `INSERT IGNORE INTO im_kafka_dead_letter_events (event_id,parent_event_id,tenant_code,event_type,biz_type,biz_id,source_service,target_service,dead_id,reason,message,payload,envelope,received_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,CAST(NULLIF(?, '') AS JSON),CAST(? AS JSON),?)`, envelope.EventID, envelope.ParentEventID, envelope.TenantCode, envelope.EventType, envelope.BizType, envelope.BizID, diff --git a/server/manifest/config/config.template b/server/manifest/config/config.template index 9ed23d2..7d6a9f6 100644 --- a/server/manifest/config/config.template +++ b/server/manifest/config/config.template @@ -306,17 +306,17 @@ hggen: webViewsPath: "../web/src/views/addons/{$name}" # web页面生成路径 imAdminApi: - baseUrl: "http://im-server:6060" - serviceId: "hotgo-admin" - serviceSecret: "8569f5626a54950539eece9f731c9e3bf073daa74af8d23735d19afacac40f4b" + baseUrl: "$IM_ADMIN_API_BASE_URL" + serviceId: "$IM_ADMIN_API_SERVICE_ID" + serviceSecret: "$IM_ADMIN_API_SECRET" timeout: "5s" imInternalApi: - baseUrl: "http://im-server:6060" - serviceName: "hotgo-admin" - serviceSecret: "8569f5626a54950539eece9f731c9e3bf073daa74af8d23735d19afacac40f4b" + baseUrl: "$IM_INTERNAL_API_BASE_URL" + serviceName: "$IM_INTERNAL_API_SERVICE_NAME" + serviceSecret: "$IM_INTERNAL_API_SECRET" imConfigApi: - serviceName: "im-server" - serviceSecret: "b96832c04dbfb6dd768930ec9f082ecd90d87a1ffdaa493aa070617c48de9097" + serviceName: "$IM_CONFIG_API_SERVICE_NAME" + serviceSecret: "$IM_CONFIG_API_SECRET" timeWindow: "300s" diff --git a/server/manifest/docker/entrypoint.sh b/server/manifest/docker/entrypoint.sh index 1828001..72a473a 100644 --- a/server/manifest/docker/entrypoint.sh +++ b/server/manifest/docker/entrypoint.sh @@ -6,10 +6,11 @@ cd /app # Render the real config from the template using only the specific env vars we # expect — avoids accidentally substituting anything else that might contain a # literal '$' in the YAML. -envsubst '$MYSQL_DSN $REDIS_ADDR $REDIS_DB $REDIS_PASSWORD $TOKEN_SECRET_KEY $QUEUE_DRIVER $KAFKA_ADDRESS $KAFKA_VERSION $KAFKA_USERNAME $KAFKA_PASSWORD $KAFKA_SASL_MECHANISM' \ +envsubst '$MYSQL_DSN $REDIS_ADDR $REDIS_DB $REDIS_PASSWORD $TOKEN_SECRET_KEY $QUEUE_DRIVER $KAFKA_ADDRESS $KAFKA_VERSION $KAFKA_USERNAME $KAFKA_PASSWORD $KAFKA_SASL_MECHANISM $IM_ADMIN_API_BASE_URL $IM_ADMIN_API_SERVICE_ID $IM_ADMIN_API_SECRET $IM_INTERNAL_API_BASE_URL $IM_INTERNAL_API_SERVICE_NAME $IM_INTERNAL_API_SECRET $IM_CONFIG_API_SERVICE_NAME $IM_CONFIG_API_SECRET' \ < manifest/config/config.template > manifest/config/config.yaml echo "queue.driver=${QUEUE_DRIVER:-}" echo "queue.kafka.address=${KAFKA_ADDRESS:-}" +echo "imAdminApi.baseUrl=${IM_ADMIN_API_BASE_URL:-}" exec ./hotgo diff --git a/server/storage/data/generate/im_abuse_reason_menu.sql b/server/storage/data/generate/im_abuse_reason_menu.sql index f235603..baa637c 100644 --- a/server/storage/data/generate/im_abuse_reason_menu.sql +++ b/server/storage/data/generate/im_abuse_reason_menu.sql @@ -1,16 +1,16 @@ SET @now := NOW(); SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '举报原因', 'imAbuseReasonIndex', 'abuse-reason/index', '', '2', '', '/imAbuseReason/list', '', '/imAbuseReason/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '82', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imAbuseReasonIndex'); SET @imAbuseReasonId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imAbuseReasonIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imAbuseReasonId, '原因编辑', 'imAbuseReasonEdit', '', '', '3', '', '/imAbuseReason/edit', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imAbuseReasonId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imAbuseReasonEdit'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imAbuseReasonId, '原因禁用', 'imAbuseReasonDelete', '', '', '3', '', '/imAbuseReason/delete', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imAbuseReasonId, ' '), '20', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imAbuseReasonDelete'); diff --git a/server/storage/data/generate/im_app_release_menu.sql b/server/storage/data/generate/im_app_release_menu.sql index 20f3635..361d4e5 100644 --- a/server/storage/data/generate/im_app_release_menu.sql +++ b/server/storage/data/generate/im_app_release_menu.sql @@ -1,12 +1,12 @@ SET @now := NOW(); SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '版本更新', 'imAppReleaseIndex', 'app-release/index', '', '2', '', '/imAppRelease/list', '', '/imAppRelease/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '81', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imAppReleaseIndex'); SET @imAppReleaseId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imAppReleaseIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imAppReleaseId, '版本编辑', 'imAppReleaseEdit', '', '', '3', '', '/imAppRelease/edit', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imAppReleaseId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imAppReleaseEdit'); diff --git a/server/storage/data/generate/im_feedback_config_menu.sql b/server/storage/data/generate/im_feedback_config_menu.sql index 711a6f7..0746731 100644 --- a/server/storage/data/generate/im_feedback_config_menu.sql +++ b/server/storage/data/generate/im_feedback_config_menu.sql @@ -1,12 +1,12 @@ SET @now := NOW(); SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '意见反馈配置', 'imFeedbackConfigIndex', 'feedback-config/index', '', '2', '', '/imFeedbackConfig/get', '', '/imFeedbackConfig/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '84', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imFeedbackConfigIndex'); SET @imFeedbackConfigId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imFeedbackConfigIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imFeedbackConfigId, '反馈配置更新', 'imFeedbackConfigUpdate', '', '', '3', '', '/imFeedbackConfig/update', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imFeedbackConfigId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imFeedbackConfigUpdate'); diff --git a/server/storage/data/generate/im_file_policy_menu.sql b/server/storage/data/generate/im_file_policy_menu.sql index f1e2591..2503e92 100644 --- a/server/storage/data/generate/im_file_policy_menu.sql +++ b/server/storage/data/generate/im_file_policy_menu.sql @@ -20,12 +20,12 @@ CREATE TABLE IF NOT EXISTS `im_file_policy` ( KEY `idx_im_file_policy_tenant_cleanup` (`tenant_id`, `auto_cleanup`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM文件用途策略'; -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '文件策略', 'imFilePolicyIndex', 'file-policy/index', '', '2', '', '/imFilePolicy/list', '', '/imFilePolicy/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '73', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imFilePolicyIndex'); SET @imFilePolicyId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imFilePolicyIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imFilePolicyId, '策略更新', 'imFilePolicyUpdate', '', '', '3', '', '/imFilePolicy/update', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imFilePolicyId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imFilePolicyUpdate'); diff --git a/server/storage/data/generate/im_mailbox_config_menu.sql b/server/storage/data/generate/im_mailbox_config_menu.sql index ecca619..2bd9eed 100644 --- a/server/storage/data/generate/im_mailbox_config_menu.sql +++ b/server/storage/data/generate/im_mailbox_config_menu.sql @@ -1,12 +1,12 @@ SET @now := NOW(); SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '总经理信箱配置', 'imMailboxConfigIndex', 'mailbox-config/index', '', '2', '', '/imMailboxConfig/get', '', '/imMailboxConfig/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '83', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imMailboxConfigIndex'); SET @imMailboxConfigId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imMailboxConfigIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imMailboxConfigId, '信箱配置更新', 'imMailboxConfigUpdate', '', '', '3', '', '/imMailboxConfig/update', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imMailboxConfigId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imMailboxConfigUpdate'); diff --git a/server/storage/data/generate/im_menu_title_repair.sql b/server/storage/data/generate/im_menu_title_repair.sql new file mode 100644 index 0000000..d2b3f47 --- /dev/null +++ b/server/storage/data/generate/im_menu_title_repair.sql @@ -0,0 +1,117 @@ +SET NAMES utf8mb4; + +UPDATE `hg_admin_menu` SET `title` = 'IM管理' WHERE `name` = 'imManager'; +UPDATE `hg_admin_menu` SET `title` = '租户管理' WHERE `name` = 'imTenant'; +UPDATE `hg_admin_menu` SET `title` = '租户列表' WHERE `name` = 'imTenantIndex'; +UPDATE `hg_admin_menu` SET `title` = '租户详情' WHERE `name` = 'imTenantView'; +UPDATE `hg_admin_menu` SET `title` = '新增/编辑租户' WHERE `name` = 'imTenantEdit'; +UPDATE `hg_admin_menu` SET `title` = '启用/停用租户' WHERE `name` = 'imTenantStatus'; +UPDATE `hg_admin_menu` SET `title` = '租户用量统计' WHERE `name` = 'imTenantUsage'; +UPDATE `hg_admin_menu` SET `title` = '租户删除检查' WHERE `name` = 'imTenantDeletionCheck'; +UPDATE `hg_admin_menu` SET `title` = '进入删除保护期' WHERE `name` = 'imTenantEnterDeleting'; +UPDATE `hg_admin_menu` SET `title` = '恢复租户' WHERE `name` = 'imTenantRestore'; + +UPDATE `hg_admin_menu` SET `title` = '用户管理' WHERE `name` = 'imUser'; +UPDATE `hg_admin_menu` SET `title` = '用户列表' WHERE `name` = 'imUserIndex'; +UPDATE `hg_admin_menu` SET `title` = '用户详情' WHERE `name` = 'imUserView'; +UPDATE `hg_admin_menu` SET `title` = '重置密码' WHERE `name` = 'imUserResetPassword'; +UPDATE `hg_admin_menu` SET `title` = '封禁用户' WHERE `name` = 'imUserBan'; +UPDATE `hg_admin_menu` SET `title` = '解封用户' WHERE `name` = 'imUserUnban'; +UPDATE `hg_admin_menu` SET `title` = '冻结用户' WHERE `name` = 'imUserFreeze'; +UPDATE `hg_admin_menu` SET `title` = '解冻用户' WHERE `name` = 'imUserUnfreeze'; +UPDATE `hg_admin_menu` SET `title` = '踢出设备' WHERE `name` = 'imUserDeviceKick'; +UPDATE `hg_admin_menu` SET `title` = '退出所有设备' WHERE `name` = 'imUserLogoutAll'; +UPDATE `hg_admin_menu` SET `title` = '注销账号' WHERE `name` = 'imUserAccountCancel'; +UPDATE `hg_admin_menu` SET `title` = '删除账号' WHERE `name` = 'imUserAccountDelete'; + +UPDATE `hg_admin_menu` SET `title` = '群组管理' WHERE `name` = 'imGroup'; +UPDATE `hg_admin_menu` SET `title` = '群组列表' WHERE `name` = 'imGroupIndex'; +UPDATE `hg_admin_menu` SET `title` = '群组详情' WHERE `name` = 'imGroupView'; +UPDATE `hg_admin_menu` SET `title` = '群成员列表' WHERE `name` = 'imGroupMemberList'; +UPDATE `hg_admin_menu` SET `title` = '群治理配置' WHERE `name` = 'imGroupGovernance'; +UPDATE `hg_admin_menu` SET `title` = '入群审批列表' WHERE `name` = 'imGroupJoinRequestList'; +UPDATE `hg_admin_menu` SET `title` = '群邀请列表' WHERE `name` = 'imGroupInvitationList'; +UPDATE `hg_admin_menu` SET `title` = '群公告列表' WHERE `name` = 'imGroupAnnouncementList'; +UPDATE `hg_admin_menu` SET `title` = '群禁言列表' WHERE `name` = 'imGroupMuteList'; +UPDATE `hg_admin_menu` SET `title` = '群管理日志' WHERE `name` = 'imGroupAdminLogList'; +UPDATE `hg_admin_menu` SET `title` = '更新群资料' WHERE `name` = 'imGroupProfileUpdate'; +UPDATE `hg_admin_menu` SET `title` = '更新群治理配置' WHERE `name` = 'imGroupGovernanceUpdate'; +UPDATE `hg_admin_menu` SET `title` = '设置群管理员' WHERE `name` = 'imGroupAdminSet'; +UPDATE `hg_admin_menu` SET `title` = '移除群管理员' WHERE `name` = 'imGroupAdminRemove'; +UPDATE `hg_admin_menu` SET `title` = '禁言群成员' WHERE `name` = 'imGroupMemberMute'; +UPDATE `hg_admin_menu` SET `title` = '解除群成员禁言' WHERE `name` = 'imGroupMemberUnmute'; +UPDATE `hg_admin_menu` SET `title` = '移除群成员' WHERE `name` = 'imGroupMemberRemove'; +UPDATE `hg_admin_menu` SET `title` = '转让群主' WHERE `name` = 'imGroupOwnerTransfer'; + +UPDATE `hg_admin_menu` SET `title` = '注册邀请码' WHERE `name` = 'imRegistrationInviteIndex'; +UPDATE `hg_admin_menu` SET `title` = '创建邀请码' WHERE `name` = 'imInviteCreate'; +UPDATE `hg_admin_menu` SET `title` = '批量创建邀请码' WHERE `name` = 'imInviteBatchCreate'; +UPDATE `hg_admin_menu` SET `title` = '批次详情' WHERE `name` = 'imInviteBatchView'; +UPDATE `hg_admin_menu` SET `title` = '撤销邀请码' WHERE `name` = 'imInviteRevoke'; +UPDATE `hg_admin_menu` SET `title` = '撤销批次邀请码' WHERE `name` = 'imInviteBatchRevoke'; +UPDATE `hg_admin_menu` SET `title` = '导出邀请码' WHERE `name` = 'imInviteExport'; + +UPDATE `hg_admin_menu` SET `title` = '审计日志' WHERE `name` = 'imAuditLog'; +UPDATE `hg_admin_menu` SET `title` = '审计列表' WHERE `name` = 'imAuditLogIndex'; +UPDATE `hg_admin_menu` SET `title` = '审计详情' WHERE `name` = 'imAuditLogView'; +UPDATE `hg_admin_menu` SET `title` = '导出审计日志' WHERE `name` = 'imAuditLogExport'; + +UPDATE `hg_admin_menu` SET `title` = '组织架构' WHERE `name` = 'imOrgIndex'; +UPDATE `hg_admin_menu` SET `title` = '部门编辑' WHERE `name` = 'imOrgDepartmentEdit'; +UPDATE `hg_admin_menu` SET `title` = '导出部门' WHERE `name` = 'imOrgDepartmentExport'; +UPDATE `hg_admin_menu` SET `title` = '删除部门' WHERE `name` = 'imOrgDepartmentDelete'; +UPDATE `hg_admin_menu` SET `title` = '成员列表' WHERE `name` = 'imOrgMemberList'; +UPDATE `hg_admin_menu` SET `title` = '成员编辑' WHERE `name` = 'imOrgMemberEdit'; +UPDATE `hg_admin_menu` SET `title` = '导出成员' WHERE `name` = 'imOrgMemberExport'; +UPDATE `hg_admin_menu` SET `title` = '移除成员' WHERE `name` = 'imOrgMemberDelete'; +UPDATE `hg_admin_menu` SET `title` = '组织搜索' WHERE `name` = 'imOrgSearch'; + +UPDATE `hg_admin_menu` SET `title` = '文件治理' WHERE `name` = 'imFileIndex'; +UPDATE `hg_admin_menu` SET `title` = '文件详情' WHERE `name` = 'imFileView'; +UPDATE `hg_admin_menu` SET `title` = '隔离文件' WHERE `name` = 'imFileQuarantine'; +UPDATE `hg_admin_menu` SET `title` = '删除文件' WHERE `name` = 'imFileDelete'; +UPDATE `hg_admin_menu` SET `title` = '清理孤儿文件' WHERE `name` = 'imFileCleanupOrphan'; +UPDATE `hg_admin_menu` SET `title` = '文件策略' WHERE `name` = 'imFilePolicyIndex'; +UPDATE `hg_admin_menu` SET `title` = '策略更新' WHERE `name` = 'imFilePolicyUpdate'; + +UPDATE `hg_admin_menu` SET `title` = '通知模板' WHERE `name` = 'imNotificationIndex'; +UPDATE `hg_admin_menu` SET `title` = '模板更新' WHERE `name` = 'imNotificationTemplateUpdate'; + +UPDATE `hg_admin_menu` SET `title` = '外部服务配置' WHERE `name` = 'imExternalConfigIndex'; +UPDATE `hg_admin_menu` SET `title` = '配置详情' WHERE `name` = 'imExternalConfigView'; +UPDATE `hg_admin_menu` SET `title` = '更新配置' WHERE `name` = 'imExternalConfigUpdate'; +UPDATE `hg_admin_menu` SET `title` = '检查配置' WHERE `name` = 'imExternalConfigCheck'; + +UPDATE `hg_admin_menu` SET `title` = '工作台配置' WHERE `name` = 'imWorkbenchIndex'; +UPDATE `hg_admin_menu` SET `title` = '模块编辑' WHERE `name` = 'imWorkbenchEdit'; +UPDATE `hg_admin_menu` SET `title` = '模块删除' WHERE `name` = 'imWorkbenchDelete'; +UPDATE `hg_admin_menu` SET `title` = '模块排序' WHERE `name` = 'imWorkbenchReorder'; + +UPDATE `hg_admin_menu` SET `title` = '版本更新' WHERE `name` = 'imAppReleaseIndex'; +UPDATE `hg_admin_menu` SET `title` = '版本编辑' WHERE `name` = 'imAppReleaseEdit'; + +UPDATE `hg_admin_menu` SET `title` = '举报原因' WHERE `name` = 'imAbuseReasonIndex'; +UPDATE `hg_admin_menu` SET `title` = '原因编辑' WHERE `name` = 'imAbuseReasonEdit'; +UPDATE `hg_admin_menu` SET `title` = '原因删除' WHERE `name` = 'imAbuseReasonDelete'; + +UPDATE `hg_admin_menu` SET `title` = '总经理信箱配置' WHERE `name` = 'imMailboxConfigIndex'; +UPDATE `hg_admin_menu` SET `title` = '更新信箱配置' WHERE `name` = 'imMailboxConfigUpdate'; + +UPDATE `hg_admin_menu` SET `title` = '意见反馈配置' WHERE `name` = 'imFeedbackConfigIndex'; +UPDATE `hg_admin_menu` SET `title` = '更新反馈配置' WHERE `name` = 'imFeedbackConfigUpdate'; + +UPDATE `hg_admin_menu` SET `title` = '任务看板' WHERE `name` = 'imTaskDashboardIndex'; + +UPDATE `hg_admin_menu` SET `title` = 'Kafka命令' WHERE `name` = 'imKafkaCommandIndex'; +UPDATE `hg_admin_menu` SET `title` = '命令详情' WHERE `name` = 'imKafkaCommandView'; +UPDATE `hg_admin_menu` SET `title` = '发送缓存失效测试' WHERE `name` = 'imKafkaCommandCacheInvalidate'; +UPDATE `hg_admin_menu` SET `title` = '发送工作台测试事件' WHERE `name` = 'imKafkaCommandWorkbenchEvent'; + +UPDATE `hg_admin_menu` SET `title` = 'Kafka死信' WHERE `name` = 'imDeadLetterIndex'; +UPDATE `hg_admin_menu` SET `title` = '死信详情' WHERE `name` = 'imDeadLetterView'; +UPDATE `hg_admin_menu` SET `title` = '重放死信' WHERE `name` = 'imDeadLetterReplay'; +UPDATE `hg_admin_menu` SET `title` = '忽略死信' WHERE `name` = 'imDeadLetterIgnore'; +UPDATE `hg_admin_menu` SET `title` = '标记已处理' WHERE `name` = 'imDeadLetterResolve'; + +UPDATE `hg_admin_menu` SET `title` = 'Kafka审计事件' WHERE `name` = 'imKafkaAuditIndex'; +UPDATE `hg_admin_menu` SET `title` = '审计事件详情' WHERE `name` = 'imKafkaAuditView'; diff --git a/server/storage/data/generate/im_missing_menu_patch.sql b/server/storage/data/generate/im_missing_menu_patch.sql index 98cceba..d8aee92 100644 --- a/server/storage/data/generate/im_missing_menu_patch.sql +++ b/server/storage/data/generate/im_missing_menu_patch.sql @@ -26,18 +26,6 @@ FROM ( WHERE @imRootId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` m WHERE m.`name` = p.name); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) -SELECT NULL, @imRootId, 'Outbox运维', 'imOutbox', 'outbox', '', 1, '/im/outbox/index', '', '', 'ParentLayout', 1, '', 0, 0, '', 0, 0, 0, 2, CONCAT('tr_', @imRootId, ' '), 65, '', 1, @now, @now -WHERE @imRootId IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOutbox'); - -SELECT @outboxDirId := `id` FROM `hg_admin_menu` WHERE `name` = 'imOutbox' LIMIT 1; - -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) -SELECT NULL, @outboxDirId, 'Outbox列表', 'imOutboxIndex', 'index', '', 2, '', '/imOutbox/list', '', '/imOutbox/index', 1, 'imOutbox', 0, 0, '', 0, 0, 0, 3, CONCAT('tr_', @imRootId, ' tr_', @outboxDirId, ' '), 10, '', 1, @now, @now -WHERE @outboxDirId IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOutboxIndex'); - SELECT @imOrgId := `id` FROM `hg_admin_menu` WHERE `name` = 'imOrgIndex' LIMIT 1; SELECT @fileId := `id` FROM `hg_admin_menu` WHERE `name` = 'imFileIndex' LIMIT 1; SELECT @filePolicyId := `id` FROM `hg_admin_menu` WHERE `name` = 'imFilePolicyIndex' LIMIT 1; @@ -48,7 +36,6 @@ SELECT @appReleaseId := `id` FROM `hg_admin_menu` WHERE `name` = 'imAppReleaseIn SELECT @abuseReasonId := `id` FROM `hg_admin_menu` WHERE `name` = 'imAbuseReasonIndex' LIMIT 1; SELECT @mailboxConfigId := `id` FROM `hg_admin_menu` WHERE `name` = 'imMailboxConfigIndex' LIMIT 1; SELECT @feedbackConfigId := `id` FROM `hg_admin_menu` WHERE `name` = 'imFeedbackConfigIndex' LIMIT 1; -SELECT @outboxListId := `id` FROM `hg_admin_menu` WHERE `name` = 'imOutboxIndex' LIMIT 1; SELECT @tenantListId := `id` FROM `hg_admin_menu` WHERE `name` = 'imTenantIndex' LIMIT 1; SELECT @auditLogId := `id` FROM `hg_admin_menu` WHERE `name` = 'imAuditLogIndex' LIMIT 1; @@ -80,9 +67,6 @@ FROM ( SELECT @abuseReasonId, '原因禁用', 'imAbuseReasonDelete', '/imAbuseReason/delete', 3, CONCAT('tr_', @imRootId, ' tr_', @abuseReasonId, ' '), 20 UNION ALL SELECT @mailboxConfigId, '信箱配置更新', 'imMailboxConfigUpdate', '/imMailboxConfig/update', 3, CONCAT('tr_', @imRootId, ' tr_', @mailboxConfigId, ' '), 10 UNION ALL SELECT @feedbackConfigId, '反馈配置更新', 'imFeedbackConfigUpdate', '/imFeedbackConfig/update', 3, CONCAT('tr_', @imRootId, ' tr_', @feedbackConfigId, ' '), 10 UNION ALL - SELECT @outboxListId, 'Outbox详情', 'imOutboxView', '/imOutbox/view', 4, CONCAT('tr_', @imRootId, ' tr_', @outboxDirId, ' tr_', @outboxListId, ' '), 10 UNION ALL - SELECT @outboxListId, '重试Outbox事件', 'imOutboxRetry', '/imOutbox/retry', 4, CONCAT('tr_', @imRootId, ' tr_', @outboxDirId, ' tr_', @outboxListId, ' '), 20 UNION ALL - SELECT @outboxListId, '标记Outbox死信', 'imOutboxDead', '/imOutbox/dead', 4, CONCAT('tr_', @imRootId, ' tr_', @outboxDirId, ' tr_', @outboxListId, ' '), 30 UNION ALL SELECT @tenantListId, '租户用量与健康', 'imTenantUsage', '/imTenant/usage', 4, CONCAT('tr_', @imRootId, ' tr_', (SELECT `pid` FROM `hg_admin_menu` WHERE `id` = @tenantListId), ' tr_', @tenantListId, ' '), 40 UNION ALL SELECT @tenantListId, '租户删除前检查', 'imTenantDeletionCheck', '/imTenant/deletionCheck', 4, CONCAT('tr_', @imRootId, ' tr_', (SELECT `pid` FROM `hg_admin_menu` WHERE `id` = @tenantListId), ' tr_', @tenantListId, ' '), 50 UNION ALL SELECT @tenantListId, '租户进入删除流程', 'imTenantEnterDeleting', '/imTenant/enterDeleting', 4, CONCAT('tr_', @imRootId, ' tr_', (SELECT `pid` FROM `hg_admin_menu` WHERE `id` = @tenantListId), ' tr_', @tenantListId, ' '), 60 UNION ALL diff --git a/server/storage/data/generate/im_notification_menu.sql b/server/storage/data/generate/im_notification_menu.sql index 4107d2b..1049aef 100644 --- a/server/storage/data/generate/im_notification_menu.sql +++ b/server/storage/data/generate/im_notification_menu.sql @@ -20,12 +20,12 @@ CREATE TABLE IF NOT EXISTS `im_notification_template` ( KEY `idx_im_notification_template_tenant_status` (`tenant_id`, `status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='IM通知模板配置'; -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '通知模板', 'imNotificationIndex', 'notification/index', '', '2', '', '/imNotification/templateList', '', '/imNotification/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '75', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imNotificationIndex'); SET @imNotificationId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imNotificationIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imNotificationId, '模板更新', 'imNotificationTemplateUpdate', '', '', '3', '', '/imNotification/templateUpdate', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imNotificationId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imNotificationTemplateUpdate'); diff --git a/server/storage/data/generate/im_org_menu.sql b/server/storage/data/generate/im_org_menu.sql index f9fcfa0..e4737d1 100644 --- a/server/storage/data/generate/im_org_menu.sql +++ b/server/storage/data/generate/im_org_menu.sql @@ -1,40 +1,40 @@ SET @now := NOW(); SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '组织架构', 'imOrgIndex', 'org/index', '', '2', '', '/imOrg/departmentList', '', '/imOrg/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '65', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgIndex'); SET @imOrgId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imOrgIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '部门编辑', 'imOrgDepartmentEdit', '', '', '3', '', '/imOrg/departmentEdit', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgDepartmentEdit'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '部门导出', 'imOrgDepartmentExport', '', '', '3', '', '/imOrg/departmentExport', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '15', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgDepartmentExport'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '部门删除', 'imOrgDepartmentDelete', '', '', '3', '', '/imOrg/departmentDelete', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '20', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgDepartmentDelete'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '成员列表', 'imOrgMemberList', '', '', '3', '', '/imOrg/memberList', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '30', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgMemberList'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '成员编辑', 'imOrgMemberEdit', '', '', '3', '', '/imOrg/memberEdit', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '40', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgMemberEdit'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '成员导出', 'imOrgMemberExport', '', '', '3', '', '/imOrg/memberExport', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '45', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgMemberExport'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '成员移除', 'imOrgMemberDelete', '', '', '3', '', '/imOrg/memberDelete', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '50', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgMemberDelete'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imOrgId, '组织搜索', 'imOrgSearch', '', '', '3', '', '/imOrg/search', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imOrgId, ' '), '60', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imOrgSearch'); diff --git a/server/storage/data/generate/im_outbox_menu.sql b/server/storage/data/generate/im_outbox_menu.sql index 90d07c3..b65ada8 100644 --- a/server/storage/data/generate/im_outbox_menu.sql +++ b/server/storage/data/generate/im_outbox_menu.sql @@ -1,35 +1,16 @@ +-- Outbox运维菜单已废弃。 +-- 现架构 Kafka 事件直接落库,不再使用旧 `business_outbox` / `group_outbox` 运维入口。 + SET @now = NOW(); -SELECT @imRootId := `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1; - -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) -SELECT NULL, '0', 'IM管理', 'imManager', '/im', '', '1', '/im/tenant/index', '', '', 'LAYOUT', '1', '', '1', '0', '', '0', '0', '0', '1', '', '200', '', '1', @now, @now -WHERE @imRootId IS NULL; - -SELECT @imRootId := `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1; - -SELECT @outboxDirId := `id` FROM `hg_admin_menu` WHERE `name` = 'imOutbox' LIMIT 1; - -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) -SELECT NULL, @imRootId, 'Outbox运维', 'imOutbox', 'outbox', '', '1', '/im/outbox/index', '', '', 'ParentLayout', '1', '', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '65', '', '1', @now, @now -WHERE @outboxDirId IS NULL; - -SELECT @outboxDirId := `id` FROM `hg_admin_menu` WHERE `name` = 'imOutbox' LIMIT 1; - -SELECT @outboxListId := `id` FROM `hg_admin_menu` WHERE `name` = 'imOutboxIndex' LIMIT 1; - -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) -SELECT NULL, @outboxDirId, 'Outbox列表', 'imOutboxIndex', 'index', '', '2', '', '/imOutbox/list', '', '/imOutbox/index', '1', 'imOutbox', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @outboxDirId, ' '), '10', '', '1', @now, @now -WHERE @outboxListId IS NULL; - -SELECT @outboxListId := `id` FROM `hg_admin_menu` WHERE `name` = 'imOutboxIndex' LIMIT 1; - -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) -SELECT NULL, @outboxListId, title, name, '', '', '3', '', permissions, '', '', '1', '', '0', '0', '', '0', '1', '0', '4', CONCAT('tr_', @imRootId, ' tr_', @outboxDirId, ' tr_', @outboxListId, ' '), sort, '', '1', @now, @now -FROM ( - SELECT 'Outbox详情' title, 'imOutboxView' name, '/imOutbox/view' permissions, 10 sort UNION ALL - SELECT '重试Outbox事件', 'imOutboxRetry', '/imOutbox/retry', 20 UNION ALL - SELECT '标记Outbox死信', 'imOutboxDead', '/imOutbox/dead', 30 -) p -WHERE @outboxListId IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = p.name); +UPDATE `hg_admin_menu` +SET `hidden` = 1, + `status` = 2, + `updated_at` = @now +WHERE `name` IN ( + 'imOutbox', + 'imOutboxIndex', + 'imOutboxView', + 'imOutboxRetry', + 'imOutboxDead' +); diff --git a/server/storage/data/generate/im_workbench_menu.sql b/server/storage/data/generate/im_workbench_menu.sql index 0b28785..c08e824 100644 --- a/server/storage/data/generate/im_workbench_menu.sql +++ b/server/storage/data/generate/im_workbench_menu.sql @@ -1,20 +1,20 @@ SET @now := NOW(); SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imRootId, '工作台配置', 'imWorkbenchIndex', 'workbench/index', '', '2', '', '/imWorkbench/list', '', '/imWorkbench/index', '1', 'imManager', '0', '0', '', '0', '0', '0', '2', CONCAT('tr_', @imRootId, ' '), '80', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imWorkbenchIndex'); SET @imWorkbenchId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imWorkbenchIndex' LIMIT 1); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imWorkbenchId, '工作台编辑', 'imWorkbenchEdit', '', '', '3', '', '/imWorkbench/edit', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imWorkbenchId, ' '), '10', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imWorkbenchEdit'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imWorkbenchId, '工作台禁用', 'imWorkbenchDelete', '', '', '3', '', '/imWorkbench/delete', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imWorkbenchId, ' '), '20', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imWorkbenchDelete'); -INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `component`, `route`, `hidden`, `active_menu`, `is_frame`, `is_cache`, `affix`, `sort`, `status`, `created_by`, `updated_by`, `remark`, `level`, `tree`, `created_at`, `updated_at`) +INSERT INTO `hg_admin_menu` (`id`, `pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`, `permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`, `frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`, `status`, `created_at`, `updated_at`) SELECT NULL, @imWorkbenchId, '工作台排序', 'imWorkbenchReorder', '', '', '3', '', '/imWorkbench/reorder', '', '', '1', '', '0', '0', '', '0', '0', '0', '3', CONCAT('tr_', @imRootId, ' tr_', @imWorkbenchId, ' '), '30', '', '1', @now, @now WHERE NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imWorkbenchReorder'); diff --git a/web/src/views/imOrg/index.vue b/web/src/views/imOrg/index.vue index 0e86b4f..d198500 100644 --- a/web/src/views/imOrg/index.vue +++ b/web/src/views/imOrg/index.vue @@ -155,7 +155,11 @@ /> - + diff --git a/web/src/views/imOrg/model.ts b/web/src/views/imOrg/model.ts index f2904d7..8335ba2 100644 --- a/web/src/views/imOrg/model.ts +++ b/web/src/views/imOrg/model.ts @@ -35,7 +35,7 @@ export class MemberState { public id = 0; public departmentId = ''; public departmentName = ''; - public userId = 0; + public userId = ''; public displayName = ''; public position = ''; public avatarFileId = ''; @@ -177,7 +177,7 @@ export const memberRules = { type: 'string', message: '请选择部门', }, - userId: { required: true, trigger: ['blur', 'input'], type: 'number', message: '请输入用户ID' }, + userId: { required: true, trigger: ['blur', 'input'], type: 'string', message: '请输入用户ID' }, employmentState: { required: true, trigger: ['blur', 'change'],