Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X
This commit is contained in:
25
docs/sql_align_databases.sql
Normal file
25
docs/sql_align_databases.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
-- =============================================================
|
||||
-- 线上线下库对齐修复脚本
|
||||
-- 用于 klp-oa(线上)和 klp-oa-test(线下)
|
||||
-- =============================================================
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- ==================== 第一部分:补字典(两边都执行) ====================
|
||||
|
||||
-- 1.1 regrade_quality_type 字典类型
|
||||
INSERT IGNORE INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, update_by, update_time, remark)
|
||||
VALUES ('改判后质量状态', 'regrade_quality_type', '0', 'admin', NOW(), 'admin', NOW(), '');
|
||||
|
||||
-- 1.2 regrade_quality_type 字典数据
|
||||
INSERT IGNORE INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (1, '协议销售', 'protocol_sale', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW()),
|
||||
(2, '转分剪', 'to_slitting', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW()),
|
||||
(3, '降级', 'downgrade', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW()),
|
||||
(4, '返修', 'rework', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW()),
|
||||
(5, '报废', 'scrap', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW());
|
||||
|
||||
-- 1.3 quality_review_status 补充缺失数据
|
||||
INSERT IGNORE INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (2, '待审批', '2', 'quality_review_status', '', 'warning', 'Y', '0', 'admin', NOW()),
|
||||
(3, '已通过', '3', 'quality_review_status', '', 'success', 'Y', '0', 'admin', NOW()),
|
||||
(4, '已驳回', '4', 'quality_review_status', '', 'danger', 'Y', '0', 'admin', NOW());
|
||||
51
docs/sql_align_databases_v2.sql
Normal file
51
docs/sql_align_databases_v2.sql
Normal file
@@ -0,0 +1,51 @@
|
||||
-- =============================================================
|
||||
-- 线上线下库对齐修复(修复版v2)
|
||||
-- 适配 dict_code / dict_id 非自增的表结构
|
||||
-- =============================================================
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- ==================== 1. 补字典类型 ====================
|
||||
SET @max_dict_id = (SELECT COALESCE(MAX(dict_id), 0) FROM sys_dict_type);
|
||||
|
||||
INSERT IGNORE INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time)
|
||||
VALUES (@max_dict_id + 1, '改判后质量状态', 'regrade_quality_type', '0', 'admin', NOW());
|
||||
|
||||
-- ==================== 2. 补字典数据 ====================
|
||||
SET @max_code = (SELECT COALESCE(MAX(dict_code), 0) FROM sys_dict_data);
|
||||
SET @code = @max_code + 1;
|
||||
|
||||
-- quality_review_status 缺失的3条
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 2, '待审批', '2', 'quality_review_status', '', 'warning', 'Y', '0', 'admin', NOW());
|
||||
SET @code = @code + 1;
|
||||
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 3, '已通过', '3', 'quality_review_status', '', 'success', 'Y', '0', 'admin', NOW());
|
||||
SET @code = @code + 1;
|
||||
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 4, '已驳回', '4', 'quality_review_status', '', 'danger', 'Y', '0', 'admin', NOW());
|
||||
SET @code = @code + 1;
|
||||
|
||||
-- regrade_quality_type 5条
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 1, '协议销售', 'protocol_sale', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW());
|
||||
SET @code = @code + 1;
|
||||
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 2, '转分剪', 'to_slitting', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW());
|
||||
SET @code = @code + 1;
|
||||
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 3, '降级', 'downgrade', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW());
|
||||
SET @code = @code + 1;
|
||||
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 4, '返修', 'rework', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW());
|
||||
SET @code = @code + 1;
|
||||
|
||||
INSERT IGNORE INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES (@code, 5, '报废', 'scrap', 'regrade_quality_type', '', '', 'Y', '0', 'admin', NOW());
|
||||
|
||||
-- ==================== 3. 验证 ====================
|
||||
SELECT 'Dict fix OK' AS result;
|
||||
69
docs/sql_align_dev.sql
Normal file
69
docs/sql_align_dev.sql
Normal file
@@ -0,0 +1,69 @@
|
||||
-- =============================================================
|
||||
-- 线下库 klp-oa-test 菜单对齐修复
|
||||
-- 将质量评审菜单从"质量管理"下移到"评审流程"目录下
|
||||
-- 并补充次品钢卷、O级卷菜单
|
||||
-- =============================================================
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- ==================== 1. 清理旧的质量评审菜单 ====================
|
||||
DELETE FROM sys_role_menu WHERE menu_id IN (2100000000000000036,2100000000000000037,2100000000000000038,2100000000000000039,2100000000000000040,2100000000000000041,2100000000000000042,2100000000000000043);
|
||||
DELETE FROM sys_menu WHERE menu_id IN (2100000000000000036,2100000000000000037,2100000000000000038,2100000000000000039,2100000000000000040,2100000000000000041,2100000000000000042,2100000000000000043);
|
||||
|
||||
-- 计算可用菜单ID
|
||||
SET @max_id = (SELECT COALESCE(MAX(menu_id), 0) FROM sys_menu);
|
||||
|
||||
-- ==================== 2. 创建"评审流程"目录(挂在质量管理下) ====================
|
||||
SET @parent_quality = 2068954238598967297; -- 质量管理
|
||||
SET @id_review_dir = @max_id + 1;
|
||||
INSERT IGNORE INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, is_frame, is_cache, menu_type, visible, status, icon, create_by, create_time, update_by, update_time)
|
||||
VALUES (@id_review_dir, '评审流程', @parent_quality, 5, 'review', 1, 0, 'M', '0', '0', 'guide', 'admin', NOW(), 'admin', NOW());
|
||||
|
||||
-- ==================== 3. 在评审流程下创建子菜单 ====================
|
||||
SET @parent = @id_review_dir;
|
||||
SET @id = @max_id + 2;
|
||||
|
||||
-- 次品钢卷 (order=4)
|
||||
INSERT IGNORE INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, icon, create_by, create_time)
|
||||
VALUES (@id, '次品钢卷', @parent, 4, 'rubbish', 'wms/coil/views/scrap', 1, 0, 'C', '0', '0', 'checkbox', 'admin', NOW());
|
||||
SET @id = @id + 1;
|
||||
|
||||
-- O级卷 (order=5)
|
||||
INSERT IGNORE INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, icon, create_by, create_time)
|
||||
VALUES (@id, 'O级卷', @parent, 5, 'jishu', 'wms/coil/views/jishu', 1, 0, 'C', '0', '0', 'checkbox', 'admin', NOW());
|
||||
SET @id = @id + 1;
|
||||
|
||||
-- 质量评审 (order=6)
|
||||
SET @id_review_menu = @id;
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
|
||||
VALUES (@id_review_menu, '质量评审', @parent, 6, 'qualityReview', 'mes/qc/qualityReview/index', 1, 0, 'C', '0', '0', 'qc:qualityReview:list', 'guide', 'admin', NOW());
|
||||
SET @id = @id + 1;
|
||||
|
||||
-- 质量评审待审批 (order=7, 隐藏)
|
||||
SET @id_review_todo = @id;
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
|
||||
VALUES (@id_review_todo, '质量评审待审批', @parent, 7, 'qualityReviewTodo', 'mes/qc/qualityReview/todo', 1, 0, 'C', '1', '0', 'qc:qualityReview:approve', 'checkbox', 'admin', NOW());
|
||||
SET @id = @id + 1;
|
||||
|
||||
-- ==================== 4. 按钮权限(挂在质量评审菜单下) ====================
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, menu_type, visible, status, perms, create_by, create_time)
|
||||
VALUES (@id, '质量评审新增', @id_review_menu, 1, 'F', '0', '0', 'qc:qualityReview:add', 'admin', NOW()); SET @id = @id + 1;
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, menu_type, visible, status, perms, create_by, create_time)
|
||||
VALUES (@id, '质量评审修改', @id_review_menu, 2, 'F', '0', '0', 'qc:qualityReview:edit', 'admin', NOW()); SET @id = @id + 1;
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, menu_type, visible, status, perms, create_by, create_time)
|
||||
VALUES (@id, '质量评审删除', @id_review_menu, 3, 'F', '0', '0', 'qc:qualityReview:delete', 'admin', NOW()); SET @id = @id + 1;
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, menu_type, visible, status, perms, create_by, create_time)
|
||||
VALUES (@id, '质量评审提交送审', @id_review_menu, 4, 'F', '0', '0', 'qc:qualityReview:submit', 'admin', NOW()); SET @id = @id + 1;
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, menu_type, visible, status, perms, create_by, create_time)
|
||||
VALUES (@id, '质量评审审批', @id_review_menu, 5, 'F', '0', '0', 'qc:qualityReview:approve', 'admin', NOW()); SET @id = @id + 1;
|
||||
INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, menu_type, visible, status, perms, create_by, create_time)
|
||||
VALUES (@id, '质量评审执行改判', @id_review_menu, 6, 'F', '0', '0', 'qc:qualityReview:execute', 'admin', NOW());
|
||||
|
||||
-- ==================== 5. 授权admin角色 ====================
|
||||
INSERT IGNORE INTO sys_role_menu (role_id, menu_id) VALUES
|
||||
(1, @parent_quality), (1, @id_review_dir),
|
||||
(1, @id_review_menu), (1, @id_review_todo);
|
||||
-- 按钮权限
|
||||
INSERT IGNORE INTO sys_role_menu (role_id, menu_id) SELECT 1, menu_id FROM sys_menu WHERE parent_id = @id_review_menu AND menu_type = 'F';
|
||||
|
||||
-- ==================== 6. 验证 ====================
|
||||
SELECT 'Dev align OK' AS result;
|
||||
@@ -513,7 +513,7 @@ public class SqlServerApiClient {
|
||||
params.put("endRow", endRow);
|
||||
StringBuilder where = new StringBuilder();
|
||||
if (coilId != null && !coilId.trim().isEmpty()) {
|
||||
where.append(" AND UPPER(EXCOILID) LIKE '%' || UPPER(:coilId) || '%'");
|
||||
where.append(" AND (UPPER(EXCOILID) LIKE '%' || UPPER(:coilId) || '%' OR UPPER(HOT_COILID) LIKE '%' || UPPER(:coilId) || '%')");
|
||||
params.put("coilId", coilId.trim());
|
||||
}
|
||||
if (startDate != null && !startDate.trim().isEmpty()) {
|
||||
@@ -533,7 +533,7 @@ public class SqlServerApiClient {
|
||||
Map<String, Object> params = new java.util.HashMap<>();
|
||||
StringBuilder where = new StringBuilder();
|
||||
if (coilId != null && !coilId.trim().isEmpty()) {
|
||||
where.append(" AND UPPER(EXCOILID) LIKE '%' || UPPER(:coilId) || '%'");
|
||||
where.append(" AND (UPPER(EXCOILID) LIKE '%' || UPPER(:coilId) || '%' OR UPPER(HOT_COILID) LIKE '%' || UPPER(:coilId) || '%')");
|
||||
params.put("coilId", coilId.trim());
|
||||
}
|
||||
if (startDate != null && !startDate.trim().isEmpty()) {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.klp.web.controller.system;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import javax.validation.constraints.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.system.domain.vo.SysFileCommentVo;
|
||||
import com.klp.system.domain.bo.SysFileCommentBo;
|
||||
import com.klp.system.service.ISysFileCommentService;
|
||||
|
||||
/**
|
||||
* 文件评论
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-07-04
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/system/file/comment")
|
||||
public class SysFileCommentController extends BaseController {
|
||||
|
||||
private final ISysFileCommentService iSysFileCommentService;
|
||||
|
||||
/**
|
||||
* 查询文件评论列表
|
||||
*/
|
||||
@GetMapping("/list/{fileId}")
|
||||
public R<List<SysFileCommentVo>> list(@NotNull(message = "文件ID不能为空") @PathVariable Long fileId) {
|
||||
return R.ok(iSysFileCommentService.queryListByFileId(fileId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增文件评论
|
||||
*/
|
||||
@Log(title = "文件评论", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody SysFileCommentBo bo) {
|
||||
return toAjax(iSysFileCommentService.insertByBo(bo));
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,15 @@ public class SysFileController extends BaseController {
|
||||
return toAjax(iSysFileService.deleteWithValidByIds(Arrays.asList(fileIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件浏览次数 +1
|
||||
*/
|
||||
@PutMapping("/incrementView/{fileId}")
|
||||
public R<Void> incrementView(@NotNull(message = "主键不能为空") @PathVariable Long fileId) {
|
||||
iSysFileService.incrementViewCount(fileId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询与我相关的文件(私有文件且当前用户在可见用户列表中)
|
||||
*/
|
||||
|
||||
@@ -9,10 +9,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.domain.WmsCoilQualityRejudge;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.domain.WmsMaterialCoil;
|
||||
import com.klp.mapper.WmsCoilQualityRejudgeMapper;
|
||||
import com.klp.mapper.WmsMaterialCoilMapper;
|
||||
import com.klp.service.IWmsMaterialCoilService;
|
||||
import com.klp.mes.qc.domain.QcQualityReview;
|
||||
import com.klp.mes.qc.domain.QcQualityReviewCoil;
|
||||
import com.klp.mes.qc.domain.QcQualityReviewLog;
|
||||
@@ -45,11 +45,14 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
|
||||
/** 技术部逻辑库ID(C/D级改判后移入此库区) */
|
||||
private static final Long TECH_WAREHOUSE_ID = 2019583656787259393L;
|
||||
|
||||
private final QcQualityReviewMapper baseMapper;
|
||||
private final QcQualityReviewCoilMapper coilMapper;
|
||||
private final QcQualityReviewLogMapper logMapper;
|
||||
private final WmsMaterialCoilMapper wmsMaterialCoilMapper;
|
||||
private final WmsCoilQualityRejudgeMapper wmsCoilQualityRejudgeMapper;
|
||||
private final IWmsMaterialCoilService wmsMaterialCoilService;
|
||||
|
||||
/**
|
||||
* 查询评审单详情(含钢卷明细和审批日志)
|
||||
@@ -112,11 +115,19 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改评审单(仅草稿状态可修改)
|
||||
* 修改评审单(仅草稿或已驳回状态可修改)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateByBo(QcQualityReviewBo bo) {
|
||||
// 校验:只有待提交或已驳回状态才能修改
|
||||
if (bo.getReviewId() != null) {
|
||||
QcQualityReview exist = baseMapper.selectById(bo.getReviewId());
|
||||
if (exist != null && !Long.valueOf(1L).equals(exist.getFlowStatus())
|
||||
&& !Long.valueOf(4L).equals(exist.getFlowStatus())) {
|
||||
throw new RuntimeException("只有待提交或已驳回状态的评审单才能修改");
|
||||
}
|
||||
}
|
||||
QcQualityReview update = BeanUtil.toBean(bo, QcQualityReview.class);
|
||||
validEntityBeforeSave(update);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
@@ -194,7 +205,7 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
.set(QcQualityReview::getRejectReason, null));
|
||||
|
||||
// 记录审批日志
|
||||
addLog(reviewId, "submit", "提交送审", null);
|
||||
addLog(reviewId, "submit", "提交送审");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -215,6 +226,20 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
throw new RuntimeException("请为每个钢卷指定改判后质量状态");
|
||||
}
|
||||
|
||||
// 校验:coilRegradeList 是否覆盖了评审单中的所有有效钢卷
|
||||
List<QcQualityReviewCoil> dbCoils = coilMapper.selectList(
|
||||
Wrappers.<QcQualityReviewCoil>lambdaQuery()
|
||||
.eq(QcQualityReviewCoil::getReviewId, bo.getReviewId())
|
||||
.eq(QcQualityReviewCoil::getDelFlag, 0));
|
||||
Set<Long> regradedIds = bo.getCoilRegradeList().stream()
|
||||
.map(QcQualityReviewApproveBo.CoilRegradeBo::getDetailId)
|
||||
.collect(Collectors.toSet());
|
||||
for (QcQualityReviewCoil coil : dbCoils) {
|
||||
if (!regradedIds.contains(coil.getDetailId())) {
|
||||
throw new RuntimeException("钢卷【" + coil.getCurrentCoilNo() + "】未指定改判后质量状态");
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 更新主表流程状态
|
||||
baseMapper.update(null, Wrappers.<QcQualityReview>lambdaUpdate()
|
||||
.eq(QcQualityReview::getReviewId, bo.getReviewId())
|
||||
@@ -231,7 +256,7 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
}
|
||||
|
||||
// 3. 记录审批日志
|
||||
addLog(bo.getReviewId(), "approve", bo.getLeaderOpinion(), bo.getLeaderSign());
|
||||
addLog(bo.getReviewId(), "approve", bo.getLeaderOpinion());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -259,7 +284,7 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
.set(QcQualityReview::getRejectReason, reason));
|
||||
|
||||
// 记录审批日志
|
||||
addLog(reviewId, "reject", reason, null);
|
||||
addLog(reviewId, "reject", reason);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -289,20 +314,20 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
}
|
||||
|
||||
Date now = new Date();
|
||||
String reason = "异常产品评审改判,评审单号:" + review.getReviewNo();
|
||||
for (QcQualityReviewCoil coil : coilList) {
|
||||
// 1. 写入 wms_coil_quality_rejudge 改判记录
|
||||
WmsCoilQualityRejudge rejudge = new WmsCoilQualityRejudge();
|
||||
rejudge.setCoilId(coil.getCoilId());
|
||||
rejudge.setBeforeQuality(coil.getBeforeQuality());
|
||||
rejudge.setAfterQuality(coil.getRegradeQuality());
|
||||
rejudge.setRejudgeReason("异常产品评审改判,评审单号:" + review.getReviewNo());
|
||||
wmsCoilQualityRejudgeMapper.insert(rejudge);
|
||||
|
||||
// 2. 更新钢卷的 qualityStatus 为改判后的值
|
||||
// 1. 通过统一方法更新钢卷质量状态 + 自动记录改判日志
|
||||
if (coil.getCoilId() != null && StringUtils.isNotBlank(coil.getRegradeQuality())) {
|
||||
wmsMaterialCoilService.updateQualityStatus(
|
||||
coil.getCoilId(), coil.getRegradeQuality(), reason);
|
||||
}
|
||||
|
||||
// 2. 根据改判后质量等级自动更新钢卷所在逻辑库区
|
||||
Long targetWarehouseId = determineTargetWarehouse(coil.getRegradeQuality());
|
||||
if (targetWarehouseId != null && coil.getCoilId() != null) {
|
||||
wmsMaterialCoilMapper.update(null, Wrappers.<WmsMaterialCoil>lambdaUpdate()
|
||||
.eq(WmsMaterialCoil::getCoilId, coil.getCoilId())
|
||||
.set(WmsMaterialCoil::getQualityStatus, coil.getRegradeQuality()));
|
||||
.set(WmsMaterialCoil::getWarehouseId, targetWarehouseId));
|
||||
}
|
||||
|
||||
// 3. 更新明细执行状态
|
||||
@@ -364,14 +389,14 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加审批日志
|
||||
* 添加审批日志(自动记录当前登录用户为操作人)
|
||||
*/
|
||||
private void addLog(Long reviewId, String action, String opinion, String operator) {
|
||||
private void addLog(Long reviewId, String action, String opinion) {
|
||||
QcQualityReviewLog log = new QcQualityReviewLog();
|
||||
log.setReviewId(reviewId);
|
||||
log.setAction(action);
|
||||
log.setOpinion(opinion);
|
||||
log.setOperator(operator);
|
||||
log.setOperator(LoginHelper.getUsername());
|
||||
log.setOperateTime(new Date());
|
||||
logMapper.insert(log);
|
||||
}
|
||||
@@ -386,7 +411,29 @@ public class QcQualityReviewServiceImpl implements IQcQualityReviewService {
|
||||
return "QR-" + dateStr + "-" + String.format("%04d", count + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据改判后质量等级确定目标逻辑库区
|
||||
* O/A/B → 不移动,C+/C/C- → 技术部逻辑库,D+/D/D- → 技术部逻辑库
|
||||
*/
|
||||
private Long determineTargetWarehouse(String regradeQuality) {
|
||||
if (regradeQuality == null) return null;
|
||||
// O/A/B 级不移动
|
||||
if ("O".equals(regradeQuality) || "A".equals(regradeQuality) || "B".equals(regradeQuality)) {
|
||||
return null;
|
||||
}
|
||||
// C/D 级 → 技术部逻辑库
|
||||
if (regradeQuality.startsWith("C") || regradeQuality.startsWith("D")) {
|
||||
return TECH_WAREHOUSE_ID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(QcQualityReview entity) {
|
||||
// TODO 数据校验
|
||||
if (StringUtils.isBlank(entity.getProductName())) {
|
||||
throw new RuntimeException("产品名称不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(entity.getTransmitDept())) {
|
||||
entity.setTransmitDept("品质部");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.klp.controller;
|
||||
package com.klp.pt.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
@@ -17,9 +17,9 @@ import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.domain.bo.PtProductToleranceBo;
|
||||
import com.klp.service.IPtProductToleranceService;
|
||||
import com.klp.pt.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.pt.domain.bo.PtProductToleranceBo;
|
||||
import com.klp.pt.service.IPtProductToleranceService;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.klp.domain;
|
||||
package com.klp.pt.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.klp.domain.bo;
|
||||
package com.klp.pt.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.klp.domain.vo;
|
||||
package com.klp.pt.domain.vo;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.klp.mapper;
|
||||
package com.klp.pt.mapper;
|
||||
|
||||
import com.klp.domain.PtProductTolerance;
|
||||
import com.klp.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.pt.domain.PtProductTolerance;
|
||||
import com.klp.pt.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.klp.service;
|
||||
package com.klp.pt.service;
|
||||
|
||||
import com.klp.domain.PtProductTolerance;
|
||||
import com.klp.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.domain.bo.PtProductToleranceBo;
|
||||
import com.klp.pt.domain.PtProductTolerance;
|
||||
import com.klp.pt.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.pt.domain.bo.PtProductToleranceBo;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.klp.domain.bo.PtProductToleranceBo;
|
||||
import com.klp.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.domain.PtProductTolerance;
|
||||
import com.klp.mapper.PtProductToleranceMapper;
|
||||
import com.klp.service.IPtProductToleranceService;
|
||||
import com.klp.pt.domain.bo.PtProductToleranceBo;
|
||||
import com.klp.pt.domain.vo.PtProductToleranceVo;
|
||||
import com.klp.pt.domain.PtProductTolerance;
|
||||
import com.klp.pt.mapper.PtProductToleranceMapper;
|
||||
import com.klp.pt.service.IPtProductToleranceService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.mapper.PtProductToleranceMapper">
|
||||
<mapper namespace="com.klp.pt.mapper.PtProductToleranceMapper">
|
||||
|
||||
<resultMap type="com.klp.domain.PtProductTolerance" id="PtProductToleranceResult">
|
||||
<resultMap type="com.klp.pt.domain.PtProductTolerance" id="PtProductToleranceResult">
|
||||
<result property="toleranceId" column="tolerance_id"/>
|
||||
<result property="standardId" column="standard_id"/>
|
||||
<result property="toleranceType" column="tolerance_type"/>
|
||||
|
||||
@@ -60,6 +60,10 @@ public class SysFile extends BaseEntity {
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
/**
|
||||
* 浏览次数
|
||||
*/
|
||||
private Long viewCount;
|
||||
/**
|
||||
* 删除标识 0正常 2删除
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.klp.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
/**
|
||||
* 文件评论对象 sys_file_comment
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-07-04
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("sys_file_comment")
|
||||
public class SysFileComment extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "comment_id")
|
||||
private Long commentId;
|
||||
/**
|
||||
* 关联文件ID
|
||||
*/
|
||||
private Long fileId;
|
||||
/**
|
||||
* 评论内容
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 所属部门
|
||||
*/
|
||||
private String dept;
|
||||
|
||||
}
|
||||
@@ -67,5 +67,9 @@ public class SysFileBo extends BaseEntity {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 浏览次数
|
||||
*/
|
||||
private Long viewCount;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.klp.system.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import javax.validation.constraints.*;
|
||||
|
||||
|
||||
/**
|
||||
* 文件评论业务对象 sys_file_comment
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-07-04
|
||||
*/
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysFileCommentBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long commentId;
|
||||
|
||||
/**
|
||||
* 关联文件ID
|
||||
*/
|
||||
@NotNull(message = "文件ID不能为空")
|
||||
private Long fileId;
|
||||
|
||||
/**
|
||||
* 评论内容
|
||||
*/
|
||||
@NotBlank(message = "评论内容不能为空")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 所属部门
|
||||
*/
|
||||
private String dept;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.klp.system.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
/**
|
||||
* 文件评论视图对象 sys_file_comment
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-07-04
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class SysFileCommentVo extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long commentId;
|
||||
|
||||
/**
|
||||
* 关联文件ID
|
||||
*/
|
||||
private Long fileId;
|
||||
|
||||
/**
|
||||
* 评论内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 所属部门
|
||||
*/
|
||||
private String dept;
|
||||
|
||||
}
|
||||
@@ -80,5 +80,10 @@ public class SysFileVo extends BaseEntity {
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 浏览次数
|
||||
*/
|
||||
@ExcelProperty(value = "浏览次数")
|
||||
private Long viewCount;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.klp.system.mapper;
|
||||
|
||||
import com.klp.system.domain.SysFileComment;
|
||||
import com.klp.system.domain.vo.SysFileCommentVo;
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 文件评论Mapper接口
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-07-04
|
||||
*/
|
||||
public interface SysFileCommentMapper extends BaseMapperPlus<SysFileCommentMapper, SysFileComment, SysFileCommentVo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.klp.system.service;
|
||||
|
||||
import com.klp.system.domain.vo.SysFileCommentVo;
|
||||
import com.klp.system.domain.bo.SysFileCommentBo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件评论Service接口
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-07-04
|
||||
*/
|
||||
public interface ISysFileCommentService {
|
||||
|
||||
/**
|
||||
* 查询文件评论列表
|
||||
*/
|
||||
List<SysFileCommentVo> queryListByFileId(Long fileId);
|
||||
|
||||
/**
|
||||
* 新增文件评论
|
||||
*/
|
||||
Boolean insertByBo(SysFileCommentBo bo);
|
||||
}
|
||||
@@ -51,4 +51,9 @@ public interface ISysFileService {
|
||||
* 查询与我相关的文件(私有文件且当前用户在可见用户列表中)
|
||||
*/
|
||||
TableDataInfo<SysFileVo> queryPageListRelatedToMe(SysFileBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 文件浏览次数 +1
|
||||
*/
|
||||
void incrementViewCount(Long fileId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.klp.system.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.system.domain.bo.SysFileCommentBo;
|
||||
import com.klp.system.domain.vo.SysFileCommentVo;
|
||||
import com.klp.system.domain.SysFileComment;
|
||||
import com.klp.system.mapper.SysFileCommentMapper;
|
||||
import com.klp.system.service.ISysFileCommentService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 文件评论Service业务层处理
|
||||
*
|
||||
* @author klp
|
||||
* @date 2026-07-04
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class SysFileCommentServiceImpl implements ISysFileCommentService {
|
||||
|
||||
private final SysFileCommentMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询文件评论列表(按时间升序)
|
||||
*/
|
||||
@Override
|
||||
public List<SysFileCommentVo> queryListByFileId(Long fileId) {
|
||||
LambdaQueryWrapper<SysFileComment> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(SysFileComment::getFileId, fileId);
|
||||
lqw.orderByAsc(SysFileComment::getCreateTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增文件评论
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(SysFileCommentBo bo) {
|
||||
SysFileComment add = BeanUtil.toBean(bo, SysFileComment.class);
|
||||
// 自动填充部门和评论人
|
||||
add.setDept(LoginHelper.getLoginUser().getDeptName());
|
||||
return baseMapper.insert(add) > 0;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.klp.common.helper.LoginHelper;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
@@ -124,6 +125,16 @@ public class SysFileServiceImpl implements ISysFileService {
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件浏览次数 +1
|
||||
*/
|
||||
@Override
|
||||
public void incrementViewCount(Long fileId) {
|
||||
baseMapper.update(null, Wrappers.<SysFile>lambdaUpdate()
|
||||
.setSql("view_count = view_count + 1")
|
||||
.eq(SysFile::getFileId, fileId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.system.mapper.SysFileCommentMapper">
|
||||
|
||||
<resultMap type="com.klp.system.domain.SysFileComment" id="SysFileCommentResult">
|
||||
<result property="commentId" column="comment_id"/>
|
||||
<result property="fileId" column="file_id"/>
|
||||
<result property="content" column="content"/>
|
||||
<result property="dept" column="dept"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
@@ -15,6 +15,7 @@
|
||||
<result property="fileType" column="file_type"/>
|
||||
<result property="scopeType" column="scope_type"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="viewCount" column="view_count"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
|
||||
@@ -52,6 +52,14 @@ export function exportFile(query) {
|
||||
})
|
||||
}
|
||||
|
||||
// 文件浏览次数 +1
|
||||
export function incrementView(fileId) {
|
||||
return request({
|
||||
url: '/system/file/incrementView/' + fileId,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询与我相关的文件
|
||||
export function listRelatedToMe(query) {
|
||||
return request({
|
||||
|
||||
18
klp-ui/src/api/system/fileComment.js
Normal file
18
klp-ui/src/api/system/fileComment.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询文件评论列表
|
||||
export function listFileComment(fileId) {
|
||||
return request({
|
||||
url: '/system/file/comment/list/' + fileId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增文件评论
|
||||
export function addFileComment(data) {
|
||||
return request({
|
||||
url: '/system/file/comment',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
@@ -69,11 +69,7 @@
|
||||
<!-- 待提交:提交送审 -->
|
||||
<el-button v-if="currentRow.flowStatus === 1" size="mini" type="primary" plain icon="el-icon-s-promotion"
|
||||
@click="handleSubmit" v-hasPermi="['qc:qualityReview:submit']">提交送审</el-button>
|
||||
<!-- 待审批:审批/驳回 -->
|
||||
<el-button v-if="currentRow.flowStatus === 2" size="mini" type="success" plain icon="el-icon-check"
|
||||
@click="handleApprove" v-hasPermi="['qc:qualityReview:approve']">审批通过</el-button>
|
||||
<el-button v-if="currentRow.flowStatus === 2" size="mini" type="danger" plain icon="el-icon-close"
|
||||
@click="handleReject" v-hasPermi="['qc:qualityReview:approve']">驳回</el-button>
|
||||
<!-- 待审批:审批/驳回表单在下方展示,顶部不再重复放置操作按钮 -->
|
||||
<!-- 已通过:执行改判 -->
|
||||
<el-button v-if="currentRow.flowStatus === 3" size="mini" type="warning" plain icon="el-icon-setting"
|
||||
@click="handleExecute" v-hasPermi="['qc:qualityReview:execute']">执行改判</el-button>
|
||||
@@ -541,20 +537,6 @@ export default {
|
||||
},
|
||||
|
||||
// ===== 审批 =====
|
||||
handleApprove() {
|
||||
this.approveAction = 'approve'
|
||||
this.approveForm = {
|
||||
reviewId: this.currentRow.reviewId,
|
||||
leaderOpinion: '',
|
||||
leaderSign: ''
|
||||
}
|
||||
// 先构建完整对象再赋值
|
||||
const map = {}
|
||||
this.coilList.forEach(c => {
|
||||
map[c.detailId] = c.regradeQuality || ''
|
||||
})
|
||||
this.approveCoilMap = map
|
||||
},
|
||||
doApprove() {
|
||||
if (!this.approveForm.leaderOpinion) {
|
||||
this.$modal.msgError('请输入审批意见')
|
||||
@@ -581,10 +563,6 @@ export default {
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
handleReject() {
|
||||
this.approveAction = 'reject'
|
||||
this.rejectReason = ''
|
||||
},
|
||||
doReject() {
|
||||
if (!this.rejectReason) {
|
||||
this.$modal.msgError('请输入驳回原因')
|
||||
|
||||
@@ -172,10 +172,10 @@
|
||||
<div class="search-panel">
|
||||
<div class="panel-title">查找</div>
|
||||
<div class="search-type-group">
|
||||
<el-radio v-model="searchType" label="coil">按钢卷号</el-radio>
|
||||
<el-radio v-model="searchType" label="coil">按钢卷号/热卷号</el-radio>
|
||||
<div v-if="searchType === 'coil'" class="search-field">
|
||||
<span class="search-label">钢卷号:</span>
|
||||
<el-input v-model="searchCoilId" size="mini" style="width:140px" placeholder="EXCOILID" />
|
||||
<span class="search-label">钢卷号/热卷号:</span>
|
||||
<el-input v-model="searchCoilId" size="mini" style="width:140px" placeholder="子卷号或热卷号" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-type-group">
|
||||
|
||||
@@ -152,6 +152,11 @@
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="浏览次数" align="center" width="90">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.viewCount != null ? scope.row.viewCount : 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</KLPTable>
|
||||
|
||||
<pagination
|
||||
@@ -187,6 +192,36 @@
|
||||
<span>{{ selectedFile.createBy }}</span>
|
||||
<span>{{ parseTime(selectedFile.createTime) }}</span>
|
||||
</div>
|
||||
<div class="preview-comment">
|
||||
<div class="comment-bar" @click="commentExpanded = !commentExpanded">
|
||||
<span><i class="el-icon-chat-dot-round"></i> 评论 ({{ comments.length }})</span>
|
||||
<span class="comment-toggle">{{ commentExpanded ? '收起' : '展开' }} <i :class="commentExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i></span>
|
||||
</div>
|
||||
<div v-show="commentExpanded" class="comment-body">
|
||||
<div v-if="commentLoading" class="comment-hint"><i class="el-icon-loading"></i> 加载中...</div>
|
||||
<div v-else-if="comments.length === 0" class="comment-hint comment-empty">暂无评论</div>
|
||||
<div v-else class="comment-list">
|
||||
<div v-for="item in comments" :key="item.commentId" class="comment-item">
|
||||
<div class="comment-meta">
|
||||
<span class="comment-dept">{{ item.dept }}</span>
|
||||
<span class="comment-user">{{ item.createBy }}</span>
|
||||
<span class="comment-time">{{ parseTime(item.createTime) }}</span>
|
||||
</div>
|
||||
<div class="comment-text">{{ item.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-input-area">
|
||||
<el-input
|
||||
v-model="commentInput"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="输入评论..."
|
||||
resize="none"
|
||||
/>
|
||||
<el-button type="primary" size="mini" @click="handleAddComment" :disabled="!commentInput.trim()" style="margin-top: 6px;">发送</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-content">
|
||||
<ImagePreview v-if="fileTypeCategory === 'image'" :src="selectedFile.filePath" />
|
||||
<PdfPreview v-else-if="fileTypeCategory === 'pdf'" :src="selectedFile.filePath" />
|
||||
@@ -274,6 +309,7 @@
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="文件大小">{{ formatFileSize(infoFile.fileSize) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="文件后缀">{{ infoFile.suffix || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="浏览次数">{{ infoFile.viewCount != null ? infoFile.viewCount : 0 }} 次</el-descriptions-item>
|
||||
<el-descriptions-item label="订单编号">{{ infoFile.orderNo || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="所属部门">{{ infoFile.dept || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="可见范围">
|
||||
@@ -291,7 +327,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listFile, getFile, addFile, updateFile, delFile, exportFile, listVisibleUser, addVisibleUser, delVisibleUser, listVisibleUserByFileId, listRelatedToMe } from '@/api/system/file'
|
||||
import { listFile, getFile, addFile, updateFile, delFile, exportFile, listVisibleUser, addVisibleUser, delVisibleUser, listVisibleUserByFileId, listRelatedToMe, incrementView } from '@/api/system/file'
|
||||
import { listFileComment, addFileComment } from '@/api/system/fileComment'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import UserSelect from '@/components/KLPService/UserSelect/index'
|
||||
import ImagePreview from '@/components/FilePreview/preview/image/index.vue'
|
||||
@@ -391,6 +428,11 @@ export default {
|
||||
infoVisible: false,
|
||||
infoTitle: '',
|
||||
infoFile: null,
|
||||
// 评论
|
||||
comments: [],
|
||||
commentExpanded: false,
|
||||
commentInput: '',
|
||||
commentLoading: false,
|
||||
// 拖拽调节宽度
|
||||
leftPanelWidth: '40%',
|
||||
isDragging: false,
|
||||
@@ -416,6 +458,16 @@ export default {
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
watch: {
|
||||
selectedFile(val) {
|
||||
if (val) {
|
||||
this.loadComments()
|
||||
} else {
|
||||
this.comments = []
|
||||
this.commentExpanded = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 切换tab */
|
||||
handleTabClick(tab) {
|
||||
@@ -698,6 +750,7 @@ export default {
|
||||
/** 点击文件名查看预览 */
|
||||
handlePreview(row) {
|
||||
this.selectedFile = row
|
||||
incrementView(row.fileId)
|
||||
},
|
||||
/** 点击查看按钮弹出详情 */
|
||||
handleShowInfo(row) {
|
||||
@@ -715,6 +768,25 @@ export default {
|
||||
window.open(row.filePath, '_blank')
|
||||
}
|
||||
},
|
||||
/** 加载评论列表 */
|
||||
loadComments() {
|
||||
this.commentLoading = true
|
||||
listFileComment(this.selectedFile.fileId).then(res => {
|
||||
this.comments = res.data || []
|
||||
this.commentLoading = false
|
||||
}).catch(() => {
|
||||
this.commentLoading = false
|
||||
})
|
||||
},
|
||||
/** 发送评论 */
|
||||
handleAddComment() {
|
||||
const content = this.commentInput.trim()
|
||||
if (!content) return
|
||||
addFileComment({ fileId: this.selectedFile.fileId, content }).then(() => {
|
||||
this.commentInput = ''
|
||||
this.loadComments()
|
||||
})
|
||||
},
|
||||
/** 开始拖拽 */
|
||||
startResize(e) {
|
||||
this.isDragging = true
|
||||
@@ -887,6 +959,88 @@ export default {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.preview-comment {
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.comment-bar {
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.comment-bar:hover {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.comment-toggle {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.comment-body {
|
||||
max-height: 260px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.comment-hint {
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.comment-list {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
padding: 8px 16px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.comment-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.comment-meta {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.comment-dept {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.comment-user {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.comment-time {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.comment-text {
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.comment-input-area {
|
||||
padding: 8px 16px;
|
||||
border-top: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
@@ -35,179 +35,259 @@
|
||||
<el-tab-pane label="与我相关" name="related"></el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||||
<el-form-item label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
v-model="queryParams.fileName"
|
||||
placeholder="请输入文件名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号" prop="orderNo">
|
||||
<el-input
|
||||
v-model="queryParams.orderNo"
|
||||
placeholder="请输入订单编号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属部门" prop="dept">
|
||||
<el-input
|
||||
v-model="queryParams.dept"
|
||||
placeholder="请输入部门"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="文件类型" prop="fileType">
|
||||
<el-select
|
||||
v-model="queryParams.fileType"
|
||||
placeholder="请选择文件类型"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in dict.type.sys_file_type"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="可见范围" prop="scopeType" v-if="activeTab !== 'share' && activeTab !== 'related'">
|
||||
<el-select
|
||||
v-model="queryParams.scopeType"
|
||||
placeholder="请选择可见范围"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option label="公开" :value="1" />
|
||||
<el-option label="私有" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
style="width: 240px"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="['00:00:00', '23:59:59']"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 左右分栏布局 -->
|
||||
<div class="file-layout" ref="layoutContainer">
|
||||
<!-- 左侧:文件列表 -->
|
||||
<div class="file-left" :style="{ width: activeTab === 'share' || activeTab === 'related' ? leftPanelWidth : '100%' }">
|
||||
<!-- 搜索栏 -->
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||||
<el-form-item label="文件名称" prop="fileName">
|
||||
<el-input
|
||||
v-model="queryParams.fileName"
|
||||
placeholder="请输入文件名称"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号" prop="orderNo">
|
||||
<el-input
|
||||
v-model="queryParams.orderNo"
|
||||
placeholder="请输入订单编号"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属部门" prop="dept">
|
||||
<el-input
|
||||
v-model="queryParams.dept"
|
||||
placeholder="请输入部门"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="文件类型" prop="fileType">
|
||||
<el-select
|
||||
v-model="queryParams.fileType"
|
||||
placeholder="请选择文件类型"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in dict.type.sys_file_type"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="可见范围" prop="scopeType" v-if="activeTab !== 'share' && activeTab !== 'related'">
|
||||
<el-select
|
||||
v-model="queryParams.scopeType"
|
||||
placeholder="请选择可见范围"
|
||||
clearable
|
||||
style="width: 200px"
|
||||
>
|
||||
<el-option label="公开" :value="1" />
|
||||
<el-option label="私有" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="上传时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
style="width: 240px"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="['00:00:00', '23:59:59']"
|
||||
></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5" v-if="activeTab === 'my' || activeTab === 'all'">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>上传文件</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="activeTab === 'my' || activeTab === 'all'">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
<!-- 操作按钮 -->
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5" v-if="activeTab === 'my' || activeTab === 'all'">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>上传文件</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5" v-if="activeTab === 'my' || activeTab === 'all'">
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
icon="el-icon-delete"
|
||||
size="mini"
|
||||
:disabled="multiple"
|
||||
@click="handleDelete"
|
||||
>删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="warning"
|
||||
plain
|
||||
icon="el-icon-download"
|
||||
size="mini"
|
||||
@click="handleExport"
|
||||
>导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<!-- 文件列表表格 -->
|
||||
<KLPTable v-loading="loading" :data="fileList" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" v-if="activeTab === 'my' || activeTab === 'all'" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<el-link type="primary" @click="handlePreview(scope.row)">{{ scope.row.fileName }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件类型" align="center" prop="fileType">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.sys_file_type" :value="scope.row.fileType"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件大小" align="center" prop="fileSize">
|
||||
<template slot-scope="scope">
|
||||
{{ formatFileSize(scope.row.fileSize) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单编号" align="center" prop="orderNo" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="所属部门" align="center" prop="dept" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="可见范围" align="center" prop="scopeType">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.scopeType === 1 ? 'success' : 'warning'" size="small">
|
||||
{{ scope.row.scopeType === 1 ? '公开' : '私有' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传人" align="center" prop="createBy" />
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="操作" align="center" width="220" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handlePreview(scope.row)"
|
||||
>预览</el-button>
|
||||
<el-button
|
||||
v-if="canEdit(scope.row)"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
v-if="canEdit(scope.row)"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</KLPTable>
|
||||
<!-- 文件列表表格 -->
|
||||
<KLPTable v-loading="loading" :data="fileList" @selection-change="handleSelectionChange" :highlight-current-row="activeTab === 'share' || activeTab === 'related'" @row-click="handleRowClick">
|
||||
<el-table-column type="selection" width="55" align="center" v-if="activeTab === 'my' || activeTab === 'all'" />
|
||||
<el-table-column label="文件名称" align="center" prop="fileName" :show-overflow-tooltip="true">
|
||||
<template slot-scope="scope">
|
||||
<el-link type="primary" @click="handlePreview(scope.row)">{{ scope.row.fileName }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件类型" align="center" prop="fileType" v-if="activeTab !== 'share' && activeTab !== 'related'">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.sys_file_type" :value="scope.row.fileType"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="文件大小" align="center" prop="fileSize" v-if="activeTab !== 'share' && activeTab !== 'related'">
|
||||
<template slot-scope="scope">
|
||||
{{ formatFileSize(scope.row.fileSize) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="订单编号" align="center" prop="orderNo" :show-overflow-tooltip="true" v-if="activeTab !== 'share' && activeTab !== 'related'" />
|
||||
<el-table-column label="所属部门" align="center" prop="dept" :show-overflow-tooltip="true" v-if="activeTab !== 'share' && activeTab !== 'related'" />
|
||||
<el-table-column label="可见范围" align="center" prop="scopeType" v-if="activeTab !== 'share' && activeTab !== 'related'">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.scopeType === 1 ? 'success' : 'warning'" size="small">
|
||||
{{ scope.row.scopeType === 1 ? '公开' : '私有' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上传人" align="center" prop="createBy" />
|
||||
<el-table-column label="上传时间" align="center" prop="createTime" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="浏览次数" align="center" width="90" v-if="activeTab === 'share' || activeTab === 'related'">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ scope.row.viewCount != null ? scope.row.viewCount : 0 }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" v-if="activeTab !== 'share' && activeTab !== 'related'" />
|
||||
<el-table-column label="操作" align="center" width="220" class-name="small-padding fixed-width" v-if="activeTab !== 'share' && activeTab !== 'related'">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handlePreview(scope.row)"
|
||||
>预览</el-button>
|
||||
<el-button
|
||||
v-if="canEdit(scope.row)"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleUpdate(scope.row)"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
v-if="canEdit(scope.row)"
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</KLPTable>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 拖拽分隔条(共享文件 / 与我相关 tab) -->
|
||||
<div class="resize-handle" v-if="activeTab === 'share' || activeTab === 'related'" @mousedown="startResize" :class="{ dragging: isDragging }"></div>
|
||||
|
||||
<!-- 右侧:文件预览(共享文件 / 与我相关 tab) -->
|
||||
<div class="file-right" v-if="activeTab === 'share' || activeTab === 'related'">
|
||||
<div class="preview-panel">
|
||||
<div v-if="!selectedFile" class="preview-empty">
|
||||
<el-empty description="请选择左侧文件进行预览" />
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="preview-header">
|
||||
<span class="preview-filename" :title="selectedFile.fileName">{{ selectedFile.fileName }}</span>
|
||||
<div>
|
||||
<el-button size="mini" plain icon="el-icon-info" @click="handleShowInfo(selectedFile)">查看</el-button>
|
||||
<el-button size="mini" type="primary" icon="el-icon-download" @click="downloadFile(selectedFile)">下载</el-button>
|
||||
<el-button v-if="canEdit(selectedFile)" size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(selectedFile)">编辑</el-button>
|
||||
<el-button v-if="canEdit(selectedFile)" size="mini" type="text" icon="el-icon-delete" @click="handleDelete(selectedFile)">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-meta">
|
||||
<span>{{ formatFileSize(selectedFile.fileSize) }}</span>
|
||||
<dict-tag :options="dict.type.sys_file_type" :value="selectedFile.fileType" />
|
||||
<span>{{ selectedFile.createBy }}</span>
|
||||
<span>{{ parseTime(selectedFile.createTime) }}</span>
|
||||
</div>
|
||||
<div class="preview-comment">
|
||||
<div class="comment-bar" @click="commentExpanded = !commentExpanded">
|
||||
<span><i class="el-icon-chat-dot-round"></i> 评论 ({{ comments.length }})</span>
|
||||
<span class="comment-toggle">{{ commentExpanded ? '收起' : '展开' }} <i :class="commentExpanded ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"></i></span>
|
||||
</div>
|
||||
<div v-show="commentExpanded" class="comment-body">
|
||||
<div v-if="commentLoading" class="comment-hint"><i class="el-icon-loading"></i> 加载中...</div>
|
||||
<div v-else-if="comments.length === 0" class="comment-hint comment-empty">暂无评论</div>
|
||||
<div v-else class="comment-list">
|
||||
<div v-for="item in comments" :key="item.commentId" class="comment-item">
|
||||
<div class="comment-meta">
|
||||
<span class="comment-dept">{{ item.dept }}</span>
|
||||
<span class="comment-user">{{ item.createBy }}</span>
|
||||
<span class="comment-time">{{ parseTime(item.createTime) }}</span>
|
||||
</div>
|
||||
<div class="comment-text">{{ item.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-input-area">
|
||||
<el-input
|
||||
v-model="commentInput"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="输入评论..."
|
||||
resize="none"
|
||||
/>
|
||||
<el-button type="primary" size="mini" @click="handleAddComment" :disabled="!commentInput.trim()" style="margin-top: 6px;">发送</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="preview-content">
|
||||
<ImagePreview v-if="fileTypeCategory === 'image'" :src="selectedFile.filePath" />
|
||||
<PdfPreview v-else-if="fileTypeCategory === 'pdf'" :src="selectedFile.filePath" />
|
||||
<DocxPreview v-else-if="fileTypeCategory === 'docx'" :src="selectedFile.filePath" />
|
||||
<XlsxPreview v-else-if="fileTypeCategory === 'xlsx'" :src="selectedFile.filePath" />
|
||||
<XlsPreview v-else-if="fileTypeCategory === 'xls'" :src="selectedFile.filePath" />
|
||||
<div v-else class="preview-not-supported">
|
||||
<el-empty description="暂不支持预览此文件类型" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 上传/编辑对话框 -->
|
||||
<el-dialog :title="dialogTitle" :visible.sync="open" width="650px" append-to-body @close="handleDialogClose">
|
||||
@@ -272,7 +352,7 @@
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 文件预览对话框 -->
|
||||
<!-- 文件预览对话框(仅非共享文件 tab 使用) -->
|
||||
<el-dialog :title="previewTitle" :visible.sync="previewVisible" width="80%" append-to-body>
|
||||
<div v-if="previewFile" class="file-preview-container">
|
||||
<el-descriptions :column="2" border>
|
||||
@@ -302,15 +382,26 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listFile, getFile, addFile, updateFile, delFile, exportFile, listVisibleUser, addVisibleUser, delVisibleUser, listVisibleUserByFileId, listRelatedToMe } from '@/api/system/file'
|
||||
import { listFile, getFile, addFile, updateFile, delFile, exportFile, listVisibleUser, addVisibleUser, delVisibleUser, listVisibleUserByFileId, listRelatedToMe, incrementView } from '@/api/system/file'
|
||||
import { listFileComment, addFileComment } from '@/api/system/fileComment'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import UserSelect from '@/components/KLPService/UserSelect/index'
|
||||
import ImagePreview from '@/components/FilePreview/preview/image/index.vue'
|
||||
import PdfPreview from '@/components/FilePreview/preview/pdf/index.vue'
|
||||
import DocxPreview from '@/components/FilePreview/preview/docx/index.vue'
|
||||
import XlsxPreview from '@/components/FilePreview/preview/xlsx/index.vue'
|
||||
import XlsPreview from '@/components/FilePreview/preview/xls/index.vue'
|
||||
|
||||
export default {
|
||||
name: 'SysFile',
|
||||
dicts: ['sys_file_type'],
|
||||
components: {
|
||||
UserSelect
|
||||
UserSelect,
|
||||
ImagePreview,
|
||||
PdfPreview,
|
||||
DocxPreview,
|
||||
XlsxPreview,
|
||||
XlsPreview
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -386,15 +477,51 @@ export default {
|
||||
Authorization: 'Bearer ' + getToken()
|
||||
},
|
||||
uploadFileList: [],
|
||||
// 预览
|
||||
// 预览对话框(非共享文件 tab)
|
||||
previewVisible: false,
|
||||
previewTitle: '',
|
||||
previewFile: null
|
||||
previewFile: null,
|
||||
// 选中的文件(共享文件 tab 右侧预览)
|
||||
selectedFile: null,
|
||||
// 评论
|
||||
comments: [],
|
||||
commentExpanded: false,
|
||||
commentInput: '',
|
||||
commentLoading: false,
|
||||
// 拖拽调节宽度(共享文件 tab)
|
||||
leftPanelWidth: '40%',
|
||||
isDragging: false,
|
||||
startX: 0,
|
||||
startLeftWidth: 60
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
/** 根据文件后缀分类,决定右侧用哪个预览组件 */
|
||||
fileTypeCategory() {
|
||||
if (!this.selectedFile) return null
|
||||
const raw = this.selectedFile.suffix || this.selectedFile.fileName || ''
|
||||
const ext = (raw.includes('.') ? raw.split('.').pop() : raw).toLowerCase()
|
||||
if (['png', 'jpg', 'jpeg', 'bmp', 'webp'].includes(ext)) return 'image'
|
||||
if (ext === 'pdf') return 'pdf'
|
||||
if (ext === 'docx') return 'docx'
|
||||
if (ext === 'xlsx') return 'xlsx'
|
||||
if (ext === 'xls') return 'xls'
|
||||
return 'other'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
watch: {
|
||||
selectedFile(val) {
|
||||
if (val) {
|
||||
this.loadComments()
|
||||
} else {
|
||||
this.comments = []
|
||||
this.commentExpanded = false
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 切换tab */
|
||||
handleTabClick(tab) {
|
||||
@@ -499,6 +626,7 @@ export default {
|
||||
/** 重置按钮 */
|
||||
resetQuery() {
|
||||
this.dateRange = []
|
||||
this.selectedFile = null
|
||||
this.resetForm('queryForm')
|
||||
this.queryParams = {
|
||||
pageNum: 1,
|
||||
@@ -675,6 +803,23 @@ export default {
|
||||
},
|
||||
/** 预览 */
|
||||
handlePreview(row) {
|
||||
if (this.activeTab === 'share' || this.activeTab === 'related') {
|
||||
this.selectedFile = row
|
||||
incrementView(row.fileId)
|
||||
} else {
|
||||
this.previewFile = row
|
||||
this.previewTitle = '文件详情 - ' + row.fileName
|
||||
this.previewVisible = true
|
||||
}
|
||||
},
|
||||
/** 点击行选中预览(共享文件 / 与我相关 tab) */
|
||||
handleRowClick(row) {
|
||||
if (this.activeTab === 'share' || this.activeTab === 'related') {
|
||||
this.selectedFile = row
|
||||
}
|
||||
},
|
||||
/** 查看文件详情 */
|
||||
handleShowInfo(row) {
|
||||
this.previewFile = row
|
||||
this.previewTitle = '文件详情 - ' + row.fileName
|
||||
this.previewVisible = true
|
||||
@@ -684,6 +829,54 @@ export default {
|
||||
if (row.filePath) {
|
||||
window.open(row.filePath, '_blank')
|
||||
}
|
||||
},
|
||||
/** 加载评论列表 */
|
||||
loadComments() {
|
||||
this.commentLoading = true
|
||||
listFileComment(this.selectedFile.fileId).then(res => {
|
||||
this.comments = res.data || []
|
||||
this.commentLoading = false
|
||||
}).catch(() => {
|
||||
this.commentLoading = false
|
||||
})
|
||||
},
|
||||
/** 发送评论 */
|
||||
handleAddComment() {
|
||||
const content = this.commentInput.trim()
|
||||
if (!content) return
|
||||
addFileComment({ fileId: this.selectedFile.fileId, content }).then(() => {
|
||||
this.commentInput = ''
|
||||
this.loadComments()
|
||||
})
|
||||
},
|
||||
/** 开始拖拽 */
|
||||
startResize(e) {
|
||||
this.isDragging = true
|
||||
this.startX = e.clientX
|
||||
this.startLeftWidth = parseFloat(this.leftPanelWidth)
|
||||
document.addEventListener('mousemove', this.doResize)
|
||||
document.addEventListener('mouseup', this.stopResize)
|
||||
document.body.style.cursor = 'col-resize'
|
||||
document.body.style.userSelect = 'none'
|
||||
},
|
||||
/** 拖拽中 */
|
||||
doResize(e) {
|
||||
if (!this.isDragging) return
|
||||
const container = this.$refs.layoutContainer
|
||||
const rect = container.getBoundingClientRect()
|
||||
const deltaX = e.clientX - this.startX
|
||||
let percent = this.startLeftWidth + (deltaX / rect.width) * 100
|
||||
percent = Math.max(30, Math.min(80, percent))
|
||||
this.leftPanelWidth = percent + '%'
|
||||
},
|
||||
/** 结束拖拽 */
|
||||
stopResize() {
|
||||
if (!this.isDragging) return
|
||||
this.isDragging = false
|
||||
document.removeEventListener('mousemove', this.doResize)
|
||||
document.removeEventListener('mouseup', this.stopResize)
|
||||
document.body.style.cursor = ''
|
||||
document.body.style.userSelect = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -731,4 +924,210 @@ export default {
|
||||
.upload-demo {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 左右分栏布局 */
|
||||
.file-layout {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.file-left {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.file-right {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
/* 拖拽分隔条 */
|
||||
.resize-handle {
|
||||
width: 6px;
|
||||
cursor: col-resize;
|
||||
flex-shrink: 0;
|
||||
align-self: stretch;
|
||||
background: transparent;
|
||||
position: relative;
|
||||
transition: background-color 0.2s;
|
||||
margin: 0 2px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.resize-handle:hover,
|
||||
.resize-handle.dragging {
|
||||
background: #409eff;
|
||||
}
|
||||
|
||||
.resize-handle::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 2px;
|
||||
height: 30px;
|
||||
background: #dcdfe6;
|
||||
border-radius: 1px;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.resize-handle:hover::after,
|
||||
.resize-handle.dragging::after {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.preview-panel {
|
||||
background: #fff;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 4px;
|
||||
height: calc(100vh - 280px);
|
||||
min-height: 450px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: sticky;
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
.preview-empty {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.preview-header {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preview-filename {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.preview-meta {
|
||||
padding: 8px 16px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.preview-comment {
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.comment-bar {
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.comment-bar:hover {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.comment-toggle {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.comment-body {
|
||||
max-height: 260px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.comment-hint {
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.comment-list {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
padding: 8px 16px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.comment-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.comment-meta {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.comment-dept {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.comment-user {
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.comment-time {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.comment-text {
|
||||
font-size: 13px;
|
||||
color: #303133;
|
||||
line-height: 1.5;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.comment-input-area {
|
||||
padding: 8px 16px;
|
||||
border-top: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.preview-content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.preview-content > div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.preview-not-supported {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 表格选中行高亮(非 scoped,穿透 el-table) -->
|
||||
<style>
|
||||
.file-left .el-table .current-row > td {
|
||||
background-color: #ecf5ff !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -194,6 +194,16 @@ public interface IWmsMaterialCoilService {
|
||||
*/
|
||||
String queryQualityStatusByWarehouseIdAndCurrentCoilNo(Long warehouseId, String currentCoilNo);
|
||||
|
||||
/**
|
||||
* 统一更新钢卷质量状态(自动记录改判日志)
|
||||
* 所有修改 quality_status 的地方都应当通过此方法,确保改判记录完整可追溯
|
||||
*
|
||||
* @param coilId 钢卷ID
|
||||
* @param newQuality 新质量状态
|
||||
* @param reason 变更原因
|
||||
*/
|
||||
void updateQualityStatus(Long coilId, String newQuality, String reason);
|
||||
|
||||
int exportCoil(@NotEmpty(message = "主键不能为空") Long coilId);
|
||||
|
||||
|
||||
|
||||
@@ -1823,6 +1823,40 @@ public class WmsMaterialCoilServiceImpl implements IWmsMaterialCoilService {
|
||||
return qw;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateQualityStatus(Long coilId, String newQuality, String reason) {
|
||||
if (coilId == null || StringUtils.isBlank(newQuality)) {
|
||||
log.warn("updateQualityStatus 参数不足: coilId={}, newQuality={}", coilId, newQuality);
|
||||
return;
|
||||
}
|
||||
// 查询当前钢卷
|
||||
WmsMaterialCoil coil = baseMapper.selectById(coilId);
|
||||
if (coil == null) {
|
||||
throw new RuntimeException("钢卷不存在:" + coilId);
|
||||
}
|
||||
String oldQuality = coil.getQualityStatus();
|
||||
// 状态没变,不处理
|
||||
if (StringUtils.equals(oldQuality, newQuality)) {
|
||||
log.info("钢卷质量状态未变化,跳过: coilId={}, quality={}", coilId, oldQuality);
|
||||
return;
|
||||
}
|
||||
// 1. 更新钢卷质量状态
|
||||
baseMapper.update(null, Wrappers.<WmsMaterialCoil>lambdaUpdate()
|
||||
.eq(WmsMaterialCoil::getCoilId, coilId)
|
||||
.set(WmsMaterialCoil::getQualityStatus, newQuality));
|
||||
|
||||
// 2. 记录改判记录
|
||||
WmsCoilQualityRejudge rejudge = new WmsCoilQualityRejudge();
|
||||
rejudge.setCoilId(coilId);
|
||||
rejudge.setBeforeQuality(oldQuality);
|
||||
rejudge.setAfterQuality(newQuality);
|
||||
rejudge.setRejudgeReason(reason);
|
||||
wmsCoilQualityRejudgeMapper.insert(rejudge);
|
||||
|
||||
log.info("钢卷质量状态变更: coilId={}, {} -> {}, 原因: {}", coilId, oldQuality, newQuality, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String queryQualityStatusByWarehouseIdAndCurrentCoilNo(Long warehouseId, String currentCoilNo) {
|
||||
if (warehouseId == null || StringUtils.isBlank(currentCoilNo)) {
|
||||
|
||||
Reference in New Issue
Block a user