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/.cursor/cursorrules-frontend.md b/.cursor/cursorrules-frontend.md index 16f524be..ac63da55 100644 --- a/.cursor/cursorrules-frontend.md +++ b/.cursor/cursorrules-frontend.md @@ -809,3 +809,103 @@ export default defineConfig({ 1. **按钮规范**: 工具栏第一个新增按钮必须使用 `type="primary" plain`,其他按钮使用默认样式 2. **颜色系统**: 使用最新的 Art Design Pro 颜色变量 3. **文档同步**: 代码变更后必须同步更新相关文档 + +## 4. 附件管理统一规范(强制性) + +> 适用范围:所有使用 **Element Plus** + **Vue 3 + TS** 的前端页面(弹窗、新建、编辑、详情、预览等)涉及“附件/文件”功能的模块,必须遵循本规范,以保持 UI 及交互的一致性。 + +### 4.1 组件结构 + +| 组件 | 说明 | +|------|------| +| `` | 核心上传组件,拖拽 + 点击上传,**单文件最大 10 MB**,**最多 15 个文件** | +| 自定义 `#file` 模板 | 自绘「卡片样式」:缩略图 + 文件名 + 操作按钮组 | +| `` | 卡片底部操作按钮:下载(success)、删除(danger) | +| 自定义 CSS 类 | `.upload-file-card / thumb / name / actions` 等,详见样式规范 | + +### 4.2 功能实现 + +1. **上传 Upload** + - `auto-upload="true"` + 立即上传 + - `accept="image/*,video/*,.pdf,.doc,.docx,.txt"` + - 上传前 (`before-upload`) 校验大小 <10 MB + - 上传成功: + - 新建模式:将返回的 `id` 收集到 `tempAttachmentIds` + - 编辑模式:文件已自动关联到工单 + - 上传失败:Element Plus message 提示 + +2. **下载 Download (强制使用 fetch + blob)** + - 统一函数 `handleDownloadAttachment(file)` / `downloadAttachment(attachment)` + - 流程:`fetch(filePath) → blob → URL.createObjectURL → ` + - 使用 `ElLoading.service()` 显示 *正在下载文件…* + - 下载完成后 `revokeObjectURL` 释放内存 + - 解决浏览器对图片/PDF 默认预览导致无法下载的问题 + +3. **删除 Delete(延迟删除机制)** + - 点击删除 → `proxy.$modal.confirm()` 二次确认 + - 已上传文件:只把 `attachment.id` 放入 `pendingDeleteAttachmentIds`,**不立即调用后端** + - 表单保存时统一调用 `deleteAttachment` 批量删除 + - 新增未上传文件:直接从 `tempFileList` / `attachmentList` 移除 + +4. **预览 Preview** + - 判断 `fileType === 'image'` → 使用 `Element Plus ImageViewer` 预览 + - 其他类型文件 `window.open(filePath,'_blank')` + - 详情弹窗附件列表同样遵循该预览逻辑 + +### 4.3 样式规范(SCSS) + +```scss +/* 让附件卡片一行展示 4 个 */ +:deep(.el-upload-list--picture-card) { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 9px; + margin-top: 12px; + .el-upload-list__item { + width: 166px !important; + min-height: 180px !important; + border-radius: 6px; + overflow: hidden; + } +} + +/* 卡片整体布局 */ +.upload-file-card { + display: flex; + flex-direction: column; + min-height: 180px; +} +.upload-file-thumb { height: 120px; overflow: hidden; } +.upload-file-name { font-size: 12px; padding: 8px 4px 4px; text-align: center; overflow: hidden; } +.upload-file-card-actions { + padding: 6px 8px; + border-top: 1px solid #f0f0f0; + background: #fafafa; + display: flex; justify-content: center; +} +``` + +### 4.4 统一变量 & Hook + +```ts +const attachmentList = ref([]); // el-upload file-list +const tempFileList = ref([]); // 新建时未上传的本地文件 +const tempAttachmentIds = ref([]); // 新建时已上传待关联附件 id +const pendingDeleteAttachmentIds = ref([]); // 编辑时标记待删除附件 id +``` + +### 4.5 集成步骤(页面级) + +1. 在 ` + + diff --git a/web/src/plugins/modal.ts b/web/src/plugins/modal.ts index 83388ac6..b3504018 100644 --- a/web/src/plugins/modal.ts +++ b/web/src/plugins/modal.ts @@ -21,28 +21,33 @@ export default { // 弹出提示 alert(content: any) { ElMessageBox.alert(content, '系统提示', { - confirmButtonClass: 'el-button--primary' + confirmButtonClass: 'el-button--primary', + // 允许在内容中使用
等 HTML + dangerouslyUseHTMLString: true }); }, // 错误提示 alertError(content: any) { ElMessageBox.alert(content, '系统提示', { type: 'error', - confirmButtonClass: 'el-button--primary' + confirmButtonClass: 'el-button--primary', + dangerouslyUseHTMLString: true }); }, // 成功提示 alertSuccess(content: any) { ElMessageBox.alert(content, '系统提示', { type: 'success', - confirmButtonClass: 'el-button--primary' + confirmButtonClass: 'el-button--primary', + dangerouslyUseHTMLString: true }); }, // 警告提示 alertWarning(content: any) { ElMessageBox.alert(content, '系统提示', { type: 'warning', - confirmButtonClass: 'el-button--primary' + confirmButtonClass: 'el-button--primary', + dangerouslyUseHTMLString: true }); }, // 通知提示 diff --git a/web/src/router/index.ts b/web/src/router/index.ts index a6497dbe..567f7bb4 100644 --- a/web/src/router/index.ts +++ b/web/src/router/index.ts @@ -88,13 +88,21 @@ export const constantRoutes: RouteRecordRaw[] = [ meta: { title: '个人中心', icon: 'user' } } ] + }, + // 临时测试路由 + { + path: '/test-collection-batch', + name: 'TestCollectionBatch', + component: () => import('@/views/xg-xx/collectionBatch/test.vue'), + meta: { + title: '信息采集批次测试', + icon: 'ep:setting' + } } ]; // 动态路由,基于用户权限动态去加载 -export const dynamicRoutes: RouteRecordRaw[] = [ - -]; +export const dynamicRoutes: RouteRecordRaw[] = []; /** * 创建路由 diff --git a/web/src/utils/dict.ts b/web/src/utils/dict.ts index bde704a0..0c45501d 100644 --- a/web/src/utils/dict.ts +++ b/web/src/utils/dict.ts @@ -9,7 +9,7 @@ export const useDict = (...args: string[]) => { const res = reactive<{ [key: string]: DictDataOption[] }>({}); // 初始化所有字典类型为空数组 - args.forEach(dictType => { + args.forEach((dictType) => { res[dictType] = []; }); diff --git a/web/src/views/aqbw/README.md b/web/src/views/aqbw/README.md index ee9c009f..8fc499bd 100644 --- a/web/src/views/aqbw/README.md +++ b/web/src/views/aqbw/README.md @@ -1,51 +1,61 @@ # 安全保卫管理模块 - 前端界面 ## 📋 模块说明 + - **模块名称**: 安全保卫管理 (Security Management) - **模块简称**: aqbw - **对应后端**: backend/ruoyi-modules/ruoyi-aqbw/ ## 📁 目录结构 + 此目录用于存放安全保卫管理模块的所有前端界面组件,包括: ### 🔒 门禁管理 + - 门禁权限管理 - 进出记录 - 访客管理 ### 📹 监控管理 + - 监控设备管理 - 监控录像查看 - 异常报警 ### 🚨 安全事件 + - 事件报告 - 事件处理 - 应急预案 ### 👮 安保人员 + - 人员管理 - 值班安排 - 巡逻记录 ### 🚗 车辆管理 + - 车辆登记 - 停车管理 - 违章处理 ### 📊 安全统计 + - 安全数据统计 - 事件分析 - 风险评估 ## 🎯 开发规范 + - 遵循Vue 3 + TypeScript + Element Plus开发规范 - 组件命名采用PascalCase - 文件命名采用kebab-case - 统一使用Composition API ## 📝 注意事项 + - 新增页面需要配置对应的路由 - API接口统一调用@/api/aqbw/目录下的接口 - 权限控制使用v-hasPermi指令,权限编码格式:aqbw:功能:操作 -- 安全相关数据需要严格的权限控制和日志记录 \ No newline at end of file +- 安全相关数据需要严格的权限控制和日志记录 diff --git a/web/src/views/cw/README.md b/web/src/views/cw/README.md index e0f09df2..f00dc84b 100644 --- a/web/src/views/cw/README.md +++ b/web/src/views/cw/README.md @@ -1,46 +1,55 @@ # 财务管理模块 - 前端界面 ## 📋 模块说明 + - **模块名称**: 财务管理 (Financial Management) - **模块简称**: cw - **对应后端**: backend/ruoyi-modules/ruoyi-cw/ ## 📁 目录结构 + 此目录用于存放财务管理模块的所有前端界面组件,包括: ### 💰 会计核算 + - 科目管理 - 凭证管理 - 账簿管理 ### 📊 预算管理 + - 预算编制 - 预算执行 - 预算分析 ### 💳 资产管理 + - 固定资产 - 流动资产 - 资产盘点 ### 📈 财务报表 + - 资产负债表 - 损益表 - 现金流量表 ### 💸 费用管理 + - 费用申请 - 费用审批 - 费用报销 ## 🎯 开发规范 + - 遵循Vue 3 + TypeScript + Element Plus开发规范 - 组件命名采用PascalCase - 文件命名采用kebab-case - 统一使用Composition API ## 📝 注意事项 + - 新增页面需要配置对应的路由 - API接口统一调用@/api/cw/目录下的接口 - 权限控制使用v-hasPermi指令,权限编码格式:cw:功能:操作 -- 财务数据需要特别注意精度和安全性 \ No newline at end of file +- 财务数据需要特别注意精度和安全性 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 ee66e863..593336eb 100644 --- a/web/src/views/hq/pm/repairOrder/index.vue +++ b/web/src/views/hq/pm/repairOrder/index.vue @@ -24,9 +24,18 @@ - - - + @@ -83,7 +92,7 @@ -
+ @@ -200,15 +209,13 @@ 新增报修 - 修改 + 修改 - 删除 + 删除 - 导出 + 导出 @@ -220,6 +227,7 @@ border :data="repairOrderList" @selection-change="handleSelectionChange" + @row-dblclick="handleDetail" style="width: 100%" :scroll-x="true" class="scroll-table" @@ -268,7 +276,7 @@ - - +