From 3fd8d1f2e73a843acd330e8e8b84f5800f858407 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期二, 10 十一月 2026 11:42:21 +0800
Subject: [PATCH] feat(seal): 印章详情视图与编辑删除接口

---
 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/seal/PdSealService.java |   84 ++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 80 insertions(+), 4 deletions(-)

diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/seal/PdSealService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/seal/PdSealService.java
index 74f35b1..e0f6cd0 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/seal/PdSealService.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pd/seal/PdSealService.java
@@ -4,6 +4,7 @@
 import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent;
 import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
+import cn.iocoder.yudao.framework.security.core.service.SecurityFrameworkService;
 import jakarta.annotation.Resource;
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.support.GeneratedKeyHolder;
@@ -24,14 +25,46 @@
     @Resource private BpmProcessInstanceApi bpm;
     @Resource private cn.iocoder.yudao.module.bpm.service.definition.BpmProcessAutoApproveService autoApprove;
     @Resource private cn.iocoder.yudao.module.bpm.service.task.BpmTaskService taskService;
+    @Resource private SecurityFrameworkService security;
     private long tenant() { Long id = cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.getTenantId(); return id == null ? 0L : id; }
     private ServiceException fail(String text) { return new ServiceException(1_040_990_001, text); }
 
     public List<Map<String,Object>> seals(boolean activeOnly) {
         return jdbc.queryForList("SELECT id,name,enabled,create_time FROM pd_seal WHERE tenant_id=? AND deleted=0" + (activeOnly ? " AND enabled=1" : "") + " ORDER BY id DESC", tenant());
     }
+    public byte[] getImage(long id) {
+        var rows = jdbc.queryForList("SELECT image_data FROM pd_seal WHERE id=? AND tenant_id=? AND deleted=0", id, tenant());
+        if (rows.isEmpty()) throw fail("鍗扮珷涓嶅瓨鍦�");
+        return (byte[]) rows.get(0).get("image_data");
+    }
     public long upload(String name, MultipartFile file, Long userId) throws Exception {
+        checkName(name);
+        byte[] data = readImage(file);
+        String imageHash = hash(data);
+        var keys = new GeneratedKeyHolder();
+        jdbc.update(c -> { var ps=c.prepareStatement("INSERT INTO pd_seal(name,image_data,image_hash,enabled,created_by,tenant_id) VALUES(?,?,?,1,?,?)", Statement.RETURN_GENERATED_KEYS); ps.setString(1,name.trim()); ps.setBytes(2,data); ps.setString(3,imageHash); ps.setLong(4,userId); ps.setLong(5,tenant()); return ps; }, keys);
+        return Objects.requireNonNull(keys.getKey()).longValue();
+    }
+    public void update(long id, String name, MultipartFile file) throws Exception {
+        checkName(name);
+        int updated;
+        if (file == null || file.isEmpty()) {
+            updated = jdbc.update("UPDATE pd_seal SET name=? WHERE id=? AND tenant_id=? AND deleted=0", name.trim(), id, tenant());
+        } else {
+            byte[] data = readImage(file);
+            updated = jdbc.update("UPDATE pd_seal SET name=?,image_data=?,image_hash=? WHERE id=? AND tenant_id=? AND deleted=0", name.trim(), data, hash(data), id, tenant());
+        }
+        if (updated != 1) throw fail("鍗扮珷涓嶅瓨鍦�");
+    }
+    public void delete(long id) {
+        Integer pending = jdbc.queryForObject("SELECT COUNT(*) FROM pd_seal_application WHERE seal_id=? AND tenant_id=? AND status=1", Integer.class, id, tenant());
+        if (pending != null && pending > 0) throw fail("璇ュ嵃绔犳湁杩涜涓殑鐢ㄥ嵃瀹℃壒鐢宠锛岃寰呭鎵瑰畬鎴愬悗鍐嶅垹闄�");
+        if (jdbc.update("UPDATE pd_seal SET deleted=1 WHERE id=? AND tenant_id=? AND deleted=0", id, tenant()) != 1) throw fail("鍗扮珷涓嶅瓨鍦�");
+    }
+    private void checkName(String name) {
         if (name == null || name.isBlank() || name.length() > 100) throw fail("鍗扮珷鍚嶇О涓嶈兘涓虹┖涓斾笉鑳借秴杩�100瀛�");
+    }
+    private byte[] readImage(MultipartFile file) throws Exception {
         if (file == null || file.isEmpty() || file.getSize() > 2 * 1024 * 1024) throw fail("璇蜂笂浼犱笉瓒呰繃2MB鐨凱NG鍗扮珷鍥剧墖");
         byte[] data = file.getBytes();
         byte[] sig = {(byte)137,80,78,71,13,10,26,10};
@@ -43,10 +76,10 @@
             try { reader.setInput(input); if (reader.getWidth(0) > 2048 || reader.getHeight(0) > 2048) throw fail("鍥剧墖灏哄涓嶈兘瓒呰繃2048脳2048"); reader.read(0); }
             finally { reader.dispose(); }
         }
-        String hash = HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(data));
-        var keys = new GeneratedKeyHolder();
-        jdbc.update(c -> { var ps=c.prepareStatement("INSERT INTO pd_seal(name,image_data,image_hash,enabled,created_by,tenant_id) VALUES(?,?,?,1,?,?)", Statement.RETURN_GENERATED_KEYS); ps.setString(1,name.trim()); ps.setBytes(2,data); ps.setString(3,hash); ps.setLong(4,userId); ps.setLong(5,tenant()); return ps; }, keys);
-        return Objects.requireNonNull(keys.getKey()).longValue();
+        return data;
+    }
+    private String hash(byte[] data) throws Exception {
+        return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(data));
     }
     public void setEnabled(long id, boolean enabled) {
         if (jdbc.update("UPDATE pd_seal SET enabled=? WHERE id=? AND tenant_id=? AND deleted=0", enabled, id, tenant()) != 1) throw fail("鍗扮珷涓嶅瓨鍦�");
@@ -72,6 +105,49 @@
     public List<Map<String,Object>> applications(long userId, Long projectId) {
         return jdbc.queryForList("SELECT id,project_id,project_code,seal_name,reason,status,process_instance_id,create_time,finish_time FROM pd_seal_application WHERE tenant_id=? AND applicant_id=?"+(projectId == null ? "" : " AND project_id="+projectId)+" ORDER BY id DESC LIMIT 200",tenant(),userId);
     }
+
+    /**
+     * 瀹℃壒璇︽儏锛氭煡璇㈢敤鍗扮敵璇风殑涓氬姟淇℃伅锛堝惈浣跨敤鐨勫嵃绔犲悕绉颁笌鐢宠鏃堕棿绛夛級
+     *
+     * 鍙鑼冨洿锛氱敵璇蜂汉鏈汉銆佽娴佺▼瀹炰緥鐨勫鎵逛汉锛堝惈宸插姙锛夈�佷互鍙婂叿澶囩敤鍗�/椤圭洰/娴佺▼鏌ヨ鏉冮檺鐨勭鐞嗕汉鍛樸��
+     */
+    public Map<String,Object> applicationDetail(long id, long userId) {
+        var rows = jdbc.queryForList("SELECT a.id,a.project_id,COALESCE(a.project_code,p.task_code) project_code,p.task_name project_name,"
+                + "a.seal_id,a.seal_name,a.reason,a.status,a.process_instance_id,a.applicant_id,"
+                + "u.nickname applicant_name,a.create_time,a.finish_time "
+                + "FROM pd_seal_application a "
+                + "LEFT JOIN mes_pd_project p ON p.id=a.project_id AND p.tenant_id=a.tenant_id "
+                + "LEFT JOIN system_users u ON u.id=a.applicant_id "
+                + "WHERE a.id=? AND a.tenant_id=?", id, tenant());
+        if (rows.isEmpty()) throw fail("鐢ㄥ嵃鐢宠涓嶅瓨鍦�");
+        var row = rows.get(0);
+        if (!canViewApplication(row, userId)) throw fail("鏃犳潈鏌ョ湅璇ョ敤鍗扮敵璇凤紝浠呯敵璇蜂汉銆佹湰娴佺▼瀹℃壒浜哄拰鐢ㄥ嵃绠$悊浜哄憳鍙煡鐪�");
+        return row;
+    }
+
+    /**
+     * 瀹℃壒璇︽儏锛氳幏鍙栫敵璇锋椂浣跨敤鐨勫嵃绔犲浘鐗囷紙鐢宠鎻愪氦鏃跺凡蹇収锛屽悗缁洿鎹㈠嵃绔犲浘鐗囦笉褰卞搷鍘嗗彶璁板綍锛�
+     */
+    public byte[] applicationImage(long id, long userId) {
+        var rows = jdbc.queryForList("SELECT seal_image,applicant_id,process_instance_id FROM pd_seal_application WHERE id=? AND tenant_id=?", id, tenant());
+        if (rows.isEmpty()) throw fail("鐢ㄥ嵃鐢宠涓嶅瓨鍦�");
+        var row = rows.get(0);
+        if (!canViewApplication(row, userId)) throw fail("鏃犳潈鏌ョ湅璇ョ敤鍗扮敵璇凤紝浠呯敵璇蜂汉銆佹湰娴佺▼瀹℃壒浜哄拰鐢ㄥ嵃绠$悊浜哄憳鍙煡鐪�");
+        return (byte[]) row.get("seal_image");
+    }
+
+    private boolean canViewApplication(Map<String,Object> row, long userId) {
+        Object applicant = row.get("applicant_id");
+        if (applicant instanceof Number number && number.longValue() == userId) return true;
+        // 鐢ㄥ嵃鐢宠浜�/瀹℃壒浜轰箣澶栫殑鍙鑼冨洿锛氶」鐩�佸嵃绔犮�佹祦绋�/寰呭姙鐨勭鐞嗕笌瀹℃壒鏉冮檺
+        if (security.hasAnyPermissions("mes:pd-project:export", "mes:pd-seal:manage",
+                "bpm:process-instance:query", "bpm:process-instance:manager-query",
+                "bpm:task:update", "bpm:task:manager-query")) return true;
+        Object instance = row.get("process_instance_id");
+        if (instance == null || instance.toString().isBlank()) return false;
+        return taskService.getTaskListByProcessInstanceId(instance.toString(), true).stream()
+                .anyMatch(task -> task.getAssignee() != null && String.valueOf(userId).equals(task.getAssignee()));
+    }
     @Transactional(rollbackFor=Exception.class)
     public byte[] download(long id,long userId) throws IOException {
         var rows=jdbc.queryForList("SELECT document_snapshot,seal_image,process_instance_id FROM pd_seal_application WHERE id=? AND tenant_id=? AND applicant_id=? AND status=2",id,tenant(),userId);

--
Gitblit v1.9.3