From 7285dd64f83c552b72b77bf6f93c96047c786eb6 Mon Sep 17 00:00:00 2001 From: zpc Date: Sat, 27 Dec 2025 13:41:33 +0800 Subject: [PATCH] 43 --- docs/1.0.5/开发改动文档.md | 649 +++++++++++++++++++++++++++++++ 1 file changed, 649 insertions(+) create mode 100644 docs/1.0.5/开发改动文档.md diff --git a/docs/1.0.5/开发改动文档.md b/docs/1.0.5/开发改动文档.md new file mode 100644 index 0000000..f0fa88f --- /dev/null +++ b/docs/1.0.5/开发改动文档.md @@ -0,0 +1,649 @@ +# v1.0.5 开发改动文档 - 支持连拍功能 + +## 一、需求概述 + +本次版本主要新增**连拍功能**,允许用户在**一条工作记录**中拍摄**多张照片**,所有照片共享相同的表单信息(位置、部门、工作内容等)。 + +### 需求要点 +1. 页面顶部增加"图片列表"区域,显示所有已拍摄图片缩略图 +2. 点击缩略图可切换预览 +3. 底部增加【继续拍照】【删除图片】按钮 +4. 所有图片统一使用第一张图片的水印信息 +5. 删除图片需二次确认 +6. **一条工作记录对应多张图片**(不是多条记录) +7. 兼容老数据(单图记录) + +--- + +## 二、数据库改动(核心) + +### 2.1 当前表结构 + +**cam_workrecord(工作记录表)** +| 字段名 | 类型 | 说明 | +|--------|------|------| +| Id | int (PK, 自增) | 主键 | +| RecordTime | datetime | 拍照时间 | +| Address | nvarchar(max) | 地址 | +| Longitude | nvarchar(100) | 经度 | +| Latitude | nvarchar(100) | 纬度 | +| Content | nvarchar(max) | 工作内容 | +| Remarks | nvarchar(max) | 备注 | +| DeptName | nvarchar(100) | 部门名称 | +| StatusName | nvarchar(100) | 状态 | +| **ImageUrl** | **nvarchar(300)** | **图片路径(单张,将废弃)** | +| CreateTime | datetime | 创建时间 | +| UpdateTime | datetime | 更新时间 | + +**cam_worker(施工人员表)** +| 字段名 | 类型 | 说明 | +|--------|------|------| +| Id | bigint (PK, 自增) | 主键 | +| WorkrecordId | int (FK) | 关联工作记录ID | +| WorkerName | nvarchar(100) | 人员姓名 | +| CreateTime | datetime | 创建时间 | +| UpdateTime | datetime | 更新时间 | + +### 2.2 新增表结构 + +**cam_workrecord_image(新增:工作记录图片表)** +| 字段名 | 类型 | 说明 | +|--------|------|------| +| Id | bigint (PK, 自增) | 主键 | +| WorkrecordId | int (FK) | 关联工作记录ID | +| ImageUrl | nvarchar(500) | 图片路径 | +| SortOrder | int | 排序(1=第一张,作为封面) | +| CreateTime | datetime | 创建时间 | +| UpdateTime | datetime | 更新时间 | + +### 2.3 建表SQL脚本 + +```sql +USE [WatermarkCamera] +GO + +-- 创建工作记录图片表 +CREATE TABLE [dbo].[cam_workrecord_image]( + [Id] [bigint] IDENTITY(1,1) NOT NULL, + [WorkrecordId] [int] NOT NULL, + [ImageUrl] [nvarchar](500) NOT NULL, + [SortOrder] [int] NOT NULL DEFAULT 1, + [CreateTime] [datetime] NOT NULL DEFAULT (getdate()), + [UpdateTime] [datetime] NOT NULL DEFAULT (getdate()), + CONSTRAINT [PK_cam_workrecord_image] PRIMARY KEY CLUSTERED ([Id] ASC) +) ON [PRIMARY] +GO + +-- 添加外键约束 +ALTER TABLE [dbo].[cam_workrecord_image] +ADD CONSTRAINT [FK_cam_workrecord_image_workrecord] +FOREIGN KEY ([WorkrecordId]) REFERENCES [dbo].[cam_workrecord]([Id]) +ON DELETE CASCADE +GO + +-- 添加索引 +CREATE NONCLUSTERED INDEX [IX_cam_workrecord_image_WorkrecordId] +ON [dbo].[cam_workrecord_image] ([WorkrecordId] ASC) +GO + +-- 添加字段说明 +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'主键', @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cam_workrecord_image', @level2type=N'COLUMN',@level2name=N'Id' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'工作记录ID', @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cam_workrecord_image', @level2type=N'COLUMN',@level2name=N'WorkrecordId' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'图片路径', @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cam_workrecord_image', @level2type=N'COLUMN',@level2name=N'ImageUrl' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'排序(1=第一张封面图)', @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cam_workrecord_image', @level2type=N'COLUMN',@level2name=N'SortOrder' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'创建时间', @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cam_workrecord_image', @level2type=N'COLUMN',@level2name=N'CreateTime' +GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'更新时间', @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'cam_workrecord_image', @level2type=N'COLUMN',@level2name=N'UpdateTime' +GO +``` + +### 2.4 老数据迁移脚本 + +> **重要**:先执行建表脚本,再执行迁移脚本 + +```sql +USE [WatermarkCamera] +GO + +-- 迁移老数据:将 cam_workrecord.ImageUrl 迁移到 cam_workrecord_image 表 +INSERT INTO [dbo].[cam_workrecord_image] + ([WorkrecordId], [ImageUrl], [SortOrder], [CreateTime], [UpdateTime]) +SELECT + [Id] AS WorkrecordId, + [ImageUrl], + 1 AS SortOrder, -- 老数据都是第一张(封面图) + ISNULL([CreateTime], GETDATE()), + ISNULL([UpdateTime], GETDATE()) +FROM [dbo].[cam_workrecord] +WHERE [ImageUrl] IS NOT NULL AND [ImageUrl] <> '' +GO + +-- 验证迁移结果 +SELECT + '迁移前 cam_workrecord 有图片记录数' AS [说明], + COUNT(*) AS [数量] +FROM [dbo].[cam_workrecord] +WHERE [ImageUrl] IS NOT NULL AND [ImageUrl] <> '' + +UNION ALL + +SELECT + '迁移后 cam_workrecord_image 记录数' AS [说明], + COUNT(*) AS [数量] +FROM [dbo].[cam_workrecord_image] +GO + +-- 注意:暂不删除 cam_workrecord.ImageUrl 字段,保持兼容性 +-- 后续版本可考虑废弃该字段 +``` + +### 2.5 数据结构示意 + +**迁移后数据示例:** + +cam_workrecord: +| Id | Content | DeptName | ImageUrl(保留兼容) | +|----|---------|----------|---------------------| +| 101 | 混凝土浇筑 | 建筑部 | /workfiles/.../img1.jpg | + +cam_workrecord_image: +| Id | WorkrecordId | ImageUrl | SortOrder | +|----|--------------|----------|-----------| +| 1 | 101 | /workfiles/.../img1.jpg | 1 | + +**新增连拍数据示例:** + +cam_workrecord: +| Id | Content | DeptName | ImageUrl(封面图) | +|----|---------|----------|-------------------| +| 102 | 模板搭建 | 建筑部 | /workfiles/.../img2.jpg | + +cam_workrecord_image: +| Id | WorkrecordId | ImageUrl | SortOrder | +|----|--------------|----------|-----------| +| 2 | 102 | /workfiles/.../img2.jpg | 1 | +| 3 | 102 | /workfiles/.../img3.jpg | 2 | +| 4 | 102 | /workfiles/.../img4.jpg | 3 | + +--- + +## 三、后端改动 + +### 3.1 改动文件清单 + +| 文件路径 | 改动说明 | +|----------|----------| +| `ZR.Model/Business/CamWorkrecordImage.cs` | **新增**:图片实体类 | +| `ZR.Model/Business/Dto/CamWorkrecordDto.cs` | 修改:DTO新增图片列表字段 | +| `ZR.Service/Business/CamWorkrecordImageService.cs` | **新增**:图片服务类 | +| `ZR.Admin.WebApi/Controllers/CommonController.cs` | 修改:接口支持多图 | +| `ZR.Admin.WebApi/Controllers/Business/CamWorkrecordController.cs` | 修改:后台接口支持多图、导出Excel | + +### 3.2 接口策略 + +> **重要说明**:原有接口需要改动,但要**保持入参兼容**! +> +> 原因:老版本APP传单张图片,新版本APP传多张图片,接口需要同时支持。 + +| 接口 | 用途 | 改动 | +|------|------|------| +| `/addworkrecord` | 单图/多图提交 | **改动**:支持多图,同时兼容单图 | +| `/addworkrecords` | 多图批量提交(可选) | **新增**(可选) | + +### 3.3 实体类改动 + +**新增 CamWorkrecordImage.cs:** +```csharp +namespace ZR.Model.Business +{ + /// + /// 工作记录图片 + /// + [SugarTable("cam_workrecord_image")] + public class CamWorkrecordImage + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long Id { get; set; } + + /// + /// 工作记录ID + /// + public int WorkrecordId { get; set; } + + /// + /// 图片路径 + /// + public string ImageUrl { get; set; } + + /// + /// 排序(1=第一张封面图) + /// + public int SortOrder { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreateTime { get; set; } + + /// + /// 更新时间 + /// + public DateTime UpdateTime { get; set; } + } +} +``` + +### 3.4 DTO改动 + +**CamWorkrecordDto.cs 修改:** +```csharp +public class CamRecordWorkDto +{ + public int? Id { get; set; } + public string DeptName { get; set; } + + /// + /// 单张图片Base64(兼容老版本APP) + /// + public string Image { get; set; } + + /// + /// 多张图片Base64数组(新版本APP使用) + /// + public List Images { get; set; } + + public string ImageUrl { get; set; } + public DateTime? RecordTime { get; set; } + public string Longitude { get; set; } + public string Latitude { get; set; } + public string Address { get; set; } + public string Content { get; set; } + public string StatusName { get; set; } + public string Remarks { get; set; } + public List Workers { get; set; } +} + +/// +/// 工作记录图片DTO +/// +public class CamWorkrecordImageDto +{ + public long Id { get; set; } + public int WorkrecordId { get; set; } + public string ImageUrl { get; set; } + public int SortOrder { get; set; } +} +``` + +### 3.5 接口改动逻辑 + +**CommonController.cs - AddCamWorkRecord 改动:** +```csharp +[HttpPost] +[Route("/addworkrecord")] +[AllowAnonymous] +public async Task AddCamWorkRecord([FromBody] CamRecordWorkDto parm) +{ + // 1. 参数校验 + if (parm.Workers == null || parm.Workers.Count == 0) + return ToResponse(ResultCode.PARAM_ERROR, "请选择工作人员"); + + // 2. 获取图片列表(兼容新旧版本) + var imageList = new List(); + if (parm.Images != null && parm.Images.Count > 0) + { + // 新版本APP:多张图片 + imageList = parm.Images; + } + else if (!string.IsNullOrEmpty(parm.Image)) + { + // 老版本APP:单张图片 + imageList.Add(parm.Image); + } + else if (string.IsNullOrEmpty(parm.ImageUrl)) + { + return ToResponse(ResultCode.PARAM_ERROR, "请上传图片"); + } + + // 3. 保存工作记录(只保存一条) + var modal = parm.Adapt().ToCreate(HttpContext); + modal.CreateTime = DateTime.Now; + modal.UpdateTime = DateTime.Now; + + // 4. 处理图片并保存到 cam_workrecord_image 表 + var savedImageUrls = new List(); + int sortOrder = 1; + foreach (var imageBase64 in imageList) + { + var imageUrl = await SaveImageFile(imageBase64, parm); + savedImageUrls.Add(imageUrl); + + // 保存图片记录 + var imageRecord = new CamWorkrecordImage + { + WorkrecordId = modal.Id, + ImageUrl = imageUrl, + SortOrder = sortOrder++, + CreateTime = DateTime.Now, + UpdateTime = DateTime.Now + }; + await _CamWorkrecordImageService.InsertAsync(imageRecord); + } + + // 5. 更新主表的 ImageUrl(封面图,兼容老逻辑) + if (savedImageUrls.Count > 0) + { + modal.ImageUrl = savedImageUrls[0]; + await _CamWorkrecordService.UpdateAsync(modal); + } + + // 6. 保存施工人员 + // ... 原有逻辑 + + return SUCCESS(new { id = modal.Id, imageCount = savedImageUrls.Count }); +} +``` + +### 3.6 后台接口改动 + +**CamWorkrecordController.cs 需要改动:** + +1. **查询详情**:返回图片列表 +```csharp +[HttpGet("{Id}")] +public IActionResult GetCamWorkrecord(int Id) +{ + var response = _CamWorkrecordService.GetInfo(Id); + var info = response.Adapt(); + + // 获取图片列表 + var images = _CamWorkrecordImageService.GetList(Id); + info.Images = images.Select(x => x.ImageUrl).ToList(); + + // ... 其他逻辑 + return SUCCESS(info); +} +``` + +2. **导出Excel**:支持多图(显示第一张或全部) +```csharp +// 导出时获取每条记录的所有图片 +// 可选方案:只显示第一张,或合并显示所有图片路径 +``` + +3. **删除记录**:级联删除图片 +```csharp +// 删除工作记录时,cam_workrecord_image 会自动级联删除(外键约束) +``` + +### 3.7 兼容性说明 + +| 场景 | 处理方式 | +|------|----------| +| 老版本APP传 `Image` 字段 | 兼容,转为单元素数组处理 | +| 新版本APP传 `Images` 数组 | 正常处理多图 | +| 老数据查询 | 从 `cam_workrecord_image` 表读取(已迁移) | +| 新数据查询 | 从 `cam_workrecord_image` 表读取 | +| `ImageUrl` 字段 | 保留作为封面图,兼容老代码 | + +--- + +## 四、后台管理改动 + +### 4.1 改动文件 + +| 文件路径 | 改动说明 | +|----------|----------| +| `ZR.Vue/src/views/business/CamWorkrecord.vue` | 列表/详情显示多图 | +| `ZR.Vue/src/api/business/camworkrecord.js` | API调整(可选) | + +### 4.2 列表页改动 + +**显示图片数量或缩略图列表:** +```html + + + +``` + +### 4.3 详情页改动 + +**显示所有图片:** +```html + + + +``` + +### 4.4 编辑页改动 + +> **确认需求**:允许增删图片 + +**支持多图上传/管理:** +- 显示现有图片列表(带排序序号) +- 支持添加新图片(限制最多15张) +- 支持删除图片(至少保留1张) +- 支持拖拽排序(可选) + +**UI示例:** +```html + +
+ +
+ + {{ index + 1 }} + + +
+ + + + 添加图片 + + +
+ 已上传 {{ form.images.length }}/15 张图片 +
+
+
+``` + +**后端接口改动:** +- 编辑时需要支持:新增图片、删除图片、更新排序 +- 可采用"先删后增"策略:删除原有图片记录,重新插入新的图片列表 + +### 4.5 导出Excel改动 + +> **确认需求**:导出本记录的所有图片 + +**实现方案:** +- 每条记录可能有多张图片,需要调整Excel布局 +- 方案1:多张图片横向排列在同一单元格(推荐) +- 方案2:多张图片纵向排列,合并其他列单元格 + +**代码改动思路:** +```csharp +// 导出时获取每条记录的所有图片 +var images = _CamWorkrecordImageService.GetListByWorkrecordId(item.Id); + +// 计算需要的列宽或行高 +int imageCount = images.Count; +int imageWidth = 100; // 单张图片宽度 +int totalWidth = imageWidth * Math.Min(imageCount, 5); // 最多显示5张,超出换行 + +// 将多张图片绘制到Excel单元格中 +foreach (var img in images) +{ + // 绘制图片... +} +``` + +**注意事项:** +- 图片过多时Excel文件会很大,建议压缩图片质量 +- 考虑增加"图片数量"列,方便查看 + +--- + +## 五、前端APP改动 + +### 5.1 改动文件 + +| 文件路径 | 改动说明 | +|----------|----------| +| `uniapp/WorkCameraf/pages/index/index.vue` | 主要改动,UI和逻辑 | +| `uniapp/WorkCameraf/common/utils.js` | 水印处理调整 | +| `uniapp/WorkCameraf/common/server.js` | 接口调用参数调整 | + +### 5.2 数据结构改动 + +```javascript +data() { + return { + imageList: [], // 图片列表 [{original: '', watermark: '', id: ''}] + currentIndex: 0, // 当前选中图片索引 + maxImageCount: 15, // 最大图片数量限制 + // ...其他字段保持不变 + } +} +``` + +### 5.3 继续拍照限制 + +```javascript +async continueCapture() { + // 检查是否达到最大数量 + if (this.imageList.length >= this.maxImageCount) { + uni.showToast({ + title: '最多只能拍摄15张图片', + icon: 'none' + }) + return + } + // ... 继续拍照逻辑 +} +``` + +### 5.4 提交数据改动 + +```javascript +async submitData() { + const images = this.imageList.map(item => item.watermark) + + const params = { + // ... 其他字段 + Images: images, // 新增:多张图片数组 + // Image: xxx, // 不再使用单张字段 + } + + await addWatermarkRecord(params) +} +``` + +--- + +## 六、开发任务清单 + +### 6.1 数据库任务 + +- [ ] 1. 执行建表脚本(cam_workrecord_image) +- [ ] 2. 执行老数据迁移脚本 +- [ ] 3. 验证迁移结果 + +### 6.2 后端任务 + +- [ ] 1. 新增 `CamWorkrecordImage` 实体类 +- [ ] 2. 新增 `ICamWorkrecordImageService` 服务接口和实现 +- [ ] 3. 修改 `CamRecordWorkDto`,新增 `Images` 字段 +- [ ] 4. 修改 `/addworkrecord` 接口,支持多图(兼容单图) +- [ ] 5. 修改查询接口,返回图片列表 +- [ ] 6. 修改删除接口,确保级联删除图片 +- [ ] 7. 修改导出Excel,处理多图场景 +- [ ] 8. 接口测试 + +### 6.3 后台前端任务 + +- [ ] 1. 列表页:显示图片数量或缩略图 +- [ ] 2. 详情页:显示所有图片 +- [ ] 3. 编辑页:支持多图管理 +- [ ] 4. 测试验证 + +### 6.4 APP前端任务 + +- [ ] 1. 修改数据结构,支持图片列表 +- [ ] 2. 添加图片列表UI组件 +- [ ] 3. 实现图片切换功能 +- [ ] 4. 实现继续拍照功能 +- [ ] 5. 实现删除图片功能(含二次确认) +- [ ] 6. 修改提交逻辑,传 `Images` 数组 +- [ ] 7. 样式调整和优化 +- [ ] 8. H5端测试 +- [ ] 9. APP端测试 + +--- + +## 七、需求确认事项 + +| 序号 | 问题 | 确认结果 | 状态 | +|------|------|----------|------| +| 1 | 连拍最多支持几张图片? | **最多15张** | ✅ 已确认 | +| 2 | 后台导出Excel是否需要导出所有图片? | **导出本记录的所有图片** | ✅ 已确认 | +| 3 | 后台编辑时是否允许增删图片? | **允许增删图片** | ✅ 已确认 | +| 4 | 是否需要删除 `cam_workrecord.ImageUrl` 字段? | **保留兼容,需写迁移脚本** | ✅ 已确认 | +| 5 | 图片文件存储路径是否需要调整? | **保持现有结构** | ✅ 已确认 | + +--- + +## 八、风险评估 + +| 风险项 | 风险等级 | 应对措施 | +|--------|----------|----------| +| 老数据迁移失败 | 高 | 迁移前备份数据库,验证迁移结果 | +| 老版本APP不兼容 | 中 | 接口保持入参兼容,支持单图和多图 | +| 多图上传超时 | 中 | 前端压缩,限制图片数量和大小 | +| 后台显示异常 | 中 | 兼容处理无图片或单图场景 | + +--- + +## 九、版本计划 + +- 数据库迁移:上线前执行 +- 开发周期:待定 +- 测试周期:待定 +- 上线时间:待定 + +--- + +**文档版本**:v2.0 +**编写日期**:2025-12-27 +**编写人**:Claude AI Assistant