diff --git a/fad-rolling-mill/src/main/java/com/ruoyi/rm/controller/RmFileReviewController.java b/fad-rolling-mill/src/main/java/com/ruoyi/rm/controller/RmFileReviewController.java new file mode 100644 index 0000000..b394b01 --- /dev/null +++ b/fad-rolling-mill/src/main/java/com/ruoyi/rm/controller/RmFileReviewController.java @@ -0,0 +1,35 @@ +package com.ruoyi.rm.controller; + +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.rm.domain.bo.RmFileReviewBo; +import com.ruoyi.rm.domain.vo.RmFileReviewVo; +import com.ruoyi.rm.service.IRmFileReviewService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/rm/fileReview") +public class RmFileReviewController extends BaseController { + + private final IRmFileReviewService fileReviewService; + + @GetMapping("/list") + public R> list(String fileModule, Long fileId) { + return R.ok(fileReviewService.queryByFile(fileModule, fileId)); + } + + @PostMapping + public R add(@RequestBody RmFileReviewBo bo) { + return R.ok(fileReviewService.addReview(bo)); + } +} diff --git a/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/bo/RmFileReviewBo.java b/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/bo/RmFileReviewBo.java new file mode 100644 index 0000000..9c141a8 --- /dev/null +++ b/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/bo/RmFileReviewBo.java @@ -0,0 +1,16 @@ +package com.ruoyi.rm.domain.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class RmFileReviewBo extends BaseEntity { + private Long id; + private Long fileId; + private String fileModule; + private Long reviewerId; + private String content; + private String reviewAction; +} diff --git a/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/entity/RmFileReview.java b/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/entity/RmFileReview.java new file mode 100644 index 0000000..97172b3 --- /dev/null +++ b/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/entity/RmFileReview.java @@ -0,0 +1,27 @@ +package com.ruoyi.rm.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("fad_rm_file_review") +public class RmFileReview extends BaseEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId + private Long id; + private Long fileId; + private String fileModule; + private Long reviewerId; + private String content; + private String reviewAction; + @TableLogic + private Integer delFlag; +} diff --git a/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/vo/RmFileReviewVo.java b/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/vo/RmFileReviewVo.java new file mode 100644 index 0000000..fca2129 --- /dev/null +++ b/fad-rolling-mill/src/main/java/com/ruoyi/rm/domain/vo/RmFileReviewVo.java @@ -0,0 +1,23 @@ +package com.ruoyi.rm.domain.vo; + +import com.ruoyi.common.core.domain.entity.SysUser; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +@Data +public class RmFileReviewVo implements Serializable { + private static final long serialVersionUID = 1L; + + private Long id; + private Long fileId; + private String fileModule; + private Long reviewerId; + private String content; + private String reviewAction; + private Date createTime; + + /** 审核人姓名(从 sys_user 关联) */ + private String reviewerName; +} diff --git a/fad-rolling-mill/src/main/java/com/ruoyi/rm/mapper/RmFileReviewMapper.java b/fad-rolling-mill/src/main/java/com/ruoyi/rm/mapper/RmFileReviewMapper.java new file mode 100644 index 0000000..1530865 --- /dev/null +++ b/fad-rolling-mill/src/main/java/com/ruoyi/rm/mapper/RmFileReviewMapper.java @@ -0,0 +1,8 @@ +package com.ruoyi.rm.mapper; + +import com.ruoyi.common.core.mapper.BaseMapperPlus; +import com.ruoyi.rm.domain.entity.RmFileReview; +import com.ruoyi.rm.domain.vo.RmFileReviewVo; + +public interface RmFileReviewMapper extends BaseMapperPlus { +} diff --git a/fad-rolling-mill/src/main/java/com/ruoyi/rm/service/IRmFileReviewService.java b/fad-rolling-mill/src/main/java/com/ruoyi/rm/service/IRmFileReviewService.java new file mode 100644 index 0000000..c0d7fdb --- /dev/null +++ b/fad-rolling-mill/src/main/java/com/ruoyi/rm/service/IRmFileReviewService.java @@ -0,0 +1,13 @@ +package com.ruoyi.rm.service; + +import com.ruoyi.rm.domain.bo.RmFileReviewBo; +import com.ruoyi.rm.domain.vo.RmFileReviewVo; + +import java.util.List; + +public interface IRmFileReviewService { + + List queryByFile(String fileModule, Long fileId); + + RmFileReviewVo addReview(RmFileReviewBo bo); +} diff --git a/fad-rolling-mill/src/main/java/com/ruoyi/rm/service/impl/RmFileReviewServiceImpl.java b/fad-rolling-mill/src/main/java/com/ruoyi/rm/service/impl/RmFileReviewServiceImpl.java new file mode 100644 index 0000000..5687d57 --- /dev/null +++ b/fad-rolling-mill/src/main/java/com/ruoyi/rm/service/impl/RmFileReviewServiceImpl.java @@ -0,0 +1,58 @@ +package com.ruoyi.rm.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.helper.LoginHelper; +import com.ruoyi.rm.domain.bo.RmFileReviewBo; +import com.ruoyi.rm.domain.entity.RmFileReview; +import com.ruoyi.rm.domain.vo.RmFileReviewVo; +import com.ruoyi.rm.mapper.RmFileReviewMapper; +import com.ruoyi.rm.service.IRmFileReviewService; +import com.ruoyi.system.mapper.SysUserMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class RmFileReviewServiceImpl implements IRmFileReviewService { + + private final RmFileReviewMapper baseMapper; + private final SysUserMapper sysUserMapper; + + @Override + public List queryByFile(String fileModule, Long fileId) { + List list = baseMapper.selectVoList( + Wrappers.lambdaQuery() + .eq(RmFileReview::getFileModule, fileModule) + .eq(RmFileReview::getFileId, fileId) + .orderByAsc(RmFileReview::getCreateTime)); + for (RmFileReviewVo vo : list) { + if (vo.getReviewerId() != null) { + SysUser user = sysUserMapper.selectUserById(vo.getReviewerId()); + if (user != null) { + vo.setReviewerName(user.getNickName()); + } + } + } + return list; + } + + @Override + public RmFileReviewVo addReview(RmFileReviewBo bo) { + Long userId = LoginHelper.getUserId(); + if (userId == null) { + throw new RuntimeException("未登录"); + } + RmFileReview entity = BeanUtil.toBean(bo, RmFileReview.class); + entity.setReviewerId(userId); + baseMapper.insert(entity); + + RmFileReviewVo vo = BeanUtil.toBean(entity, RmFileReviewVo.class); + SysUser user = sysUserMapper.selectUserById(userId); + vo.setReviewerName(user != null ? user.getNickName() : null); + return vo; + } +} diff --git a/ruoyi-ui/src/api/oa/task.js b/ruoyi-ui/src/api/oa/task.js index 149429b..a1237c0 100644 --- a/ruoyi-ui/src/api/oa/task.js +++ b/ruoyi-ui/src/api/oa/task.js @@ -122,3 +122,21 @@ export function delTask(taskId) { method: 'delete' }) } + +// 按总包项目+阶段查询任务 +export function listRmTask(projectId, stageCode) { + return request({ + url: '/oa/task/rm/tasks', + method: 'get', + params: { projectId, stageCode } + }) +} + +// 按总包项目统计各阶段任务数 +export function taskCountByStage(projectId) { + return request({ + url: '/oa/task/rm/taskCount', + method: 'get', + params: { projectId } + }) +} diff --git a/ruoyi-ui/src/api/rm/fileReview.js b/ruoyi-ui/src/api/rm/fileReview.js new file mode 100644 index 0000000..276fc8c --- /dev/null +++ b/ruoyi-ui/src/api/rm/fileReview.js @@ -0,0 +1,17 @@ +import request from '@/utils/request' + +export function listFileReview(fileModule, fileId) { + return request({ + url: '/rm/fileReview/list', + method: 'get', + params: { fileModule, fileId } + }) +} + +export function addFileReview(data) { + return request({ + url: '/rm/fileReview', + method: 'post', + data + }) +} diff --git a/ruoyi-ui/src/views/oa/task/allocation/index.vue b/ruoyi-ui/src/views/oa/task/allocation/index.vue index 0bddd69..bd7bb31 100644 --- a/ruoyi-ui/src/views/oa/task/allocation/index.vue +++ b/ruoyi-ui/src/views/oa/task/allocation/index.vue @@ -177,6 +177,26 @@ + + + + + + + + + + + + + + + + + + + + - +
{{ selected ? selected.drawingName : '选择图纸预览' }} @@ -62,23 +62,69 @@ 编辑
- -
- - 图号{{ selected.drawingNo || '-' }} - 图纸类型{{ selected.drawingType || '-' }} - 版本{{ selected.version || '-' }} - - - 设计人{{ selected.drawer || '-' }} - 设计日期{{ selected.startDate || '-' }} - 完成日期{{ selected.endDate || '-' }} - - - 状态{{ statusLabel(selected.status) }} - 备注{{ selected.remark || '-' }} - -
+ + + +
+
图号{{ selected.drawingNo || '-' }}
+
图纸类型{{ selected.drawingType || '-' }}
+
版本{{ selected.version || '-' }}
+
设计人{{ selected.drawer || '-' }}
+
设计日期{{ selected.startDate || '-' }}
+
完成日期{{ selected.endDate || '-' }}
+
状态{{ statusLabel(selected.status) }}
+
备注{{ selected.remark }}
+
+
+ + + 发表意见 + + +
+
+ {{ item.reviewerName }} + {{ item.reviewAction }} +
+

{{ item.content }}

+
+
+
+
+ + 暂无审核意见 +
+
+ + +
+
+
+ {{ t.taskTitle }} + 完成 + 待验收 + 进行中 +
+
+ 执行人: {{ t.workerNickName }} + 发起人: {{ t.createUserNickName }} +
+
+
+
+ + 暂无关联任务 +
+
+
@@ -89,6 +135,26 @@
+ + + + + + + + + + + + + + + + + @@ -185,6 +251,8 @@ @@ -340,12 +457,26 @@ export default { .right-header { padding: 8px 12px; font-size: 14px; font-weight: 600; border-bottom: 1px solid #d0d7de; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } .right-actions { display: flex; gap: 4px; } -/* Detail card */ -.detail-card { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; } -.info-row { margin-bottom: 6px; } -.info-label { font-size: 11px; color: #909399; margin-right: 6px; } -.info-value { font-size: 12px; color: #333; } -.text-ellipsis { display: inline-block; max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; } +/* Collapse info + review */ +.info-collapse { flex-shrink: 0; } +.info-collapse >>> .el-collapse-item__header { padding: 0 12px; font-size: 13px; font-weight: 600; height: 36px; } +.info-collapse >>> .el-collapse-item__wrap { border-bottom: 1px solid #e8eaed; } +.info-collapse >>> .el-collapse-item__content { padding: 8px 12px 10px; } +.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 16px; } +.detail-item { display: flex; font-size: 12px; line-height: 1.8; } +.detail-label { color: #909399; width: 55px; flex-shrink: 0; } +.detail-value { color: #333; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.review-item-header { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; } +.review-item-header strong { font-size: 13px; } +.review-item-content { font-size: 12px; color: #555; margin: 2px 0 0; line-height: 1.5; white-space: pre-wrap; } +.review-empty { text-align: center; color: #c0c4cc; font-size: 13px; padding: 8px 0; display: flex; flex-direction: column; align-items: center; gap: 4px; } +.review-action-tag { font-size: 11px; } +.info-collapse >>> .el-timeline-item__timestamp { font-size: 12px; color: #999; } +.task-list { display: flex; flex-direction: column; gap: 6px; } +.task-item { background: #f8f9fa; border-radius: 4px; padding: 6px 8px; } +.task-item-header { display: flex; align-items: center; justify-content: space-between; gap: 4px; } +.task-item-title { font-size: 12px; font-weight: 600; color: #333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; } +.task-item-meta { font-size: 11px; color: #909399; margin-top: 2px; display: flex; gap: 8px; } /* Viewer */ .viewer-area { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; } diff --git a/ruoyi-ui/src/views/rm/layout/index.vue b/ruoyi-ui/src/views/rm/layout/index.vue index afff75f..681abb1 100644 --- a/ruoyi-ui/src/views/rm/layout/index.vue +++ b/ruoyi-ui/src/views/rm/layout/index.vue @@ -48,7 +48,7 @@ @size-change="handleSizeChange" @current-change="handlePageChange" /> - +
{{ selectedFile ? selectedFile.fileName : '选择文件预览' }} @@ -56,6 +56,88 @@ 下载
+ + + +
+
+ 文件名 + {{ selectedFile.fileName }} +
+
+ 类型 + {{ selectedFile.fileType }} +
+
+ 版本 + {{ selectedFile.version || '-' }} +
+
+ 上传日期 + {{ selectedFile.uploadDate || '-' }} +
+
+ 状态 + + {{ statusLabel(selectedFile.status) }} + +
+
+ 备注 + {{ selectedFile.remark }} +
+
+
+ + + 发表意见 + + +
+
+ {{ item.reviewerName }} + {{ item.reviewAction }} +
+

{{ item.content }}

+
+
+
+
+ + 暂无审核意见 +
+
+ + +
+
+
+ {{ t.taskTitle }} + 完成 + 待验收 + 进行中 +
+
+ 执行人: {{ t.workerNickName }} + 发起人: {{ t.createUserNickName }} +
+
+
+
+ + 暂无关联任务 +
+
+
+
@@ -131,12 +213,34 @@ 保存
+ + + + + + + + + + + + + + + + +
@@ -304,7 +457,30 @@ export default { .right-panel { flex: 1; background: #fff; border-radius: 4px; border: 1px solid #d0d7de; display: flex; flex-direction: column; min-width: 0; } .right-header { padding: 8px 12px; font-size: 14px; font-weight: 600; border-bottom: 1px solid #d0d7de; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } .right-actions { display: flex; gap: 4px; } -.viewer-area { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; } + +/* Collapse info + review */ +.info-collapse { flex-shrink: 0; } +.info-collapse >>> .el-collapse-item__header { padding: 0 12px; font-size: 13px; font-weight: 600; height: 36px; } +.info-collapse >>> .el-collapse-item__wrap { border-bottom: 1px solid #e8eaed; } +.info-collapse >>> .el-collapse-item__content { padding: 8px 12px 10px; } +.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 16px; } +.detail-item { display: flex; font-size: 12px; line-height: 1.8; } +.detail-label { color: #909399; width: 65px; flex-shrink: 0; } +.detail-value { color: #333; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.review-item-header { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; } +.review-item-header strong { font-size: 13px; } +.review-item-content { font-size: 12px; color: #555; margin: 2px 0 0; line-height: 1.5; white-space: pre-wrap; } +.review-empty { text-align: center; color: #c0c4cc; font-size: 13px; padding: 8px 0; display: flex; flex-direction: column; align-items: center; gap: 4px; } +.review-action-tag { font-size: 11px; } +.info-collapse >>> .el-timeline-item__timestamp { font-size: 12px; color: #999; } +.task-list { display: flex; flex-direction: column; gap: 6px; } +.task-item { background: #f8f9fa; border-radius: 4px; padding: 6px 8px; } +.task-item-header { display: flex; align-items: center; justify-content: space-between; gap: 4px; } +.task-item-title { font-size: 12px; font-weight: 600; color: #333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; } +.task-item-meta { font-size: 11px; color: #909399; margin-top: 2px; display: flex; gap: 8px; } + +/* Viewer */ +.viewer-area { flex: 1; min-height: 200px; display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; } .viewer-area > iframe { width: 100%; height: 100%; border: 0; } .viewer-placeholder { text-align: center; } diff --git a/ruoyi-ui/src/views/rm/manuals/index.vue b/ruoyi-ui/src/views/rm/manuals/index.vue index 933c5ac..dc8e22b 100644 --- a/ruoyi-ui/src/views/rm/manuals/index.vue +++ b/ruoyi-ui/src/views/rm/manuals/index.vue @@ -42,7 +42,7 @@ - +
{{ selected ? selected.manualName : '选择文件预览' }} @@ -51,17 +51,42 @@ 编辑
- -
- - 类型{{ selected.docType }} - 版本{{ selected.version || '-' }} - 上传日期{{ selected.uploadDate || '-' }} - - - 描述{{ selected.description }} - -
+ + + +
+
类型{{ selected.docType }}
+
版本{{ selected.version || '-' }}
+
上传日期{{ selected.uploadDate || '-' }}
+
描述{{ selected.description }}
+
+
+ + + 发表意见 + + +
+
+ {{ item.reviewerName }} + {{ item.reviewAction }} +
+

{{ item.content }}

+
+
+
+
+ + 暂无审核意见 +
+
+
@@ -72,6 +97,26 @@
+ + + + + + + + + + + + + + + + + @@ -120,6 +165,8 @@ @@ -286,11 +374,21 @@ export default { .right-header { padding: 8px 12px; font-size: 14px; font-weight: 600; border-bottom: 1px solid #d0d7de; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } .right-actions { display: flex; gap: 4px; } -/* Detail card */ -.detail-card { padding: 10px 12px; border-bottom: 1px solid #f0f0f0; flex-shrink: 0; } -.info-row { margin-bottom: 6px; } -.info-label { font-size: 11px; color: #909399; margin-right: 6px; } -.info-value { font-size: 12px; color: #333; } +/* Collapse info + review */ +.info-collapse { flex-shrink: 0; } +.info-collapse >>> .el-collapse-item__header { padding: 0 12px; font-size: 13px; font-weight: 600; height: 36px; } +.info-collapse >>> .el-collapse-item__wrap { border-bottom: 1px solid #e8eaed; } +.info-collapse >>> .el-collapse-item__content { padding: 8px 12px 10px; } +.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 16px; } +.detail-item { display: flex; font-size: 12px; line-height: 1.8; } +.detail-label { color: #909399; width: 65px; flex-shrink: 0; } +.detail-value { color: #333; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.review-item-header { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; } +.review-item-header strong { font-size: 13px; } +.review-item-content { font-size: 12px; color: #555; margin: 2px 0 0; line-height: 1.5; white-space: pre-wrap; } +.review-empty { text-align: center; color: #c0c4cc; font-size: 13px; padding: 8px 0; display: flex; flex-direction: column; align-items: center; gap: 4px; } +.review-action-tag { font-size: 11px; } +.info-collapse >>> .el-timeline-item__timestamp { font-size: 12px; color: #999; } /* Viewer */ .viewer-area { flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; }