提交代码

This commit is contained in:
zlwu committed 2025-08-22 16:10:35 +08:00
1 parent 3a27cfa0e7
commit 3f5caaea67
2 files changed
+398 -7

No files matched your search

@@ -0,0 +1,250 @@
# 撤销申请页面图片加载问题修复记录
## 问题描述
**现象**: 在已有撤销申请时,再次打开撤销申请界面(`revokeApplication.vue`),界面中的图片没有做加载显示,看控制台没有调用接口。
**影响范围**: 移动端撤销申请页面的图片附件显示功能
## 问题分析
### 原因分析
1. **缺少图片blob处理**: `revokeApplication.vue` 在 `handleExistingEvidenceData` 方法中只是简单地将 OSS 数据转换为附件列表,但没有像 `RevokeApplicationView.vue` 查看页面那样处理图片的 blob 数据获取。
2. **图片URL处理不完整**: 对于图片文件,需要特殊处理URL前缀并获取blob数据才能正确显示。
3. **缺少图片预加载机制**: 没有预加载机制确保图片能够正确显示。
### 参考实现
参考了 `RevokeApplicationView.vue` 中的图片处理机制:
- `processAllImageFiles()` 方法处理图片blob数据
- `getImageBlobUrl()` 方法获取图片blob URL
- `preloadAllImages()` 方法预加载图片
## 解决方案
### 1. 增强附件数据处理 (`handleExistingEvidenceData`)
```javascript
// 处理现有证明材料附件数据时
const attachmentFiles = response.data.map((item, index) => {
// 使用fileSuffix字段判断文件类型
const fileType = this.getFileTypeBySuffix(item.fileSuffix);
const isImage = this.isImageFile({
name: item.originalName,
type: fileType,
});
// 处理图片URL - 确保有正确的API前缀
let processedUrl = item.url;
if (isImage && item.url && item.url.startsWith('/resource/')) {
// 图片文件需要添加/api前缀
processedUrl = `/api${item.url}`;
}
// 构造完整的文件名(包含扩展名)
let fullFileName = item.originalName || `证明材料${index + 1}`;
if (
item.fileSuffix &&
!fullFileName
.toLowerCase()
.endsWith(`.${item.fileSuffix.toLowerCase()}`)
) {
fullFileName = `${fullFileName}.${item.fileSuffix}`;
}
return {
uid: `existing_${index}_${Date.now()}`,
name: fullFileName,
url: processedUrl,
ossId: item.ossId,
status: 'success',
type: fileType,
size: item.fileSize || 0,
};
});
this.attachmentList = attachmentFiles;
// 🚀 关键步骤:处理图片文件以确保正确显示
await this.processAllImageFiles();
// 强制刷新组件显示
this.$nextTick(() => {
// 预加载图片以确保能正确显示
this.preloadAllImages();
});
```
### 2. 添加图片处理核心方法
#### `processAllImageFiles()` - 处理所有图片文件
```javascript
async processAllImageFiles() {
console.log('=== 处理所有图片文件 ===');
// 处理附件列表中的图片
const imageFiles = this.attachmentList.filter((file) => this.isImageFile(file));
for (const file of imageFiles) {
if (file.url && !file.blobUrl) {
try {
console.log(`处理图片文件: ${file.name}`);
const blobUrl = await this.getImageBlobUrl(file.url);
if (blobUrl) {
file.blobUrl = blobUrl;
file.fileType = 'image';
file.type = file.type && file.type.startsWith('image') ? file.type : 'image';
file.isImage = true;
console.log(`图片文件处理成功: ${file.name} - ${blobUrl}`);
}
} catch (error) {
console.error(`处理图片文件失败: ${file.name}`, error);
}
}
}
}
```
#### `getImageBlobUrl()` - 获取图片blob数据
```javascript
async getImageBlobUrl(imageUrl) {
try {
console.log(`获取图片blob数据: ${imageUrl}`);
// 处理图片URL路径
let apiUrl = imageUrl;
if (imageUrl.startsWith('/api/')) {
// 移除/api前缀,因为request会自动添加baseURL
apiUrl = imageUrl.replace('/api', '');
} else if (imageUrl.startsWith('/resource/')) {
// 直接使用相对路径
apiUrl = imageUrl;
} else if (imageUrl.startsWith('http')) {
// 完整URL,需要特殊处理
console.log('检测到完整URL,直接返回原URL');
return imageUrl;
}
console.log(`API请求URL: ${apiUrl}`);
// 使用request方法获取图片数据
const response = await request({
url: apiUrl,
method: 'GET',
responseType: 'arraybuffer', // 设置响应类型为arraybuffer
header: {
isToken: true, // 图片请求可能需要token验证
},
});
// 将arraybuffer转换为blob
const blob = new Blob([response], { type: 'image/*' });
const blobUrl = URL.createObjectURL(blob);
console.log(`成功创建blob URL: ${blobUrl}`);
return blobUrl;
} catch (error) {
console.error(`获取图片blob数据失败: ${imageUrl}`, error);
// 如果请求失败,返回原始URL作为备用方案
return imageUrl;
}
}
```
#### `preloadAllImages()` - 预加载图片
```javascript
async preloadAllImages() {
console.log('=== 预加载所有图片 ===');
// 预加载附件列表中的图片
const imageFiles = this.attachmentList.filter((file) => this.isImageFile(file));
for (const file of imageFiles) {
if (file.url) {
try {
console.log(`预加载图片: ${file.name} - ${file.url}`);
const img = new Image();
img.onload = () => {
console.log(`图片预加载成功: ${file.name}`);
};
img.onerror = () => {
console.error(`图片预加载失败: ${file.name} - ${file.url}`);
};
img.src = file.blobUrl || file.url;
} catch (error) {
console.error(`预加载图片出错: ${file.name}`, error);
}
}
}
}
```
### 3. 增强模板错误处理
在模板中为image组件添加错误处理:
```vue
<image
:src="image.blobUrl || image.url"
class="attachment-image"
mode="aspectFill"
@error="handleImageError"
></image>
```
```javascript
// 图片加载错误处理
handleImageError(event) {
console.warn('图片加载失败:', event);
}
```
## 修复效果
### 修复前
- 已有撤销申请记录时,图片附件无法显示
- 控制台没有任何API调用记录
- 图片区域显示空白或加载失败
### 修复后
- 已有撤销申请记录时,图片附件正常显示
- 控制台显示完整的图片处理流程日志
- 图片正确加载并支持预览功能
## 技术要点
1. **blob数据处理**: 通过获取图片的arraybuffer数据并转换为blob URL,确保图片能正确显示
2. **URL路径处理**: 正确处理不同格式的图片URL路径
3. **异步处理**: 使用async/await确保图片处理的时序正确
4. **错误处理**: 添加完善的错误处理和降级方案
5. **内存管理**: 在页面卸载时清理blob URL,防止内存泄漏
## 测试建议
1. **基础功能测试**:
- 创建新的撤销申请(上传图片附件)
- 保存后重新进入页面,验证图片是否正常显示
2. **边界条件测试**:
- 测试不同格式的图片文件(JPG, PNG, GIF等)
- 测试混合附件(图片+文档)
- 测试网络异常情况下的降级处理
3. **性能测试**:
- 测试多张图片的加载性能
- 检查内存泄漏情况
## 相关文件
- **主要修改文件**: `mobile/src/pages/xskh/wjjl/revokeApplication.vue`
- **参考实现文件**: `mobile/src/pages/xskh/wjjl/RevokeApplicationView.vue`
- **修复日期**: 2025-01-03
- **修复人员**: AI Assistant
## 总结
通过参考查看页面的成功实现,为撤销申请页面添加了完整的图片blob数据处理机制,确保了已有撤销申请记录的图片附件能够正确显示。修复方案具有良好的错误处理和性能优化特性。