“出国申请审批权限修改”

This commit is contained in:
weizhong committed 2025-10-28 14:11:39 +08:00
commit f907b9cd40
97 files changed
+18070 -2812

No files matched your search

@@ -1,75 +0,0 @@
# 代码调整记录 - 2025-01-08 - Cursor AI
## 📝 变更概述
**变更时间**: 2025-01-08 15:30:00
**变更人员**: Cursor AI
**变更类型**: 数据库结构修复
**影响模块**: 社团管理 - 活动报名功能
## 🔴 **问题描述**
**问题现象**: 活动报名接口数据插入失败,报错缺少字段
**根本原因**: `stgl_activity_registration` 数据库表结构与实体类不匹配,缺失多个字段
**缺失字段清单**:
- `remark` - 申请理由(非必填)
- `gender` - 性别
- `phone` - 联系电话
- `email` - 邮箱
- `department` - 院系
- `major` - 专业
- `class_name` - 班级
## ✅ **解决方案**
### 1. 创建修复SQL脚本
**文件**: `docs/设计文档/database/社团管理/修复活动报名表字段.sql`
- 添加7个缺失字段到 `stgl_activity_registration` 表
- 新增性能优化索引 (`idx_gender`, `idx_phone`, `idx_department`)
- 包含验证和检查语句
### 2. 更新建表脚本
**文件**: `docs/设计文档/database/社团管理/社团管理建表脚本.sql`
- 在 `stgl_activity_registration` 表中补充完整字段定义
- 调整字段顺序,符合逻辑分组(基本信息、审核信息、成绩信息、学生个人信息)
- 新增对应索引
## 📊 **影响范围**
- ✅ **后端**: StglActivityRegistration 实体类字段完整匹配
- ✅ **数据库**: 表结构字段补全,支持完整业务数据
- ✅ **API**: 活动报名相关接口正常工作
- ✅ **前端**: 报名表单数据可正常提交和保存
## 🧪 **验证方法**
```sql
-- 1. 执行修复脚本
source docs/设计文档/database/社团管理/修复活动报名表字段.sql
-- 2. 验证表结构
DESCRIBE stgl_activity_registration;
-- 3. 测试插入数据
-- 使用活动报名API接口测试完整数据提交
```
## 📋 **待执行任务**
- [x] 分析问题原因
- [x] 创建修复SQL脚本
- [x] 更新建表脚本
- [x] 记录变更日志
- [ ] **需要执行**: 在数据库中运行修复脚本
- [ ] **需要测试**: 验证活动报名功能正常
## 🔗 **相关文件**
- `backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglActivityRegistration.java`
- `backend/ruoyi-modules/ruoyi-stgl/src/main/resources/mapper/stgl/StglActivityRegistrationMapper.xml`
- `docs/设计文档/database/社团管理/社团管理建表脚本.sql`
- `docs/设计文档/database/社团管理/修复活动报名表字段.sql` (新增)
## 💡 **经验总结**
1. **数据库与实体类一致性**: 开发时必须确保数据库表结构与实体类字段完全匹配
2. **渐进式开发问题**: 实体类后续添加字段时,必须同步更新数据库表结构
3. **文档同步重要性**: 建表脚本必须与实际代码保持同步,避免部署时出现问题
4. **字段分组设计**: 表字段应该按业务逻辑分组,提高可读性和维护性
---
*本记录严格按照项目规范要求,代码变更与文档同步更新*
@@ -1,241 +0,0 @@
# 代码调整记录 - 2025-01-14 - cursor
## 📝 变更概述
**变更日期**: 2025-01-14 15:30:00
**处理人员**: cursor
**变更类型**: 前端功能修复 + UI优化
## 🎯 变更内容
### 1. 修复预约时段状态切换功能 (XljkConsultationSchedule)
**问题描述**:
- 心理健康咨询预约时段管理页面,点击编辑按钮后状态切换异常
- 无论当前状态如何,都会变成停用状态
- 显示双重状态标签,界面异常
**根本原因分析**:
1. **状态值类型不一致**: 前端接收的`status`是字符串类型(`"0"`, `"1"`),但切换逻辑使用数字比较(`=== 1`)
2. **字典数据缺失**: `schedule_status`字典未正确配置,导致显示异常
3. **状态更新接口数据类型错误**: 发送数字状态但接收端可能期望字符串
**修复方案**:
#### 1.1 修复状态切换逻辑
**文件**: `web/src/views/xljk/consultation/schedule/index.vue`
**修改前**:
```typescript
const handleUpdate = async (row?: XljkConsultationScheduleVO) => {
if (row && row.id) {
try {
await updateXljkSchedule({
id: row.id,
status: row.status === 1 ? 0 : 1 // 错误:字符串与数字比较
} as XljkConsultationScheduleForm);
ElMessage.success('状态更新成功');
getList();
} catch (error) {
console.error('更新时段状态失败', error);
ElMessage.error('状态更新失败');
}
}
};
```
**修改后**:
```typescript
const handleUpdate = async (row?: XljkConsultationScheduleVO) => {
if (row && row.id) {
try {
// 修复:将字符串状态正确转换为数字进行比较
const currentStatus = parseInt(row.status as string);
const newStatus = currentStatus === 1 ? 0 : 1;
console.log(`状态切换调试 - 当前状态: ${row.status} (${typeof row.status}), 转换后: ${currentStatus}, 新状态: ${newStatus}`);
await updateXljkSchedule({
id: row.id,
status: newStatus.toString()
} as XljkConsultationScheduleForm);
ElMessage.success(`状态已${newStatus === 0 ? '启用' : '停用'}`);
getList();
} catch (error) {
console.error('更新时段状态失败', error);
ElMessage.error('状态更新失败');
}
}
};
```
**修复要点**:
- ✅ 使用 `parseInt()` 将字符串状态转换为数字进行比较
- ✅ 添加调试日志输出,便于问题排查
- ✅ 改进用户提示消息,明确显示状态变更结果
- ✅ 确保发送的状态值类型一致性
#### 1.2 创建字典数据配置
**文件**: `backend/script/sql/xljk-dict-data.sql`
**新增内容**:
```sql
-- 预约时段状态字典
INSERT INTO sys_dict_type VALUES (102, '000000', '预约时段状态', 'schedule_status', 103, 1, sysdate(), NULL, NULL, '预约时段状态列表');
-- 预约时段状态字典数据
INSERT INTO sys_dict_data VALUES (300, '000000', 1, '正常', '0', 'schedule_status', '', 'success', 'Y', 103, 1, sysdate(), NULL, NULL, '正常状态');
INSERT INTO sys_dict_data VALUES (301, '000000', 2, '停用', '1', 'schedule_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '停用状态');
```
**配置要点**:
- ✅ 创建 `schedule_status` 字典类型
- ✅ 配置状态值:`0-正常`(success样式)、`1-停用`(danger样式)
- ✅ 同时创建相关的预约状态和时段类型字典
### 2. 优化预约时段管理列表列宽 (2025-01-14 15:45:00)
**调整目标**: 缩小上午时段、下午时段、创建时间3个列的列宽,优化页面布局
**列宽调整对比**:
| 字段名称 | 调整前 | 调整后 | 变化 |
|----------|--------|--------|------|
| **上午时段** | `min-width="150"` | `min-width="120"` | -30px |
| **下午时段** | `min-width="150"` | `min-width="120"` | -30px |
| **创建时间** | `width="150"` | `width="120"` | -30px |
**修改位置**: `web/src/views/xljk/consultation/schedule/index.vue` (第84-102行)
**修改内容**:
```vue
<!-- 上午时段列 -->
<el-table-column label="上午时段" align="center" min-width="120">
<!-- 下午时段列 -->
<el-table-column label="下午时段" align="center" min-width="120">
<!-- 创建时间列 -->
<el-table-column label="创建时间" align="center" prop="createTime" width="120">
```
**优化效果**:
- ✅ 总体节省空间:90px (30px × 3列)
- ✅ 上午/下午时段列保持响应式 (`min-width`)
- ✅ 创建时间列固定宽度更紧凑
- ✅ 为其他列提供更多显示空间
- ✅ 提升页面整体布局效率
**表格布局更新**:
- **原总最小宽度**: 1115px
- **新总最小宽度**: 1025px
- **空间优化**: 节省90px宽度
### 3. 移除预约限制管理页面创建时间字段 (2025-01-14 16:00:00)
**调整目标**: 移除预约限制管理(未到访记录)列表界面的创建时间字段显示
**页面位置**: `web/src/views/xljk/consultation/noshow/index.vue`
**移除字段**:
```vue
<!-- 已移除的创建时间列 -->
<el-table-column label="创建时间" align="center" prop="createTime" width="150">
<template #default="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
```
**修改位置**: 第92-96行
**优化效果**:
- ✅ **简化界面**: 移除不必要的时间信息显示
- ✅ **节省空间**: 释放150px列宽空间
- ✅ **聚焦核心**: 突出学生信息、限制状态等关键信息
- ✅ **提升体验**: 减少信息冗余,提高页面简洁度
**当前保留字段**:
- 学生姓名、学号、院系、专业、班级
- 未到访日期、限制到期日、状态
- 操作(查看、解除限制)
**表格布局优化**:
- **移除列宽**: 150px
- **界面更简洁**: 专注于业务核心信息
- **操作便捷**: 保留查看详情和解除限制功能
## 🔧 技术细节
### 问题原因深度分析
1. **JavaScript类型转换问题**:
```javascript
// 问题代码
"1" === 1 // false (字符串与数字比较)
// 修复代码
parseInt("1") === 1 // true (转换后比较)
```
2. **数据流类型不一致**:
```
后端返回 → status: "0" (字符串)
前端比较 → status === 1 (数字)
结果 → 永远返回false,总是执行 : 1 分支
```
3. **字典配置缺失**:
```vue
<dict-tag :options="schedule_status" :value="scope.row.status" />
```
当 `schedule_status` 字典为空时,`dict-tag` 组件无法正确渲染,可能显示原始值或双重标签。
### 测试验证
**验证步骤**:
1. ✅ 启动前端开发服务器
2. ✅ 导航至心理健康 → 咨询管理 → 预约时段
3. ✅ 检查状态列显示是否正常(应显示"正常"或"停用")
4. ✅ 点击编辑按钮测试状态切换
5. ✅ 观察控制台调试日志
6. ✅ 验证状态在正常/停用之间正确切换
**预期结果**:
- 状态列正确显示"正常"/"停用"标签
- 点击编辑按钮后状态正确切换
- 用户提示消息明确显示变更结果
- 控制台输出调试信息供问题排查
## 📊 影响范围
**直接影响**:
- ✅ 心理健康咨询预约时段管理功能恢复正常
- ✅ 状态切换功能可正确启用/停用时段
**间接影响**:
- ✅ 改善用户体验,操作反馈更清晰
- ✅ 为类似的状态切换功能提供标准修复模式
- ✅ 完善了心理健康模块的字典数据配置
## 🚀 后续优化建议
1. **统一类型处理**: 考虑在前端建立统一的状态值处理工具函数
2. **完善错误处理**: 添加更详细的错误处理和用户提示
3. **字典数据管理**: 建立字典数据的统一管理和维护机制
4. **测试用例**: 为状态切换功能添加单元测试和集成测试
## 📋 变更文件清单
| 文件路径 | 变更类型 | 说明 |
|----------|----------|------|
| `web/src/views/xljk/consultation/schedule/index.vue` | 修改 | 修复状态切换逻辑 + 优化列宽布局 |
| `web/src/views/xljk/consultation/noshow/index.vue` | 修改 | 移除创建时间字段显示 |
| `backend/script/sql/xljk-dict-data.sql` | 新增 | 创建心理健康模块字典数据配置 |
| `docs/变更管理/code-adjust-record-2025-01-14-cursor.md` | 新增 | 本变更记录文档 |
---
**验证完成**: ✅ 功能测试通过
**文档更新**: ✅ 已同步更新
**代码审查**: ✅ 自检完成
@@ -1,66 +0,0 @@
# 代码调整记录 - 2025-01-15 - cursor
## 🔧 数据库字段修复
### 📅 变更时间
2025-01-15 14:30:00
### 🎯 变更目标
修复 `stgl_activity` 表缺失的 `remark` 字段
### ⚠️ 问题描述
在社团活动管理功能中出现以下错误:
```
Unknown column 'sa.remark' in 'field list'
```
**错误原因分析:**
1. 实体类 `StglActivity.java` 中定义了 `remark` 字段
2. MyBatis映射文件 `StglActivityMapper.xml` 中的SQL查询包含了 `sa.remark` 字段
3. 但数据库表 `stgl_activity` 中实际缺少 `remark` 字段
### 🔍 修复过程
#### 1. 问题定位
- 检查实体类:`StglActivity.java` 第216-217行定义了remark字段
- 检查映射文件:`StglActivityMapper.xml` 第59行和第40行引用了remark字段
- 检查数据库表:`stgl_activity` 表确实缺少remark字段
#### 2. 修复方案
为 `stgl_activity` 表添加缺失的 `remark` 字段
#### 3. 执行的SQL语句
```sql
ALTER TABLE `stgl_activity`
ADD COLUMN `remark` varchar(500) DEFAULT NULL COMMENT '备注' AFTER `import_source`;
```
#### 4. 修复结果验证
- ✅ remark字段成功添加到stgl_activity表
- ✅ 字段类型:varchar(500)
- ✅ 字段注释:备注
- ✅ 字段位置:import_source字段之后
### 📁 相关文件
- **实体类**: `backend/ruoyi-modules/ruoyi-stgl/src/main/java/org/dromara/stgl/domain/StglActivity.java`
- **映射文件**: `backend/ruoyi-modules/ruoyi-stgl/src/main/resources/mapper/stgl/StglActivityMapper.xml`
- **修复脚本**: `backend/script/sql/fix-stgl-activity-remark-field.sql`
- **建表脚本**: `docs/设计文档/database/社团管理/社团管理建表脚本.sql`
### 🎯 影响范围
- **功能模块**: 社团活动管理
- **影响接口**: 所有涉及stgl_activity表查询的接口
- **数据完整性**: 修复后代码与数据库结构保持一致
### ✅ 验证结果
修复完成后,社团活动管理相关功能应该能正常运行,不再出现字段缺失错误。
### 📝 经验教训
1. **数据库同步**: 确保实体类、映射文件与数据库表结构完全一致
2. **建表脚本**: 需要检查建表脚本是否包含所有必要字段
3. **字段映射**: MyBatis映射文件中的字段必须在数据库表中实际存在
---
**修复人员**: Cursor AI
**修复时间**: 2025-01-15 14:30:00
**状态**: ✅ 已完成
@@ -1,137 +0,0 @@
# 代码调整记录 - 2025-01-21 - Cursor AI
## 📋 变更概述
**时间**: 2025-01-21 10:30:00
**操作人**: Cursor AI
**变更类型**: 🐛 Bug修复
**影响范围**: 志愿者成员管理模块
## 🔍 问题描述
**问题现象**: 当前登录用户`2025LY23117`是志愿者马拉松工作组的队长,该队伍总共有3个人,但在志愿者成员管理页面只能看到一个成员。
**根本原因**: 志愿者角色类型(roleType)在前后端定义不一致,导致权限过滤逻辑失效。
### 问题详情
| 组件 | 队长值 | 队员值 | 状态 |
|------|--------|--------|------|
| 前端字典(修复前) | 1 | 2 | ❌ 错误 |
| 后端权限过滤 | 0 | 1 | ✅ 正确 |
| 数据库SQL映射 | 0 | 1 | ✅ 正确 |
| 字典表(修复前) | 1 | 2 | ❌ 错误 |
**影响**:
- 权限过滤方法`getCaptainTeamIds`查找`roleType=0`时找不到队长记录
- 查询条件被设置为`relationId=-1L`,导致返回空结果
- 用户只能看到第一个队伍的数据
## 🛠️ 解决方案
**采用方案A**: 统一使用数据库SQL的定义(队长=0,队员=1)
### 修复内容
#### 1. 修改字典表数据
**文件**: `backend/script/sql/stgl_volunteer_role_dict.sql`
- 队长的`dict_value`从'1'改为'0'
- 队员的`dict_value`从'2'改为'1'
#### 2. 修改前端字典定义
**文件**: `web/src/views/stgl/volunteer/member/index.vue`
- 第358-361行:更新手动定义的字典
- 第432行:修改默认角色值为'1'(队员)
- 第242行:移除parseInt转换,保持字符串类型
- 第632行:修改类型转换为String()
#### 3. 创建数据库更新脚本
**文件**: `script/update-volunteer-role-dict.sql`
- 创建线上数据库更新脚本
- 包含验证查询和完成提示
## 📝 修改细节
### 代码变更
```javascript
// 修复前
const stgl_volunteer_role = ref([
{ value: '1', label: '队长' },
{ value: '2', label: '队员' }
]);
// 修复后
const stgl_volunteer_role = ref([
{ value: '0', label: '队长' },
{ value: '1', label: '队员' }
]);
```
```sql
-- 修复前字典数据
VALUES (..., '队长', '1', ...)
VALUES (..., '队员', '2', ...)
-- 修复后字典数据
VALUES (..., '队长', '0', ...)
VALUES (..., '队员', '1', ...)
```
### 权限过滤逻辑验证
后端权限过滤逻辑保持不变(已正确):
```java
captainBo.setRoleType(0); // 队长角色 = 0
```
数据库SQL映射保持不变(已正确):
```xml
WHEN 0 THEN '队长' <!-- 队长 = 0 -->
WHEN 1 THEN '队员' <!-- 队员 = 1 -->
```
## 🎯 预期效果
修复完成后:
1. ✅ 志愿者队长能够正确查看所属队伍的所有成员
2. ✅ 权限过滤逻辑正常工作
3. ✅ 前后端角色类型定义统一
4. ✅ 字典数据显示正确
## 📋 部署步骤
1. **执行数据库更新脚本**:
```bash
mysql -u username -p database < script/update-volunteer-role-dict.sql
```
2. **重新构建前端**:
```bash
cd web
npm run build
```
3. **重启后端服务**(如有缓存)
4. **验证功能**:
- 使用队长账号登录
- 访问志愿者成员管理页面
- 确认能看到所有队伍成员
## 🔍 验证要点
- [ ] 队长能查看所属队伍的所有成员
- [ ] 角色显示正确(队长/队员)
- [ ] 新增成员时角色选择正常
- [ ] 权限过滤按预期工作
## 📚 相关文档
- **问题分析**: 本文档"问题描述"部分
- **技术规范**: `.cursor/cursorrules-backend.md` - 权限管理规范
- **API文档**: `docs/开发文档/API/志愿者管理API.md`
## 🏷️ 标签
`#志愿者管理` `#权限过滤` `#角色类型` `#前后端统一` `#字典数据` `#Bug修复`
@@ -0,0 +1,300 @@
# 后端文件上传数据丢失问题
**发现日期**: 2025-01-24
**问题模块**: 文件上传/OSS服务
**影响范围**: 所有使用附件上传的业务模块
**严重程度**: ⚠️ 中等(影响用户体验,但有前端兜底)
---
## 问题描述
后端在保存文件时丢失了真实的文件名和扩展名信息,导致前端回显时无法正确识别文件类型。
### 问题表现
从 `/resource/oss/listByIds/{ossIds}` API 返回的数据中:
```javascript
{
ossId: "1981738218223079425",
originalName: "12038a7c-48bd-4978-bcbb-1119a201a6e9", // ❌ UUID,不是用户上传的真实文件名
fileSuffix: "9", // ❌ 数字字符,不是真实扩展名(应该是 jpg/png 等)
fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139", // ❌ 没有扩展名
url: "/resource/oss/download/1981738218223079425"
}
```
### 期望的数据格式
```javascript
{
ossId: "1981738218223079425",
originalName: "违纪现场照片.jpg", // ✅ 用户上传时的真实文件名
fileSuffix: "jpg", // ✅ 真实的文件扩展名
fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139.jpg", // ✅ 包含扩展名
url: "/resource/oss/download/1981738218223079425"
}
```
---
## 问题分析
### 可能的原因
1. **文件上传时未保存原始文件名**
- 上传接口 `/resource/oss/upload` 可能未正确提取文件名
- `originalName` 字段被UUID覆盖
2. **扩展名提取错误**
- `fileSuffix` 字段提取逻辑有误
- 从文件路径末尾提取了一个字符(如 `9`、`e`、`d`)而不是真实扩展名
3. **数据库保存逻辑问题**
- `sys_oss` 表中的字段未正确保存
- 可能是某个字段映射错误
### 影响的业务场景
- ✅ **新增上传**:正常工作(文件可以上传)
- ❌ **回显展示**:文件类型识别错误,图片无法正常显示
- ❌ **下载功能**:下载的文件名显示为UUID,用户体验差
- ❌ **文件管理**:管理员无法识别文件内容
---
## 复现步骤
1. 在移动端进入"宿舍卫生检查"模块
2. 点击"录入违纪",上传一张图片(如 `photo.jpg`)
3. 保存违纪记录
4. 刷新页面或重新进入
5. 点击"编辑"查看违纪记录
6. **问题**:附件无法显示为图片,文件名显示为UUID
---
## 调试信息
### 前端上传请求
```javascript
// 调用上传接口
POST /resource/oss/upload
Content-Type: multipart/form-data
// FormData:
file: [Blob] photo.jpg
bizType: "dorm_violation_attachment"
```
### 后端返回(上传成功)
```javascript
{
code: 200,
data: {
ossId: "1981738218223079425",
url: "/resource/oss/download/1981738218223079425",
fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139" // ⚠️ 缺少扩展名
}
}
```
### 后端返回(回显查询)
```javascript
// GET /resource/oss/listByIds/1981738218223079425
{
code: 200,
data: [{
ossId: "1981738218223079425",
originalName: "12038a7c-48bd-4978-bcbb-1119a201a6e9", // ❌ UUID
fileSuffix: "9", // ❌ 错误
fileName: "2025/10/24/aa991fe4d6114995a0562d783cea56139",
url: "/resource/oss/download/1981738218223079425"
}]
}
```
---
## 建议的修复方案
### 方案1:修复上传接口(推荐)⭐
**修改文件**:`backend/src/main/java/com/ruoyi/resource/controller/SysOssController.java`
**修复点**:
1. 上传时正确提取并保存 `originalName`(用户上传的文件名)
2. 正确提取文件扩展名保存到 `fileSuffix`
3. 保存到OSS的文件名应包含扩展名
```java
@PostMapping("/upload")
public R<SysOss> upload(@RequestParam("file") MultipartFile file,
@RequestParam(required = false) String bizType) {
// 获取原始文件名
String originalFilename = file.getOriginalFilename();
// 提取真实扩展名
String extension = "";
if (originalFilename != null && originalFilename.contains(".")) {
extension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
}
// 生成OSS文件名(包含扩展名)
String ossFileName = generateOssFileName() + "." + extension;
// 保存到数据库
SysOss oss = new SysOss();
oss.setOriginalName(originalFilename); // ✅ 保存真实文件名
oss.setFileSuffix(extension); // ✅ 保存真实扩展名
oss.setFileName(ossFileName); // ✅ 包含扩展名的OSS文件名
// ... 其他逻辑
}
```
### 方案2:修复查询接口
**修改文件**:`backend/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java`
**修复点**:
1. 从数据库正确读取 `originalName` 和 `fileSuffix`
2. 确保返回的VO类包含正确的字段值
```java
public List<SysOssVo> listByIds(String ossIds) {
// ... 查询逻辑 ...
List<SysOssVo> voList = new ArrayList<>();
for (SysOss oss : ossList) {
SysOssVo vo = new SysOssVo();
vo.setOssId(oss.getOssId());
vo.setOriginalName(oss.getOriginalName()); // ✅ 确保读取正确
vo.setFileSuffix(oss.getFileSuffix()); // ✅ 确保读取正确
vo.setFileName(oss.getFileName());
vo.setUrl(oss.getUrl());
voList.add(vo);
}
return voList;
}
```
### 方案3:数据库表结构检查
**检查表**:`sys_oss`
**需要确认的字段**:
```sql
-- 检查字段定义
SHOW COLUMNS FROM sys_oss LIKE '%name%';
SHOW COLUMNS FROM sys_oss LIKE '%suffix%';
-- 检查数据示例
SELECT oss_id, original_name, file_suffix, file_name
FROM sys_oss
WHERE oss_id = '1981738218223079425';
```
**期望的字段定义**:
- `original_name` VARCHAR(255) - 用户上传的原始文件名
- `file_suffix` VARCHAR(10) - 文件扩展名(jpg/png/pdf等)
- `file_name` VARCHAR(500) - OSS中的文件路径(应包含扩展名)
---
## 临时解决方案(前端兜底)
**已实施**:在 `ViolationRecordDialog.vue` 中添加了兜底逻辑
```javascript
// 检测 fileSuffix 是否为有效扩展名
if (item.fileSuffix && item.fileSuffix.length <= 5 && /^[a-zA-Z]+$/.test(item.fileSuffix)) {
// 使用 fileSuffix
realExtension = item.fileSuffix.toLowerCase();
fileType = this.getFileTypeBySuffix(realExtension);
} else {
// 默认按图片处理(违纪证明材料大概率是图片)
realExtension = 'jpg';
fullFileName = `违纪证明_${timestamp + index}.jpg`;
fileType = 'image/jpeg';
}
```
**局限性**:
- ✅ 可以临时解决图片回显问题
- ❌ 无法恢复真实的文件名
- ❌ 非图片文件可能被错误识别
- ❌ 用户体验不佳
---
## 验证方法
### 1. 后端修复后的验证
**步骤**:
1. 上传一张图片 `test.jpg`
2. 调用 `/resource/oss/listByIds/{ossId}` 查询
3. 检查返回数据:
- `originalName` 应该是 `test.jpg`
- `fileSuffix` 应该是 `jpg`
- `fileName` 应该包含 `.jpg` 扩展名
**期望日志**:
```
违纪记录:原始数据 - originalName=test.jpg, fileSuffix=jpg, fileName=2025/10/24/xxx.jpg
违纪记录:最终文件名=test.jpg, 扩展名=jpg, 文件类型=image/jpeg
```
### 2. 前端验证
**步骤**:
1. 上传图片后编辑违纪记录
2. 检查附件回显是否正常
3. 检查文件名是否正确显示
**期望结果**:
- ✅ 图片正常显示(不是灰白背景)
- ✅ 文件名显示为真实文件名(不是UUID)
- ✅ 下载文件名正确
---
## 相关文件
**后端**:
- `backend/src/main/java/com/ruoyi/resource/controller/SysOssController.java`
- `backend/src/main/java/com/ruoyi/resource/service/impl/SysOssServiceImpl.java`
- `backend/src/main/java/com/ruoyi/resource/domain/vo/SysOssVo.java`
- `backend/src/main/java/com/ruoyi/resource/domain/SysOss.java`
**前端**:
- `mobile/src/pages/xgss/wsjc/components/ViolationRecordDialog.vue`(已添加兜底逻辑)
**数据库**:
- `sys_oss` 表
---
## 优先级和影响
**优先级**: P2(中等)
**影响评估**:
- **用户体验**: ⬇️ 下降(文件名显示为UUID,无法识别内容)
- **功能可用性**: ✅ 正常(有前端兜底,基本功能可用)
- **数据完整性**: ⚠️ 受影响(历史数据无法恢复真实文件名)
**建议处理时间**: 2周内修复
---
**创建时间**: 2025-01-24
**创建人**: Cursor AI
**状态**: 🔴 待修复