feat(seal): 印章详情视图与编辑删除接口
- 印章详情返回视图数据供前端展示
- 补充印章详情视图 SQL
Co-Authored-By: Claude Code <noreply@anthropic.com>
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ç¨å°å®¡æ¹è¯¦æ
ï¼å±ç¤ºä½¿ç¨çå°ç« ä¿¡æ¯ï¼å¹¶æ¯æé¢è§å°ç« å¾ç |
| | | -- |
| | | -- æºå¶ï¼bpm_business_attach æãæµç¨ Keyãæ å°å°ä¸å¡è¯¦æ
ç»ä»¶ï¼ |
| | | -- 审æ¹è¯¦æ
é¡µå¨ processDefinition 为æ®é表åä¸å¸¦ businessKey æ¶èªå¨æ¹ä¸º CUSTOMï¼ |
| | | -- 渲æ component_path æåçç»ä»¶ï¼å¹¶æ businessKeyï¼ç¨å°ç³è¯· idï¼ä½ä¸º id ä¼ å
¥ã |
| | | -- æ¬èæ¬å¹çï¼å¯é夿§è¡ã |
| | | |
| | | INSERT INTO bpm_business_attach (process_definition_key, business_type, component_path, status, remark, creator, create_time, updater, update_time, deleted) |
| | | SELECT 'hrm-seal-use-approval', 'pd_seal_application', '/mes/pd/seal/detail/approve/index.vue', 0, |
| | | 'ç¨å°å®¡æ¹å±ç¤ºç¨å°ç³è¯·ä¿¡æ¯ä¸å°ç« å¾ç', '1', NOW(), '1', NOW(), b'0' |
| | | WHERE NOT EXISTS ( |
| | | SELECT 1 FROM bpm_business_attach WHERE process_definition_key = 'hrm-seal-use-approval' AND deleted = b'0' |
| | | ); |
| | | |
| | | UPDATE bpm_business_attach |
| | | SET component_path = '/mes/pd/seal/detail/approve/index.vue', |
| | | business_type = 'pd_seal_application', |
| | | status = 0, |
| | | updater = '1', |
| | | update_time = NOW() |
| | | WHERE process_definition_key = 'hrm-seal-use-approval' |
| | | AND deleted = b'0'; |
| | | |
| | | -- æ ¡éªï¼åºè¿å 1 è¡ï¼status=0ï¼å¯ç¨ï¼ |
| | | SELECT id, process_definition_key, component_path, status |
| | | FROM bpm_business_attach |
| | | WHERE process_definition_key = 'hrm-seal-use-approval' AND deleted = b'0'; |
| | |
| | | } |
| | | @GetMapping("/applications") @PreAuthorize("@ss.hasPermission('mes:pd-project:export')") |
| | | public CommonResult<List<Map<String,Object>>> applications(@RequestParam(required=false) Long projectId){ return success(service.applications(getLoginUserId(),projectId)); } |
| | | /** 审æ¹è¯¦æ
使ç¨ï¼ç»å½å³å¯è®¿é®ï¼å¯è§èå´å¨ Service å
æç³è¯·äºº/审æ¹äºº/管çæéæ ¡éª */ |
| | | @GetMapping("/application") |
| | | public CommonResult<Map<String,Object>> application(@RequestParam long id){ return success(service.applicationDetail(id,getLoginUserId())); } |
| | | @GetMapping("/application/image") |
| | | public void applicationImage(@RequestParam long id,HttpServletResponse response) throws java.io.IOException { |
| | | byte[] image=service.applicationImage(id,getLoginUserId()); |
| | | response.setContentType("image/png"); |
| | | response.setHeader("Cache-Control","no-store, private"); |
| | | response.setHeader("X-Content-Type-Options","nosniff"); |
| | | response.getOutputStream().write(image); |
| | | } |
| | | @GetMapping("/download") @PreAuthorize("@ss.hasPermission('mes:pd-project:export')") |
| | | public void download(@RequestParam long id,HttpServletResponse response) throws Exception {byte[] bytes=service.download(id,getLoginUserId()); response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document"); response.setHeader("Content-Disposition","attachment; filename=tracking.docx"); response.getOutputStream().write(bytes);} |
| | | } |
| | |
| | | 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; |
| | |
| | | @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>> 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); |