# 就业援助模块开发问题记录 > 记录开发过程中遇到的各种问题及解决方案,供后续新模块开发参考 --- ## 1. SQL 执行问题 ### 1.1 达梦不支持行内 COMMENT 语法 **错误:** `Syntax error (-2007)` **原因:** 达梦(DM8)原生模式下不支持 MySQL 的行内 `COMMENT 'xxx'` 语法。 **错误写法:** ```sql CREATE TABLE FOO ( ID VARCHAR(36) NOT NULL COMMENT '主键ID' -- ❌ DM不支持 ); ``` **正确写法:** ```sql CREATE TABLE FOO ( ID VARCHAR(36) NOT NULL ); COMMENT ON TABLE FOO IS '表名'; COMMENT ON COLUMN FOO.ID IS '主键ID'; ``` **注意:** `.docs/sql/` 目录下的参考文件(如 `重点关注人员信息.sql`)使用的是 MySQL 语法,要在 DM 上执行需先转换。 --- ### 1.2 SQL 执行到错误的模式(Schema) **错误:** `Table or view not found` **原因:** 在 DM 管理工具中连接时,SQL 可能执行到了错误的 schema 下,导致表和数据不在预期的 schema 中。 **解决:** 执行前确认当前 schema,或者使用 `SET SCHEMA 模式名` 切换到正确模式。 --- ### 1.3 达梦保留字需用双引号包围 **错误:** `Invalid column name [name]` **原因:** `NAME`、`DESCRIPTION`、`STATUS` 是达梦保留字,在 SQL 中直接使用会报错。 **解决:** 用双引号包围保留字,且需要注意**大小写**——达梦默认以**大写**存储对象名,所以双引号内也需大写: ```sql -- ✅ 正确 INSERT INTO sys_permission (id, "NAME", "DESCRIPTION", "STATUS") VALUES (..., 'xxx', 'xxx', 1); -- ❌ 错误(大小写不匹配) INSERT INTO sys_permission (id, "name", "description", "status") VALUES (...); ``` --- ### 1.4 视图 SQL 需使用 DM 原生函数 **错误:** 视图创建成功后查询报错 **原因:** DM 原生模式下 `TIMESTAMPDIFF` + `CURDATE()` 是 MySQL 函数 **解决:** 使用 DM 原生函数: ```sql -- ❌ MySQL 语法 TIMESTAMPDIFF(YEAR, birth_date, CURDATE()) AS age -- ✅ DM 原生语法 FLOOR(MONTHS_BETWEEN(CURRENT_DATE, birth_date) / 12) AS age ``` --- ## 2. 菜单权限问题 ### 2.1 权限 status = NULL 导致按钮不显示 **现象:** 数据库中有权限记录,角色授权也正确,但前端按钮不显示。 **根因:** 后端 `SysPermissionController` 查询权限时过滤条件为 `status = 1`。但插入 SQL 中 `status` 字段为 `NULL`,导致权限码不被返回给前端。 **参考:** `V20260604_9__fix_permission_status.sql` **解决:** 插入按钮权限时 `status` 必须设为 `1`: ```sql -- ✅ 正确 INSERT INTO sys_permission (..., status, internal_or_external) VALUES (..., 1, 0); -- status = 1 -- ❌ 错误 INSERT INTO sys_permission (..., status, internal_or_external) VALUES (..., NULL, 0); -- status = NULL ``` **修复已有数据:** ```sql UPDATE sys_permission SET status = 1 WHERE perms LIKE '模块名:%' AND (status IS NULL OR status != 1); ``` --- ### 2.2 v-auth 权限指令不生效 **现象:** 权限已插入、角色已关联、status=1,但 `v-auth` 仍然隐藏按钮 **排查步骤:** 1. 在控制台查看 `permissionStore.getPermCodeList` 是否包含目标权限码 2. 如果不在列表中,检查 `status` 是否为 `1` 3. 重启后端服务(清除缓存) 4. 重新登录(前端重新加载权限列表) --- ## 3. 前端组件模式 ### 3.1 列表页必须使用 useListPage + 手动搜索表单 **参考模块:** `FocusPersonnelList.vue` **正确模式:** ```vue ``` **❌ 错误模式(不要用):** ```ts // 不要用 formConfig.schemas 方式(前端的 useSearchForm: true) const [registerTable] = useTable({ formConfig: { schemas: [...] }, // ❌ }); ``` --- ### 3.2 Modal 组件必须使用 ref 方式 **参考模块:** `FocusPersonnelModal.vue` **正确模式:** ```vue ``` **❌ 错误模式(不要用):** ```ts const [registerModal, { openModal }] = useModal(); // ❌ ``` --- ### 3.3 详情页组件模式 **参考模块:** `FocusPersonnelDetail.vue` **正确模式:** ```vue ``` --- ### 3.4 字典翻译必须使用 useDict **现象:** 列表显示数值而非文字(如性别显示 "1" 而非 "男性") **解决:** 使用 `useDict` 钩子加载字典: ```ts import { useDict } from '/@/hooks/dictionary/useDict'; const { getDictText } = useDict(['JobSeekerStatus', 'JobSeekerCategory', ...]); ``` 模板中使用 `getDictText` 翻译: ```vue ``` 性别用硬编码映射即可: ```ts const genderMap: Record = { '1': '男性', '2': '女性' }; ``` --- ### 3.5 selectedRowKeys 判空保护 **错误:** `Cannot read properties of undefined (reading 'length')` **原因:** 表格未初始化时 `selectedRowKeys` 为 `undefined`,直接访问 `.length` 报错 **解决:** ```vue :disabled="!selectedRowKeys || selectedRowKeys.length === 0" ``` --- ## 4. 达梦函数兼容性速查表 | 功能 | MySQL 语法 | DM 语法 | |------|-----------|---------| | 当前日期 | `CURDATE()` | `CURRENT_DATE` | | 年龄计算 | `TIMESTAMPDIFF(YEAR, birth, CURDATE())` | `FLOOR(MONTHS_BETWEEN(CURRENT_DATE, birth) / 12)` | | 标识符引用 | `` `name` `` | `"NAME"`(双引号,大写) | | 行内注释 | `COMMENT 'xxx'` | 不支持,用 `COMMENT ON` | | 删除视图 | `DROP VIEW IF EXISTS v_name` | 支持 | | 删除表 | `DROP TABLE IF EXISTS t_name` | 支持 | | 字符串拼接 | `CONCAT('%', val, '%')` | `CONCAT('%', val, '%')` | | 分页 | `LIMIT ? OFFSET ?` | `LIMIT ? OFFSET ?` | --- ## 5. 开发流程检查清单 ### 新建模块时逐项检查: - [ ] 建表SQL:去掉行内 `COMMENT`,改用 `COMMENT ON` - [ ] 建表SQL:使用 `DROP TABLE IF EXISTS` 支持重复执行 - [ ] 视图SQL:使用 `FLOOR(MONTHS_BETWEEN(...))` 替代 `TIMESTAMPDIFF` - [ ] 视图SQL:使用 `DROP VIEW IF EXISTS` 支持重复执行 - [ ] 菜单SQL:`status` 设为 `1`(非 NULL) - [ ] 菜单SQL:保留字 `NAME`/`DESCRIPTION`/`STATUS` 用大写双引号 - [ ] 菜单SQL:先 DELETE 清理旧数据再 INSERT(兼容重复执行) - [ ] Mapper XML:年龄用 `FLOOR(MONTHS_BETWEEN(...))` 计算 - [ ] Mapper XML:不使用反引号 - [ ] 前端列表页:使用 `useListPage` + 手动 `` 搜索 - [ ] 前端Modal:使用 `ref` 方式 + ``,非 `useModal` - [ ] 前端详情:使用 `` + `watch` 加载 - [ ] 前端字典:使用 `useDict` 加载字典翻译 - [ ] 导出按钮:保留 `v-auth` 权限控制 - [ ] selectedRowKeys:添加 `!selectedRowKeys` 判空