图片组件统一改造方案

目标

将客户、设备、备件模块的图片上传功能统一改造为使用 UnifiedAttachmentUpload 组件,实现:

  1. 统一的上传体验
  2. OSS Key 永久引用支持
  3. 多图片支持(逗号分隔)
  4. 预签名URL自动转换

改造范围

1. 客户模块 ✅ (已完成)

  • 实体类BzCustomer.java
    • customerPhotoUrl - 照片URL字段
    • customerPhotoKeys - 照片Key字段(新增)
  • 前端表单ui/src/views/business/customer/components/customer-form.vue
  • 列表页面ui/src/views/business/customer/index.vue
  • 后端ServiceBzCustomerServiceImpl.java:75,211
  • MapperBzCustomerMapper.xml

2. 设备模块 🔄 (进行中)

  • 实体类BzEquipment.java
    • equipmentPhotoUrl - 照片URL字段
    • equipmentPhotoKeys - 照片Key字段(新增)✅
  • 前端表单:待修改
  • 后端ServiceBzEquipmentServiceImpl.java:58,252 - 需修改
  • MapperBzEquipmentMapper.xml - 待添加 Keys 字段

3. 备件模块 🔄 (进行中)

  • 实体类BzSparePart.java
    • partImageUrl - 图片URL字段
    • partImageKeys - 图片Key字段(新增)✅
  • 前端表单:待修改
  • 后端ServiceBzSparePartServiceImpl.java:74 - 需修改
  • MapperBzSparePartMapper.xml - 待添加 Keys 字段

核心原理

数据流向

上传 → OSS → 返回 {fileUrl, fileKey} → 前端分别存储 → 后端保存
      ↓
  查询 ← 从 Keys 字段读取 ← Mapper ← Service 转换为预签名URL

Keys vs URL

字段类型 存储内容 特点 用途
Keys business/customer/xxx.jpg 永久有效的OSS Key 数据库存储
URL https://oss.com/xxx.jpg?sign=xxx 临时预签名URL 前端展示

转换逻辑

// 查询时:从Keys转换为URL
String keys = "key1.jpg,key2.jpg";
String urls = OssUtils.convertToPresignedUrl(keys);
// 结果:url1?sign=xxx,url2?sign=xxx

// 批量转换
OssUtils.convertListToPresignedUrl(
    list,
    Entity::getPhotoKeys,      // 从Keys字段读取
    Entity::setPhotoUrl        // 设置到URL字段
);

已完成的修改

1. 后端实体类

✅ BzCustomer.java

// 第93-119行
private String customerPhotoUrl;    // URL字段
private String customerPhotoKeys;   // Keys字段

✅ BzEquipment.java

// 第51-57行
private String equipmentPhotoUrl;   // URL字段
private String equipmentPhotoKeys;  // Keys字段(新增)

✅ BzSparePart.java

// 第101-107行
private String partImageUrl;       // URL字段
private String partImageKeys;      // Keys字段(新增)

2. 后端Service

✅ BzCustomerServiceImpl.java

// 第75行 - 列表查询
OssUtils.convertListToPresignedUrl(list, BzCustomer::getCustomerPhotoKeys, BzCustomer::setCustomerPhotoUrl);

// 第59-62行 - 单条查询
if (customer != null && customer.getCustomerPhotoKeys() != null) {
    customer.setCustomerPhotoUrl(OssUtils.convertToPresignedUrl(customer.getCustomerPhotoKeys()));
}

3. 前端组件

✅ customer-form.vue (第66-77行)

<unified-attachment-upload
  v-model="formData.customerPhotoUrl"
  v-model:keys="formData.customerPhotoKeys"
  :multiple="true"
  accept=".jpg,.jpeg,.png,.gif,.bmp"
  :limit="5"
  :max-size="10"
  tip="支持客户照片上传,最多5张,最大10MB"
/>

4. 数据库

✅ 客户表

ALTER TABLE bz_customer ADD COLUMN customer_photo_keys VARCHAR(1000);
ALTER TABLE bz_customer MODIFY COLUMN customer_photo_url VARCHAR(1000);

待完成的修改

1. 数据库(重要!)

执行SQL脚本:db/update_photo_keys_unified.sql

-- 设备表
ALTER TABLE bz_equipment ADD COLUMN equipment_photo_keys VARCHAR(1000);
ALTER TABLE bz_equipment MODIFY COLUMN equipment_photo_url VARCHAR(1000);

-- 备件表
ALTER TABLE bz_spare_part ADD COLUMN part_image_keys VARCHAR(1000);
ALTER TABLE bz_spare_part MODIFY COLUMN part_image_url VARCHAR(1000);

2. Mapper XML文件

BzEquipmentMapper.xml

需要在以下位置添加 equipment_photo_keys 字段:

  • <resultMap> 中添加映射
  • <sql id="selectBzEquipmentVo"> 中添加查询字段
  • <insert> 中添加插入逻辑
  • <update> 中添加更新逻辑

BzSparePartMapper.xml

需要在以下位置添加 part_image_keys 字段:

  • <resultMap> 中添加映射
  • <sql id="selectBzSparePartVo"> 中添加查询字段
  • <insert> 中添加插入逻辑
  • <update> 中添加更新逻辑

3. Service实现类

BzEquipmentServiceImpl.java

// 第58行 - 需要修改
OssUtils.convertListToPresignedUrl(list, BzEquipment::getEquipmentPhotoKeys, BzEquipment::setEquipmentPhotoUrl);

// 第252行 - 需要修改
OssUtils.convertListToPresignedUrl(list, BzEquipment::getEquipmentPhotoKeys, BzEquipment::setEquipmentPhotoUrl);

BzSparePartServiceImpl.java

// 第74行 - 需要修改
OssUtils.convertListToPresignedUrl(list, BzSparePart::getPartImageKeys, BzSparePart::setPartImageUrl);

4. 前端表单

设备表单

文件位置:需要查找 ui/src/views/business/equipment 目录下的表单组件

修改为:

<unified-attachment-upload
  v-model="formData.equipmentPhotoUrl"
  v-model:keys="formData.equipmentPhotoKeys"
  :multiple="true"
  accept=".jpg,.jpeg,.png,.gif,.bmp"
  :limit="10"
  :max-size="20"
  tip="支持设备照片上传,最多10张,最大20MB"
/>

备件表单

文件位置:需要查找 ui/src/views/business/sparePart 目录下的表单组件

修改为:

<unified-attachment-upload
  v-model="formData.partImageUrl"
  v-model:keys="formData.partImageKeys"
  :multiple="true"
  accept=".jpg,.jpeg,.png,.gif,.bmp"
  :limit="10"
  :max-size="20"
  tip="支持备件图片上传,最多10张,最大20MB"
/>

执行步骤

第一步:数据库迁移

# 执行SQL脚本
mysql -u root -p husky_afterservice_db < db/update_photo_keys_unified.sql

第二步:验证数据库

-- 查看新增字段
SELECT
    TABLE_NAME,
    COLUMN_NAME,
    COLUMN_TYPE,
    COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'husky_afterservice_db'
  AND COLUMN_NAME LIKE '%_keys'
ORDER BY TABLE_NAME;

第三步:修改Mapper XML文件

  1. 修改 BzEquipmentMapper.xml
  2. 修改 BzSparePartMapper.xml

第四步:修改Service实现

  1. 修改 BzEquipmentServiceImpl.java
  2. 修改 BzSparePartServiceImpl.java

第五步:修改前端表单

  1. 查找并修改设备表单组件
  2. 查找并修改备件表单组件

第六步:重启测试

  1. 重启后端服务
  2. 清空浏览器缓存
  3. 测试图片上传功能
  4. 测试图片预览功能
  5. 测试编辑功能

测试清单

  • 客户照片上传
  • 客户照片预览(列表页、详情页)
  • 客户照片编辑
  • 设备照片上传
  • 设备照片预览(列表页、详情页)
  • 设备照片编辑
  • 备件图片上传
  • 备件图片预览(列表页、详情页)
  • 备件图片编辑
  • 多图片支持测试
  • 图片删除功能
  • OSS Key正确存储验证

注意事项

  1. 数据兼容性:执行SQL脚本不会影响现有数据
  2. 字段长度:所有URL和Keys字段统一为 VARCHAR(1000)
  3. 逗号分隔:多个URL或Key使用英文逗号分隔
  4. 预签名URL:URL字段存储的是临时预签名URL,有效期限制
  5. OSS Key:Keys字段存储的是永久有效的OSS对象Key
  6. 批量转换:使用 convertListToPresignedUrl 方法批量转换
  7. getter参数:第二个参数必须是 getXxxKeys 方法
  8. setter参数:第三个参数必须是 setXxxUrl 方法

常见问题

Q1: 为什么需要两个字段?

A: Keys字段永久有效,适合数据库存储;URL字段是临时的,适合前端展示。

Q2: 如何处理已有数据?

A: 执行SQL脚本后,已有数据的URL字段保留,新增Keys字段为空。需要手动迁移或通过程序转换。

Q3: 上传失败怎么办?

A: 检查OSS配置、文件大小限制、网络连接。

Q4: 如何支持更多文件格式?

A: 修改组件的 accept 属性,例如:accept=".jpg,.png,.pdf,.doc"

参考文档

  • UnifiedAttachmentUpload组件:ui/src/components/UnifiedAttachmentUpload/README.md
  • OssUtils工具类:src/main/java/com/husky/common/utils/oss/OssUtils.java
  • 客户模块实现:参考已完成的客户管理模块

更新日志

  • 2025-10-16: 完成客户模块改造
  • 2025-10-16: 添加设备和备件实体类Keys字段
  • 2025-10-16: 创建统一数据库迁移SQL脚本
  • 2025-10-16: 修复客户Service中的批量转换逻辑
作者:聂盼盼  创建时间:2025-10-16 11:13
最后编辑:聂盼盼  更新时间:2025-10-28 19:53