diff --git a/.cursor/cursorrules-backend.md b/.cursor/cursorrules-backend.md index 26d3cc7f..c643cb5a 100644 --- a/.cursor/cursorrules-backend.md +++ b/.cursor/cursorrules-backend.md @@ -1979,3 +1979,53 @@ public interface SysUserMapper extends BaseMapperPlus { Page selectUserPage(Page page, @Param("bo") SysUserBo bo); } ``` + +### 🗑️ 逻辑删除规则(全局强制,2025-07-11新增) + +> **适用范围**:所有业务表、所有MyBatis-Plus实体、所有Service删除操作 +> +> **设计目标**:统一软删除实现,避免物理删除带来的数据丢失,保证查询接口自动过滤已删除数据。 + +1. **数据库字段** + - 字段名:`deleted` + - 字段类型:`tinyint(1)` + - 默认值:`0`(存在) + - 含义:`0`-存在,`1`-已删除 + +2. **实体类注解** + ```java + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic(value = "0", delval = "1") + private Integer deleted; + ``` + - `@TableLogic` 由 MyBatis-Plus 提供,可自动将 `DELETE` SQL 转换为 + ```sql + UPDATE table SET deleted = 1 WHERE id = ? + ``` + - 同时在所有自动生成的 `SELECT` 语句中追加条件 `deleted = 0`,无需显式编写过滤条件。 + +3. **删除操作代码规范** + - Service 层推荐使用 MyBatis-Plus 的 `deleteById` / `deleteBatchIds` 等方法即可触发逻辑删除。 + - 如需自定义删除 SQL,**必须**包含 `deleted = 0` 过滤并在删除时设置 `deleted = 1`。 + - Controller 层仍按业务语义暴露 `DELETE /{id}` 接口,无需额外逻辑,保持与物理删除一致的调用方式。 + +4. **查询操作规范** + - 默认情况下,MyBatis-Plus 已自动附加 `deleted = 0` 条件。编写自定义 SQL 时,**必须**手动加上 `AND deleted = 0`。 + - 对外返回的分页/列表接口,不得包含 `deleted = 1` 的数据。 + +5. **数据恢复** + - 若业务需要"恢复已删除数据",可单独提供接口,将 `deleted` 字段重新置回 `0`。 + +> 📌 **注意**:逻辑删除是项目级强制要求,任何物理删除(`DELETE FROM ...`)将被代码审查拒绝。 + +#### 🔴 AI 开发强制要求 + +当使用 AI 进行数据库开发时: + +1. **必须先阅读** `docs/设计文档/database/mysql-database-standard.md` 规范 +2. **必须使用标准模板**,不得随意修改基础字段 +3. **必须保持与现有表结构的一致性** +4. **建表后必须立即更新** `hzdyjs_xg.sql` 文件 +5. **必须在变更记录中记录** 数据库变更 diff --git a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqHallInfo.java b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqHallInfo.java index 3551afa0..dc0bbaa1 100644 --- a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqHallInfo.java +++ b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqHallInfo.java @@ -49,5 +49,10 @@ public class HqHallInfo extends TenantEntity { */ private String hallDescription; + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic(value = "0", delval = "1") + private Integer deleted; } diff --git a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqPmRepairCategory.java b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqPmRepairCategory.java index 6cacfd66..c5486041 100644 --- a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqPmRepairCategory.java +++ b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/domain/HqPmRepairCategory.java @@ -121,4 +121,10 @@ public class HqPmRepairCategory extends TenantEntity { */ private String remark; + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic(value = "0", delval = "1") + private Integer deleted; + } diff --git a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqPmRepairCategoryServiceImpl.java b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqPmRepairCategoryServiceImpl.java index a7ef0251..784a87f2 100644 --- a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqPmRepairCategoryServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqPmRepairCategoryServiceImpl.java @@ -254,7 +254,8 @@ public class HqPmRepairCategoryServiceImpl implements IHqPmRepairCategoryService @Override public List queryTree() { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); - lqw.eq(HqPmRepairCategory::getStatus, "1"); + // 不过滤状态,返回所有分类(包括停用状态),前端可自行根据 status 进行展示控制 + // lqw.eq(HqPmRepairCategory::getStatus, "1"); lqw.orderByAsc(HqPmRepairCategory::getSortOrder).orderByAsc(HqPmRepairCategory::getId); List allList = baseMapper.selectVoList(lqw); diff --git a/web/src/views/hq/pm/repairCategory/index.vue b/web/src/views/hq/pm/repairCategory/index.vue index f0bfe66e..e04c5c8c 100644 --- a/web/src/views/hq/pm/repairCategory/index.vue +++ b/web/src/views/hq/pm/repairCategory/index.vue @@ -71,7 +71,7 @@ :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" border header-align="center" - @row-click="handleRowClick" + @row-dblclick="handleRowClick" style="width: 100%" class="tree-table" > diff --git a/web/src/views/hq/pm/repairOrder/index.vue b/web/src/views/hq/pm/repairOrder/index.vue index 517fa57a..f3fc9bd1 100644 --- a/web/src/views/hq/pm/repairOrder/index.vue +++ b/web/src/views/hq/pm/repairOrder/index.vue @@ -1510,6 +1510,16 @@ const satisfactionLevelOptions = ref([ { value: '5', label: '非常不满意' } ]); +// 新增:过滤已删除(deleted = 1)及已停用(status = 0) 的维修类型 +const filterActiveCategories = (categories: RepairCategoryVO[]): RepairCategoryVO[] => { + return (categories || []) + .filter((cat: any) => String(cat.deleted) !== '1' && String(cat.status) !== '0') + .map((cat) => ({ + ...cat, + children: cat.children ? filterActiveCategories(cat.children) : [] + })); +}; + /** 查询报修工单列表 */ const getList = async () => { loading.value = true; @@ -1562,7 +1572,8 @@ const getStatistics = async () => { const getCategoryOptions = async () => { try { const res = await getRepairCategoryOptions(); - categoryOptions.value = res.data; + // 过滤掉已删除或停用的数据 + categoryOptions.value = (res.data || []).filter((cat: any) => String(cat.deleted) !== '1' && String(cat.status) !== '0'); } catch (error) { console.error('获取维修类型选项失败:', error); } @@ -1572,7 +1583,8 @@ const getCategoryOptions = async () => { const getCategoryTreeOptions = async () => { try { const res = await getRepairCategoryTree(); - categoryTreeOptions.value = res.data || []; + // 过滤掉已删除或停用的数据(递归) + categoryTreeOptions.value = filterActiveCategories(res.data || []); } catch (error) { console.error('获取维修类型树形结构失败:', error); categoryTreeOptions.value = [];