From fa1f70a074ab87d1dc9876bb77ad841e391564c9 Mon Sep 17 00:00:00 2001 From: shenrongliang <1328040932@qq.com> Date: 星期四, 26 六月 2025 10:11:43 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/main' --- ruoyi-modules/sc-page-designer/pom.xml | 28 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java | 23 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java | 89 + ruoyi-ui/apps/web-antd/src/views/system/process/index.vue | 472 +++++++++ ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/index.vue | 95 + ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java | 20 ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue | 224 ++++ ruoyi-ui/apps/web-antd/src/views/work/Issued/index.vue | 13 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java | 70 + ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml | 33 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerService.java | 29 ruoyi-ui/apps/web-antd/src/views/work/myWork/index.vue | 13 ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatSession.java | 13 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java | 19 pom.xml | 11 ruoyi-modules/pom.xml | 2 ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/serivceDialog.vue | 64 + ruoyi-ui/apps/web-antd/src/views/work/statistics/index.vue | 13 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java | 28 ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts | 14 ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysUserController.java | 11 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerController.java | 72 + ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java | 3 ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/data.ts | 44 ruoyi-ui/apps/web-antd/src/api/tool/page-designer/model.d.ts | 21 ruoyi-ui/apps/web-antd/src/services/flowableService.js | 0 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java | 22 ruoyi-ui/apps/web-antd/src/views/tool/dynamicForm/index.vue | 10 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java | 27 ruoyi-ui/apps/web-antd/src/views/tool/page-designer/index.vue | 217 ++++ ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java | 27 ruoyi-ui/apps/web-antd/src/views/tool/page-designer/page-drawer.vue | 337 ++++++ ruoyi-ui/apps/web-antd/src/views/tool/page-designer/data.tsx | 109 ++ ruoyi-admin/pom.xml | 10 ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml | 27 ruoyi-ui/apps/web-antd/src/api/tool/page-designer/index.ts | 52 + ruoyi-ui/apps/web-antd/package.json | 4 ruoyi-modules/sc-services/pom.xml | 24 ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts | 45 ruoyi-ui/apps/web-antd/src/bootstrap.ts | 4 ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java | 133 ++ ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx | 86 + ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesigner.java | 40 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java | 3 ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue | 397 +++++++ ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerMapper.java | 20 46 files changed, 3,009 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 848c226..bcb9603 100644 --- a/pom.xml +++ b/pom.xml @@ -308,7 +308,16 @@ <artifactId>ruoyi-chat</artifactId> <version>${revision}</version> </dependency> - + <dependency> + <groupId>org.ruoyi</groupId> + <artifactId>sc-services</artifactId> + <version>${revision}</version> + </dependency> + <dependency> + <groupId>org.ruoyi</groupId> + <artifactId>sc-page-designer</artifactId> + <version>${revision}</version> + </dependency> <dependency> <groupId>org.ruoyi</groupId> <artifactId>ruoyi-knowledge-api</artifactId> diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 5e3267d..3b8d957 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -61,6 +61,16 @@ <dependency> <groupId>org.ruoyi</groupId> + <artifactId>sc-services</artifactId> + </dependency> + + <dependency> + <groupId>org.ruoyi</groupId> + <artifactId>sc-page-designer</artifactId> + </dependency> + + <dependency> + <groupId>org.ruoyi</groupId> <artifactId>ruoyi-generator</artifactId> </dependency> diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatSession.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatSession.java index aa8967a..cffdc53 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatSession.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/ChatSession.java @@ -1,5 +1,6 @@ package org.ruoyi.domain; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; @@ -16,7 +17,7 @@ */ @Data @EqualsAndHashCode(callSuper = true) -@TableName("chat_session") +@TableName("CHAT_SESSION") public class ChatSession extends BaseEntity { @Serial @@ -25,28 +26,30 @@ /** * 涓婚敭 */ - @TableId(value = "id") + @TableId(value = "ID") private Long id; /** - * 鐢ㄦ埛id + * 鐢ㄦ埛ID */ + @TableField("USER_ID") private Long userId; /** * 浼氳瘽鏍囬 */ + @TableField("SESSION_TITLE") private String sessionTitle; /** * 浼氳瘽鍐呭 */ + @TableField("SESSION_CONTENT") private String sessionContent; /** * 澶囨敞 */ + @TableField("REMARK") private String remark; - - } diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java index a924688..5cfb993 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeInfo.java @@ -17,7 +17,7 @@ */ @Data @EqualsAndHashCode(callSuper = true) -@TableName("knowledge_info") +@TableName("KNOWLEDGE_INFO") public class KnowledgeInfo extends BaseEntity { @Serial @@ -27,6 +27,7 @@ * 涓婚敭ID */ @TableId(value = "ID") + @TableField("ID") private Long id; /** diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml index 95230d7..cbd569e 100644 --- a/ruoyi-modules/pom.xml +++ b/ruoyi-modules/pom.xml @@ -22,6 +22,8 @@ <module>ruoyi-system</module> <module>ruoyi-generator</module> <module>ruoyi-flowable</module> + <module>sc-services</module> + <module>sc-page-designer</module> </modules> <properties> diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java index 4a04827..efb587d 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java @@ -177,7 +177,8 @@ @Transactional(rollbackFor = Exception.class) public void removeKnowledge(String id) { Map<String,Object> map = new HashMap<>(); - KnowledgeInfo knowledgeInfo = baseMapper.selectById(id); + KnowledgeInfo knowledgeInfo = baseMapper.selectOne(new LambdaQueryWrapper<KnowledgeInfo>() + .eq(KnowledgeInfo::getKid, id)); check(knowledgeInfo); map.put("kid",knowledgeInfo.getKid()); // 鍒犻櫎鍚戦噺鏁版嵁 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysUserController.java index 04e5c0d..30babe9 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysUserController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/SysUserController.java @@ -322,4 +322,15 @@ return R.ok(trees); } + /** + * 鑾峰彇閮ㄩ棬涓嬬殑鎵�鏈夌敤鎴蜂俊鎭� + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list/dept/{deptId}") + public R<List<SysUserVo>> listByDeptId(@PathVariable Long deptId) { + List<SysUserVo> sysUserVos = userService.selectUserList(new SysUserBo()); + return R.ok(sysUserVos.stream() + .filter(user -> deptId.equals(user.getDeptId())) + .collect(Collectors.toList())); + } } diff --git a/ruoyi-modules/sc-page-designer/pom.xml b/ruoyi-modules/sc-page-designer/pom.xml new file mode 100644 index 0000000..400f53d --- /dev/null +++ b/ruoyi-modules/sc-page-designer/pom.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.ruoyi</groupId> + <artifactId>ruoyi-modules</artifactId> + <version>${revision}</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>sc-page-designer</artifactId> + <description> + school-ai椤甸潰璁捐鍣ㄦā鍧� + </description> + + <dependencies> + <!-- 閫氱敤宸ュ叿--> + <dependency> + <groupId>org.ruoyi</groupId> + <artifactId>ruoyi-common-core</artifactId> + </dependency> + <dependency> + <groupId>org.ruoyi</groupId> + <artifactId>ruoyi-system-api</artifactId> + </dependency> + </dependencies> +</project> diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerController.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerController.java new file mode 100644 index 0000000..16fad07 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerController.java @@ -0,0 +1,72 @@ +package org.ruoyi.pageDesigner.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.common.web.core.BaseController; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.pageDesigner.domain.PageDesigner; +import org.ruoyi.pageDesigner.domain.PageDesignerDTO; +import org.ruoyi.pageDesigner.domain.PageDesignerVo; +import org.ruoyi.pageDesigner.service.PageDesignerService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author kanglujie + * @date 2025-06-23 14:41:24 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/page-designer") +public class PageDesignerController extends BaseController { + + private final PageDesignerService pageDesignerService; + + /** + * 鑾峰彇椤甸潰璁捐鍒楄〃 + */ + @GetMapping("/list") + public TableDataInfo<PageDesignerVo> list(PageDesignerDTO pageDesignerDTO, PageQuery pageQuery) { + return pageDesignerService.selectPagelistAll(pageDesignerDTO, pageQuery); + } + + /** + * 鑾峰彇椤甸潰璁捐璇︽儏 + */ + @GetMapping("/{id}") + public R<PageDesigner> getInfo(@PathVariable Long id) { + return R.ok(pageDesignerService.getDetail(id)); + } + + /** + * 鏂板椤甸潰璁捐 + */ + @PostMapping + public R<Void> add(@Valid @RequestBody PageDesignerDTO dto) { + pageDesignerService.add(dto); + return R.ok("鏂板鎴愬姛"); + } + + /** + * 淇敼椤甸潰璁捐 + */ + @PutMapping + public R<Void> update(@Valid @RequestBody PageDesignerDTO dto) { + pageDesignerService.updatePage(dto); + return R.ok("淇敼鎴愬姛"); + } + + /** + * 鍒犻櫎椤甸潰璁捐 + */ + @DeleteMapping + public R<Void> remove(@RequestBody List<Long> ids) { + pageDesignerService.deleteByIds(ids); + return R.ok("鍒犻櫎鎴愬姛"); + } +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java new file mode 100644 index 0000000..5af3c15 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/controller/PageDesignerTemplateController.java @@ -0,0 +1,70 @@ +package org.ruoyi.pageDesigner.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.common.web.core.BaseController; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.pageDesigner.domain.*; +import org.ruoyi.pageDesigner.service.PageDesignerTemplateService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @author kanglujie + * @date 2025-06-23 14:41:24 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/page-designer-template") +public class PageDesignerTemplateController extends BaseController { + + private final PageDesignerTemplateService service; + + /** + * 鑾峰彇椤甸潰璁捐鍒楄〃 + */ + @GetMapping("/list") + public TableDataInfo<PageDesignerTemplateVo> list(PageDesignerTemplateDTO dto, PageQuery pageQuery) { + return service.selectPagelistAll(dto, pageQuery); + } + + /** + * 鑾峰彇椤甸潰璁捐璇︽儏 + */ + @GetMapping("/{id}") + public R<PageDesignerTemplate> getInfo(@PathVariable Long id) { + return R.ok(service.getDetail(id)); + } + + /** + * 鏂板椤甸潰璁捐 + */ + @PostMapping + public R<Void> add(@Valid @RequestBody PageDesignerTemplateDTO dto) { + service.add(dto); + return R.ok("鏂板鎴愬姛"); + } + + /** + * 淇敼椤甸潰璁捐 + */ + @PutMapping + public R<Void> update(@Valid @RequestBody PageDesignerTemplateDTO dto) { + service.updatePage(dto); + return R.ok("淇敼鎴愬姛"); + } + + /** + * 鍒犻櫎椤甸潰璁捐 + */ + @DeleteMapping + public R<Void> remove(@RequestBody List<Long> ids) { + service.deleteByIds(ids); + return R.ok("鍒犻櫎鎴愬姛"); + } +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesigner.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesigner.java new file mode 100644 index 0000000..19603e1 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesigner.java @@ -0,0 +1,40 @@ +package org.ruoyi.pageDesigner.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.ruoyi.core.domain.BaseEntity; + +/** + * @author kanglujie + * @date 2025-06-23 17:24:05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("PAGE_DESIGNER") +public class PageDesigner extends BaseEntity { + @TableId(value = "ID") + private Long id; + @TableField("NAME") + private String name; + @TableField("MENU_ID") + private String menuId; // 鍏宠仈鐨勮彍鍗旾D + @TableField("MENU_PARENT_ID") + private String menuParentId; // 鍏宠仈鐨勮彍鍗曠埗ID + @TableField("STATUS") + private String status; + @TableField(value = "DEL_FLAG") + @TableLogic + private String delFlag; + @TableField("REMARK") + private String remark; + @TableField("FORM_JSON") + private String formJson; + @TableField("SHOW_COLUMN") + private String showColumn; // 鍙互灏� selectedFields 瀛樺偍涓� JSON 瀛楃涓� + @TableField("ACTIONS_FUNC") + private String actionsFunc; // 鍙互灏� enableActions 瀛樺偍涓� JSON 瀛楃涓� +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java new file mode 100644 index 0000000..bf81590 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerDTO.java @@ -0,0 +1,27 @@ +package org.ruoyi.pageDesigner.domain; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.ruoyi.core.domain.BaseEntity; + +/** + * @author kanglujie + * @date 2025-06-23 17:23:35 + */ +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = PageDesigner.class, reverseConvertGenerate = false) +public class PageDesignerDTO extends BaseEntity { + private Long id; // 淇敼鏃朵紶鍏� + private String name; // 椤甸潰鍚嶇О + private String menuId; // 鍏宠仈鑿滃崟 ID + private String status; // 鍚敤鐘舵�� + private String remark; // 澶囨敞 + private String formJson; // 琛ㄥ崟璁捐 JSON 瀛楃涓� + private String showColumn; // 瀛楁鏄剧ず閰嶇疆 + private String actionsFunc; // 鍚敤鐨勬搷浣滈」锛堝鍒犳敼鏌ワ級 + private String menuParentId; +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java new file mode 100644 index 0000000..338c97a --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplate.java @@ -0,0 +1,28 @@ +package org.ruoyi.pageDesigner.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.ruoyi.core.domain.BaseEntity; + +/** + * @author kanglujie + * @date 2025-06-23 17:24:05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("PAGE_DESIGNER_TEMPLATE") +public class PageDesignerTemplate extends BaseEntity { + @TableId(value = "ID") + private Long id; + @TableField(value = "PAGE_ID") + private Long pageId; + @TableField("FORM_DATA") + private String formData; + @TableField(value = "DEL_FLAG") + @TableLogic + private String delFlag; +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java new file mode 100644 index 0000000..f2be0b8 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateDTO.java @@ -0,0 +1,22 @@ +package org.ruoyi.pageDesigner.domain; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.ruoyi.core.domain.BaseEntity; + +/** + * @author kanglujie + * @date 2025-06-23 17:23:35 + */ +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = PageDesignerTemplate.class, reverseConvertGenerate = false) +public class PageDesignerTemplateDTO extends BaseEntity { + private Long id; + private Long pageId; + private String formData; + private String delFlag; +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java new file mode 100644 index 0000000..9974206 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerTemplateVo.java @@ -0,0 +1,19 @@ +package org.ruoyi.pageDesigner.domain; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author kanglujie + * @date 2025-06-23 17:23:35 + */ +@Data +@AutoMapper(target = PageDesignerTemplate.class) +public class PageDesignerTemplateVo implements Serializable { + private Long id; + private Long pageId; + private String formData; + private String delFlag; +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java new file mode 100644 index 0000000..6d079fe --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/domain/PageDesignerVo.java @@ -0,0 +1,23 @@ +package org.ruoyi.pageDesigner.domain; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.ruoyi.system.domain.vo.SysMenuVo; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author kanglujie + * @date 2025-06-23 17:23:35 + */ +@Data +@AutoMapper(target = PageDesigner.class) +public class PageDesignerVo implements Serializable { + private Long id; // 淇敼鏃朵紶鍏� + private String name; // 椤甸潰鍚嶇О + private String status; // 鍚敤鐘舵�� + private String remark; // 澶囨敞 + private String menuParentId; // 鑿滃崟鐖禝D + private Date createTime; // 鍒涘缓鏃堕棿 +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerMapper.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerMapper.java new file mode 100644 index 0000000..f3757c7 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerMapper.java @@ -0,0 +1,20 @@ +package org.ruoyi.pageDesigner.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.ruoyi.pageDesigner.domain.PageDesigner; +import org.ruoyi.pageDesigner.domain.PageDesignerVo; + +/** + * @author kanglujie + * @date 2025-06-23 17:34:48 + */ +@Mapper +public interface PageDesignerMapper extends BaseMapper<PageDesigner> { + Page<PageDesignerVo> selectPagelistAll(@Param("page") Page<PageDesigner> page, @Param(Constants.WRAPPER) Wrapper<PageDesigner> queryWrapper); + +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java new file mode 100644 index 0000000..c0a54d1 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/mapper/PageDesignerTemplateMapper.java @@ -0,0 +1,20 @@ +package org.ruoyi.pageDesigner.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.ruoyi.pageDesigner.domain.PageDesignerTemplate; +import org.ruoyi.pageDesigner.domain.PageDesignerTemplateVo; + +/** + * @author kanglujie + * @date 2025-06-23 17:34:48 + */ +@Mapper +public interface PageDesignerTemplateMapper extends BaseMapper<PageDesignerTemplate> { + Page<PageDesignerTemplateVo> selectPagelistAll(@Param("page") Page<PageDesignerTemplate> page, @Param(Constants.WRAPPER) Wrapper<PageDesignerTemplate> queryWrapper); + +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerService.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerService.java new file mode 100644 index 0000000..2289ae9 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerService.java @@ -0,0 +1,29 @@ +package org.ruoyi.pageDesigner.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.pageDesigner.domain.PageDesigner; +import org.ruoyi.pageDesigner.domain.PageDesignerDTO; +import org.ruoyi.pageDesigner.domain.PageDesignerVo; + +import java.util.List; + +/** + * @author kanglujie + * @date 2025-06-23 17:35:56 + */ +public interface PageDesignerService extends IService<PageDesigner> { + + void add(PageDesignerDTO dto); + + void updatePage(PageDesignerDTO dto); + + List<PageDesigner> listAll(String keyword); + + PageDesigner getDetail(Long id); + + void deleteByIds(List<Long> ids); + + TableDataInfo<PageDesignerVo> selectPagelistAll(PageDesignerDTO pageDesignerDTO, PageQuery pageQuery); +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java new file mode 100644 index 0000000..a0e2bdb --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/PageDesignerTemplateService.java @@ -0,0 +1,27 @@ +package org.ruoyi.pageDesigner.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.pageDesigner.domain.*; + +import java.util.List; + +/** + * @author kanglujie + * @date 2025-06-23 17:35:56 + */ +public interface PageDesignerTemplateService extends IService<PageDesignerTemplate> { + + void add(PageDesignerTemplateDTO dto); + + void updatePage(PageDesignerTemplateDTO dto); + + List<PageDesignerTemplate> listAll(String keyword); + + PageDesignerTemplate getDetail(Long id); + + void deleteByIds(List<Long> ids); + + TableDataInfo<PageDesignerTemplateVo> selectPagelistAll(PageDesignerTemplateDTO dto, PageQuery pageQuery); +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java new file mode 100644 index 0000000..ee61662 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerServiceImpl.java @@ -0,0 +1,133 @@ +package org.ruoyi.pageDesigner.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.amazonaws.util.json.Jackson; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.ruoyi.common.core.constant.UserConstants; +import org.ruoyi.common.core.utils.StreamUtils; +import org.ruoyi.common.core.utils.StringUtils; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.helper.DataBaseHelper; +import org.ruoyi.pageDesigner.domain.PageDesigner; +import org.ruoyi.pageDesigner.domain.PageDesignerDTO; +import org.ruoyi.pageDesigner.domain.PageDesignerVo; +import org.ruoyi.pageDesigner.mapper.PageDesignerMapper; +import org.ruoyi.pageDesigner.service.PageDesignerService; +import org.ruoyi.system.domain.SysMenu; +import org.ruoyi.system.mapper.SysMenuMapper; +import org.ruoyi.system.mapper.SysUserMapper; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * @author kanglujie + * @date 2025-06-23 17:36:29 + */ +@Service +@RequiredArgsConstructor +public class PageDesignerServiceImpl extends ServiceImpl<PageDesignerMapper, PageDesigner> + implements PageDesignerService { + + private final SysMenuMapper menuMapper; + + @Override + public void add(PageDesignerDTO dto) { + SysMenu menu = new SysMenu(); + menu.setMenuName(dto.getName()); + menu.setParentId(Long.valueOf(dto.getMenuParentId())); + menu.setOrderNum(999); + menu.setComponent("tool/template/index"); + menu.setIsFrame("1"); + menu.setIsCache("0"); + menu.setMenuType("C"); // C:鐩綍, M:鑿滃崟, F:鎸夐挳 + menu.setVisible("0"); + menu.setStatus(dto.getStatus()); + menuMapper.insert(menu); + PageDesigner entity = convertToEntity(dto); + entity.setMenuId(menu.getMenuId().toString()); + this.save(entity); + menu.setPath(String.valueOf(entity.getId())); + menuMapper.updateById(menu); + } + + @Override + public void updatePage(PageDesignerDTO dto) { + PageDesigner entity = convertToEntity(dto); + this.updateById(entity); + PageDesigner byId = this.getById(entity.getId()); + SysMenu menu = new SysMenu(); + menu.setMenuId(Long.valueOf(byId.getMenuId())); + menu.setStatus(entity.getStatus()); + menu.setParentId(Long.valueOf(entity.getMenuParentId())); + menuMapper.updateById(menu); + } + + @Override + public TableDataInfo<PageDesignerVo> selectPagelistAll(PageDesignerDTO pageDesignerDTO, PageQuery pageQuery) { + Page<PageDesignerVo> page = baseMapper.selectPagelistAll(pageQuery.build(), this.buildQueryWrapper(pageDesignerDTO)); + return TableDataInfo.build(page); + } + private Wrapper<PageDesigner> buildQueryWrapper(PageDesignerDTO pageDesignerDTO) { + Map<String, Object> params = pageDesignerDTO.getParams(); + QueryWrapper<PageDesigner> wrapper = Wrappers.query(); + wrapper.eq("del_flag", UserConstants.USER_NORMAL) + .eq(ObjectUtil.isNotNull(pageDesignerDTO.getId()), "id", pageDesignerDTO.getId()) + .like(StringUtils.isNotBlank(pageDesignerDTO.getName()), "name", pageDesignerDTO.getName()) + .eq(StringUtils.isNotBlank(pageDesignerDTO.getStatus()), "status", pageDesignerDTO.getStatus()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "create_time", params.get("beginTime"), params.get("endTime")) + ; + return wrapper; + } + @Override + public List<PageDesigner> listAll(String keyword) { + LambdaQueryWrapper<PageDesigner> wrapper = new LambdaQueryWrapper<>(); + wrapper.like(keyword != null, PageDesigner::getName, keyword); + return this.list(wrapper); + } + + @Override + public PageDesigner getDetail(Long id) { + return this.getById(id); + } + + @Override + public void deleteByIds(List<Long> ids) { + List<PageDesigner> designers = this.listByIds(ids); + for (PageDesigner designer : designers) { + Long id = designer.getId(); + this.removeById(id); + + Long menuId = Long.valueOf(designer.getMenuId()); + if (menuId != null) { + menuMapper.deleteById(menuId); + } + } + + } + + private PageDesigner convertToEntity(PageDesignerDTO dto) { + PageDesigner entity = new PageDesigner(); + entity.setId(dto.getId()); + entity.setName(dto.getName()); + entity.setMenuId(dto.getMenuId()); + entity.setStatus(dto.getStatus()); + entity.setRemark(dto.getRemark()); + entity.setFormJson(dto.getFormJson()); + entity.setShowColumn(dto.getShowColumn()); + entity.setActionsFunc(dto.getActionsFunc()); + entity.setMenuParentId(dto.getMenuParentId()); + return entity; + } +} diff --git a/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java new file mode 100644 index 0000000..8ed291e --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/java/org/ruoyi/pageDesigner/service/impl/PageDesignerTemplateServiceImpl.java @@ -0,0 +1,89 @@ +package org.ruoyi.pageDesigner.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import org.ruoyi.common.core.constant.UserConstants; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.pageDesigner.domain.*; +import org.ruoyi.pageDesigner.mapper.PageDesignerMapper; +import org.ruoyi.pageDesigner.mapper.PageDesignerTemplateMapper; +import org.ruoyi.pageDesigner.service.PageDesignerService; +import org.ruoyi.pageDesigner.service.PageDesignerTemplateService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author kanglujie + * @date 2025-06-23 17:36:29 + */ +@Service +@RequiredArgsConstructor +public class PageDesignerTemplateServiceImpl extends ServiceImpl<PageDesignerTemplateMapper, PageDesignerTemplate> + implements PageDesignerTemplateService { + + private final ObjectMapper objectMapper; + + @Override + public void add(PageDesignerTemplateDTO dto) { + PageDesignerTemplate entity = convertToEntity(dto); + this.save(entity); + } + + @Override + public void updatePage(PageDesignerTemplateDTO dto) { + PageDesignerTemplate entity = convertToEntity(dto); + this.updateById(entity); + } + + @Override + public TableDataInfo<PageDesignerTemplateVo> selectPagelistAll(PageDesignerTemplateDTO dto, PageQuery pageQuery) { + Page<PageDesignerTemplateVo> page = baseMapper.selectPagelistAll(pageQuery.build(), this.buildQueryWrapper(dto)); + return TableDataInfo.build(page); + } + private Wrapper<PageDesignerTemplate> buildQueryWrapper(PageDesignerTemplateDTO dto) { + //Map<String, Object> params = pageDesignerDTO.getParams(); + QueryWrapper<PageDesignerTemplate> wrapper = Wrappers.query(); + wrapper.eq("del_flag", UserConstants.USER_NORMAL) + .eq(ObjectUtil.isNotNull(dto.getPageId()), "page_id", dto.getPageId()) + // .like(StringUtils.isNotBlank(pageDesignerDTO.getName()), "name", pageDesignerDTO.getName()) + // .eq(StringUtils.isNotBlank(pageDesignerDTO.getStatus()), "status", pageDesignerDTO.getStatus()) + // .between(params.get("beginTime") != null && params.get("endTime") != null, + // "create_time", params.get("beginTime"), params.get("endTime")) + ; + return wrapper; + } + @Override + public List<PageDesignerTemplate> listAll(String keyword) { + LambdaQueryWrapper<PageDesignerTemplate> wrapper = new LambdaQueryWrapper<>(); + wrapper.like(keyword != null, PageDesignerTemplate::getPageId, keyword); + return this.list(wrapper); + } + + @Override + public PageDesignerTemplate getDetail(Long id) { + return this.getById(id); + } + + @Override + public void deleteByIds(List<Long> ids) { + this.removeByIds(ids); + } + + private PageDesignerTemplate convertToEntity(PageDesignerTemplateDTO dto) { + PageDesignerTemplate entity = new PageDesignerTemplate(); + entity.setId(dto.getId()); + entity.setFormData(dto.getFormData()); + entity.setDelFlag(dto.getDelFlag()); + entity.setPageId(dto.getPageId()); + return entity; + } +} diff --git a/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml b/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml new file mode 100644 index 0000000..bd1d17f --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerMapper.xml @@ -0,0 +1,33 @@ +<?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="org.ruoyi.pageDesigner.mapper.PageDesignerMapper"> + + <!-- 澶氱粨鏋勫祵濂楄嚜鍔ㄦ槧灏勯渶甯︿笂姣忎釜瀹炰綋鐨勪富閿甶d 鍚﹀垯鏄犲皠浼氬け璐� --> + <resultMap type="org.ruoyi.pageDesigner.domain.PageDesignerVo" id="PageDesignerResult"> + <id property="id" column="id"/> + <result property="name" column="name"/> + <result property="status" column="status"/> + <result property="createTime" column="create_time"/> + <result property="menuParentId" column="menu_parent_id"/> + <result property="remark" column="remark"/> + </resultMap> + + + <select id="selectPagelistAll" resultMap="PageDesignerResult"> + select + id, + name, + status, + create_time, + menu_parent_id, + remark + from page_designer + ${ew.getCustomSqlSegment} + </select> + + + + +</mapper> diff --git a/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml b/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml new file mode 100644 index 0000000..8c23389 --- /dev/null +++ b/ruoyi-modules/sc-page-designer/src/main/resources/mapper/PageDesignerTemplateMapper.xml @@ -0,0 +1,27 @@ +<?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="org.ruoyi.pageDesigner.mapper.PageDesignerTemplateMapper"> + + <!-- 缁撴灉鏄犲皠 --> + <resultMap type="org.ruoyi.pageDesigner.domain.PageDesignerTemplateVo" id="PageDesignerTemplateResult"> + <id property="id" column="id"/> + <result property="pageId" column="page_id"/> + <result property="formData" column="form_data"/> + <result property="delFlag" column="del_flag"/> + </resultMap> + + <select id="selectPagelistAll" resultMap="PageDesignerTemplateResult"> + SELECT + id, + page_id, + form_data, + del_flag + FROM page_designer_template + <where> + ${ew.sqlSegment} + </where> + </select> + +</mapper> diff --git a/ruoyi-modules/sc-services/pom.xml b/ruoyi-modules/sc-services/pom.xml new file mode 100644 index 0000000..982daae --- /dev/null +++ b/ruoyi-modules/sc-services/pom.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.ruoyi</groupId> + <artifactId>ruoyi-modules</artifactId> + <version>${revision}</version> + <relativePath>../pom.xml</relativePath> + </parent> + <artifactId>sc-services</artifactId> + <description> + school-ai涓氬姟妯″潡 + </description> + + <dependencies> + <!-- 閫氱敤宸ュ叿--> + <dependency> + <groupId>org.ruoyi</groupId> + <artifactId>ruoyi-common-core</artifactId> + </dependency> + </dependencies> +</project> diff --git a/ruoyi-ui/apps/web-antd/package.json b/ruoyi-ui/apps/web-antd/package.json index 2138a2a..7336cf0 100644 --- a/ruoyi-ui/apps/web-antd/package.json +++ b/ruoyi-ui/apps/web-antd/package.json @@ -46,14 +46,18 @@ "@vben/utils": "workspace:*", "@vueuse/core": "catalog:", "ant-design-vue": "catalog:", + "axios": "^1.10.0", + "bpmn-js": "^18.6.2", "cropperjs": "^1.6.2", "crypto-js": "^4.2.0", "dayjs": "catalog:", + "diagram-js": "^15.3.0", "echarts": "^5.5.1", "element-plus": "^2.10.2", "jsencrypt": "^3.3.2", "lodash-es": "^4.17.21", "pinia": "catalog:", + "qs": "^6.13.1", "tinymce": "^7.3.0", "unplugin-vue-components": "^0.27.3", "vue": "catalog:", diff --git a/ruoyi-ui/apps/web-antd/src/api/tool/page-designer/index.ts b/ruoyi-ui/apps/web-antd/src/api/tool/page-designer/index.ts new file mode 100644 index 0000000..79fa508 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/api/tool/page-designer/index.ts @@ -0,0 +1,52 @@ +import { requestClient } from '#/api/request'; +import type { + PageDesigner +} from './model'; + +enum Api { + pageAdd = '/page-designer', + pageUpdate = '/page-designer', + pageList = '/page-designer/list', + pageInfo = '/page-designer', + pageRemove = '/page-designer', +} + +/** + * 鏂板椤甸潰璁捐 + */ +export function pageAdd(data: any) { + return requestClient.post(Api.pageAdd, data); +} + +/** + * 淇敼椤甸潰璁捐 + */ +export function pageUpdate(data: any) { + return requestClient.put(Api.pageUpdate, data); +} + +/** + * 鑾峰彇椤甸潰璁捐鍒楄〃 + */ +export function pageList(params?: any) { + return requestClient.get<{ + total: number; + rows: PageDesigner[]; + code: number; + msg: string; + }>(Api.pageList, { params }); +} + +/** + * 鑾峰彇椤甸潰璁捐璇︽儏 + */ +export function pageInfo(id: string | number) { + return requestClient.get<PageDesigner>(`${Api.pageInfo}/${id}`); +} + +/** + * 鍒犻櫎椤甸潰璁捐 + */ +export function pageRemove(ids: string[] | number[]) { + return requestClient.delete(Api.pageRemove, { data: ids }); +} diff --git a/ruoyi-ui/apps/web-antd/src/api/tool/page-designer/model.d.ts b/ruoyi-ui/apps/web-antd/src/api/tool/page-designer/model.d.ts new file mode 100644 index 0000000..88d885d --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/api/tool/page-designer/model.d.ts @@ -0,0 +1,21 @@ +export interface PageDesigner { + id?: string | number; // 涓婚敭锛岀紪杈戞椂鐢� + name: string; // 椤甸潰鍚嶇О + menuId: string | number | null; // 涓婄骇鐩綍锛堣彍鍗旾D锛� + parentId: string | number | null; // 鐖剁骇ID + status: string; // 鐘舵�� + remark?: string | null; // 澶囨敞 + formJson?: string | null; // 琛ㄥ崟璁捐JSON + showColumn?: string | null; // 鏄剧ず瀛楁(JSON瀛楃涓�) + actionsFunc?: string | null; // 鍚敤鍔熻兘(JSON瀛楃涓�) + createTime?: string; // 鍒涘缓鏃堕棿 + updateTime?: string; // 鏇存柊鏃堕棿 + menu?: { // 鍏宠仈鐨勮彍鍗曚俊鎭� + menuId: number; + menuName: string; + } | null; + parent?: { // 鍏宠仈鐨勭埗绾т俊鎭� + id: string | number; + name: string; + } | null; +} diff --git a/ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts b/ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts new file mode 100644 index 0000000..0b91788 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/api/tool/template/index.ts @@ -0,0 +1,45 @@ +import { requestClient } from '#/api/request'; +import type { Template } from './model'; + +enum Api { + templateAdd = '/page-designer-template', + templateUpdate = '/page-designer-template', + templateList = '/page-designer-template/list', + templateInfo = '/page-designer-template', + templateRemove = '/page-designer-template', +} + +/** + * 鏂板椤甸潰璁捐 + */ +export function templateAdd(data: any) { + return requestClient.post(Api.templateAdd, data); +} + +/** + * 淇敼椤甸潰璁捐 + */ +export function templateUpdate(data: any) { + return requestClient.put(Api.templateUpdate, data); +} + +/** + * 鑾峰彇椤甸潰璁捐鍒楄〃 + */ +export function templateList(params?: any) { + return requestClient.get(Api.templateList, { params }); +} + +/** + * 鑾峰彇椤甸潰璁捐璇︽儏 + */ +export function templateInfo(id: string | number) { + return requestClient.get(`${Api.templateInfo}/${id}`); +} + +/** + * 鍒犻櫎椤甸潰璁捐 + */ +export function templateRemove(ids: string[] | number[]) { + return requestClient.delete(Api.templateRemove, { data: ids }); +} \ No newline at end of file diff --git a/ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts b/ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts new file mode 100644 index 0000000..ab9d827 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/api/tool/template/model.d.ts @@ -0,0 +1,14 @@ +export interface Template { + id?: string | number; // 涓婚敭 + formData: string; // 妯$増鍚嶇О + pageDesignId: string | number; // 鍏宠仈鐨勯〉闈㈣璁D + createTime?: string; // 鍒涘缓鏃堕棿 + updateTime?: string; // 鏇存柊鏃堕棿 + pageDesign?: { // 鍏宠仈鐨勯〉闈㈣璁′俊鎭� + id: string | number; + name: string; + formJson?: string; + showColumn?: string; + actionsFunc?: string; + } | null; +} \ No newline at end of file diff --git a/ruoyi-ui/apps/web-antd/src/bootstrap.ts b/ruoyi-ui/apps/web-antd/src/bootstrap.ts index f76df08..adf3f37 100644 --- a/ruoyi-ui/apps/web-antd/src/bootstrap.ts +++ b/ruoyi-ui/apps/web-antd/src/bootstrap.ts @@ -19,7 +19,10 @@ import { router } from './router'; import formCreate from '@form-create/element-ui'; import FcDesigner from '@form-create/designer'; +import Antd from 'ant-design-vue'; +import 'ant-design-vue/dist/reset.css'; async function bootstrap(namespace: string) { + // 鍒濆鍖栫粍浠堕�傞厤鍣� await initComponentAdapter(); @@ -62,6 +65,7 @@ app.use(ElementPlus); app.use(formCreate); app.use(FcDesigner); + app.use(Antd); // 鍔ㄦ�佹洿鏂版爣棰� watchEffect(() => { if (preferences.app.dynamicTitle) { diff --git a/ruoyi-ui/apps/web-antd/src/services/flowableService.js b/ruoyi-ui/apps/web-antd/src/services/flowableService.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/services/flowableService.js diff --git a/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/data.ts b/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/data.ts new file mode 100644 index 0000000..eec5231 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/data.ts @@ -0,0 +1,44 @@ +import type { VxeGridProps } from 'src/adapter/vxe-table'; +import type { FormSchemaGetter } from "src/adapter/form"; + + +export const querySchema: FormSchemaGetter = () => [ + { + component: 'Input', + fieldName: 'roleName', + label: '鍚嶇О', + }, + + { + component: 'Select', + fieldName: 'roleSort', + label: '鍒涘缓浜�', + }, + { + component: 'RangePicker', + fieldName: 'createTime', + label: '鍒涘缓鏃堕棿', + }, +]; +export const columns: VxeGridProps['columns'] = [ + { type: 'checkbox', width: 60 }, + { + title: '鍚嶇О', + field: 'roleName', + }, + { + title: '鍒涘缓浜�', + field: 'roleSort', + }, + { + title: '鍒涘缓鏃堕棿', + field: 'createTime', + }, + { + field: 'action', + fixed: 'right', + slots: { default: 'action' }, + title: '鎿嶄綔', + width: 180, + }, +]; diff --git a/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/index.vue b/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/index.vue new file mode 100644 index 0000000..c6d7a38 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/index.vue @@ -0,0 +1,95 @@ +<template> + <Page :auto-content-height="true"> + <BasicTable table-title="宸ヤ綔鑰冩牳鎸囨爣鍒楄〃"> + <template #toolbar-tools> + <Space> + <a-button + v-access:code="['system:role:export']" + @click="handleDownloadExcel" + style="margin-right: 10px" + > + {{ $t('pages.common.export') }} + </a-button> + <a-button + type="primary" + v-access:code="['system:role:add']" + @click="handleAdd" + > + {{ $t('pages.common.add') }} + </a-button> + </Space> + </template> + </BasicTable> + </Page> +</template> + +<script setup lang="ts"> +import type { VxeGridProps } from "#/adapter/vxe-table"; +import { useVbenVxeGrid, vxeCheckboxChecked } from '#/adapter/vxe-table'; +import type { VbenFormProps } from '@vben/common-ui'; +import type { roleList} from "#/api/system/role"; +import { columns, querySchema } from './data'; +import { Page, useVbenDrawer, useVbenModal } from '@vben/common-ui'; +const formOptions: VbenFormProps = { + commonConfig: { + labelWidth: 80, + componentProps: { + allowClear: true, + }, + }, + schema: querySchema(), + wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4', + // 鏃ユ湡閫夋嫨鏍煎紡鍖� + fieldMappingTime: [ + [ + 'createTime', + ['params[beginTime]', 'params[endTime]'], + ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59'], + ], + ], +}; +const gridOptions: VxeGridProps = { + checkboxConfig: { + // 楂樹寒 + highlight: true, + // 缈婚〉鏃朵繚鐣欓�変腑鐘舵�� + reserve: true, + // 鐐瑰嚮琛岄�変腑 + // trigger: 'row', + checkMethod: ({ row }) => row.roleId !== 1, + }, + columns, + height: 'auto', + keepSource: true, + pagerConfig: {}, + proxyConfig: { + ajax: { + query: async ({ page }, formValues = {}) => { + return await roleList({ + pageNum: page.currentPage, + pageSize: page.pageSize, + ...formValues, + }); + }, + }, + }, + rowConfig: { + keyField: 'roleId', + }, + id: 'system-role-index', +}; +const [BasicTable,tableApi] = useVbenVxeGrid({ + formOptions, + gridOptions, +}); +const handleAdd = () => { + console.log('鏂板') +} +const handleDownloadExcel = () => { + console.log('瀵煎嚭') +} +</script> + +<style scoped> + +</style> diff --git a/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/serivceDialog.vue b/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/serivceDialog.vue new file mode 100644 index 0000000..c79fc8a --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/assessment/serviceRating/serivceDialog.vue @@ -0,0 +1,64 @@ + + +<script> +import {modelInfo} from "#/api/system/model/index.js"; +import {pick} from "lodash-es"; +import {useVbenModal} from "@vben/common-ui"; +import {ref, computed} from "vue"; +import { $t } from '@vben/locales'; +const defaultValues = { + id: undefined, + name: undefined, +} + +const isUpdate = ref(false); +const title = computed(() => { + return isUpdate.value ? $t('缂栬緫') : $t('鏂板'); +}); +const { validate, validateInfos, resetFields } = Form.useForm( + formData, + formRules, +); +const [BasicModal, modalApi] = useVbenModal({ + class: 'w-[550px]', + fullscreenButton: false, + closeOnClickModal: false, + onClosed: handleCancel, + onConfirm: handleConfirm, + onOpenChange: async (isOpen) => { + if (!isOpen) { + return null; + } + modalApi.modalLoading(true); + + const { id } = modalApi.getData() as { id?: number | string }; + isUpdate.value = !!id; + + if (isUpdate.value && id) { + const record = await modelInfo(id); + // 鍙祴鍊煎瓨鍦ㄧ殑瀛楁 + const filterRecord = pick(record, Object.keys(defaultValues)); + formData.value = filterRecord; + } + + modalApi.modalLoading(false); + }, +}); + + +</script> +<template> + <BasicModal :title="title"> + <Form :label-col="{ span: 4 }"> + <FormItem label="鍚嶇О" v-bind="validateInfos.name"> + <Input + v-model:value="formData.name" + :placeholder="$t('ui.formRules.required')" + /> + </FormItem> + </Form> + </BasicModal> +</template> +<style scoped> + +</style> diff --git a/ruoyi-ui/apps/web-antd/src/views/system/process/index.vue b/ruoyi-ui/apps/web-antd/src/views/system/process/index.vue new file mode 100644 index 0000000..fd598fd --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/system/process/index.vue @@ -0,0 +1,472 @@ +<template> + <div class="process-definition-container"> + <a-card title="娴佺▼瀹氫箟鍒楄〃" :bordered="false"> + <div class="table-actions"> + <a-button type="primary" @click="showCreateModal">鏂板娴佺▼鍥�</a-button> + </div> + <a-table + :columns="columns" + :data-source="definitions" + :row-key="record => record.id" + :pagination="pagination" + :loading="loading" + @change="handleTableChange" + > + <template #bodyCell="{ column, record }"> + <template v-if="column.key === 'action'"> + <a-space> + <a-button type="link" @click="showDiagram(record)">鏌ョ湅</a-button> + <a-button type="link" @click="editDiagram(record)">淇敼</a-button> + <a-button type="link" danger @click="deleteDefinition(record)">鍒犻櫎</a-button> + </a-space> + </template> + </template> + </a-table> + </a-card> + + <!-- 娴佺▼鍥炬煡鐪嬫ā鎬佹 --> + <a-modal + v-model:visible="diagramVisible" + title="娴佺▼鍥炬煡鐪�" + width="80%" + :footer="null" + @cancel="handleDiagramCancel" + > + <div style="text-align: center"> + <img + v-if="currentDiagramUrl" + :src="currentDiagramUrl" + alt="娴佺▼鍥�" + style="max-width: 100%" + /> + <a-skeleton v-else active /> + </div> + </a-modal> + + <!-- 娴佺▼鍥剧紪杈戞ā鎬佹 --> + <a-modal + v-model:visible="editorVisible" + :title="editorTitle" + width="90%" + :maskClosable="false" + :okText="'淇濆瓨'" + :cancelText="'鍙栨秷'" + :confirmLoading="editorSaving" + @ok="handleEditorOk" + @cancel="handleEditorCancel" + :destroyOnClose="true" + :afterClose="handleEditorAfterClose" + :style="{ top: '20px' }" + :bodyStyle="{ + padding: '0', + height: 'calc(100vh - 100px)', + overflow: 'hidden', + display: 'flex', + flexDirection: 'column' + }" + > + <div class="editor-container"> + <div v-if="isCreateMode" class="create-form"> + <a-form layout="vertical"> + <a-form-item label="娴佺▼鍚嶇О" required> + <a-input v-model:value="newProcess.name" placeholder="璇疯緭鍏ユ祦绋嬪悕绉�" /> + </a-form-item> + <a-form-item label="娴佺▼Key" required> + <a-input v-model:value="newProcess.key" placeholder="璇疯緭鍏ユ祦绋婯ey" /> + </a-form-item> + <a-form-item label="娴佺▼鎻忚堪"> + <a-textarea v-model:value="newProcess.description" placeholder="璇疯緭鍏ユ祦绋嬫弿杩�" /> + </a-form-item> + </a-form> + </div> + <div class="bpmn-editor" ref="bpmnEditor"></div> + </div> + </a-modal> + </div> +</template> + +<script setup> +import { ref, onMounted, nextTick } from 'vue' +import { message, Modal } from 'ant-design-vue' +import BpmnModeler from 'bpmn-js/lib/Modeler' +import 'bpmn-js/dist/assets/diagram-js.css' +import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css' +import 'bpmn-js/dist/assets/bpmn-js.css' + +// 琛ㄦ牸鍒楀畾涔� +const columns = [ + { + title: 'ID', + dataIndex: 'id', + key: 'id', + ellipsis: true + }, + { + title: '鍚嶇О', + dataIndex: 'name', + key: 'name' + }, + { + title: 'Key', + dataIndex: 'key', + key: 'key' + }, + { + title: '鎿嶄綔', + key: 'action', + } +] + +// 鏁版嵁鐘舵�� +const definitions = ref([]) +const loading = ref(false) +const pagination = ref({ + current: 1, + pageSize: 10, + total: 0, + showSizeChanger: true, + pageSizeOptions: ['10', '20', '50'] +}) + +// 娴佺▼鍥炬煡鐪嬬浉鍏崇姸鎬� +const diagramVisible = ref(false) +const currentDiagramUrl = ref('') +const currentProcessDefinition = ref(null) + +// 娴佺▼鍥剧紪杈戠浉鍏崇姸鎬� +const editorVisible = ref(false) +const editorSaving = ref(false) +const editorTitle = ref('娴佺▼鍥剧紪杈�') +const bpmnModeler = ref(null) +const bpmnEditor = ref(null) +const isCreateMode = ref(false) +const newProcess = ref({ + name: '', + key: '', + description: '' +}) + +// 鑾峰彇娴佺▼瀹氫箟鍒楄〃 +const fetchProcessDefinitions = async (params = {}) => { + loading.value = true + try { + // 妯℃嫙鏁版嵁 + const mockData = [ + { id: '1', name: '璇峰亣娴佺▼', key: 'leaveProcess'}, + { id: '2', name: '鎶ラ攢娴佺▼', key: 'expenseProcess'}, + { id: '3', name: '閲囪喘娴佺▼', key: 'purchaseProcess' } + ] + // 妯℃嫙鍒嗛〉 + const start = (params.page - 1) * params.size + const end = start + params.size + definitions.value = mockData.slice(start, end) + pagination.value.total = mockData.length + } catch (error) { + message.error('鍔犺浇娴佺▼瀹氫箟澶辫触:'+ error.message) + } finally { + loading.value = false + } +} + +// 琛ㄦ牸鍒嗛〉/鎺掑簭鍙樺寲澶勭悊 +const handleTableChange = (pag, filters, sorter) => { + const params = { + page: pag.current, + size: pag.pageSize + } + + if (sorter.field) { + params.sort = sorter.field + params.order = sorter.order === 'ascend' ? 'asc' : 'desc' + } + + fetchProcessDefinitions(params) +} + +// 鏄剧ず娴佺▼鍥� +const showDiagram = (record) => { + currentProcessDefinition.value = record + currentDiagramUrl.value = `https://via.placeholder.com/800x600?text=娴佺▼鍥�+${record.id}` + diagramVisible.value = true +} + +// 閿�姣丅PMN缂栬緫鍣� +const destroyBpmnEditor = () => { + if (bpmnModeler.value) { + bpmnModeler.value.destroy() + bpmnModeler.value = null + } +} + +// 鍒濆鍖朆PMN缂栬緫鍣� +const initBpmnEditor = async (xml) => { + await nextTick() + + // 鍏堥攢姣佹棫鐨勭紪杈戝櫒 + destroyBpmnEditor() + + try { + // 鍒涘缓鏂扮殑缂栬緫鍣ㄥ疄渚� + bpmnModeler.value = new BpmnModeler({ + container: bpmnEditor.value, + }) + + // 鍔犺浇XML鎴栭粯璁ゆ祦绋嬪浘 + const diagram = xml || ` + <?xml version="1.0" encoding="UTF-8"?> + <bpmn:definitions + xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" + xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" + xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" + xmlns:di="http://www.omg.org/spec/DD/20100524/DI" + id="Definitions_1" + targetNamespace="http://bpmn.io/schema/bpmn"> + <bpmn:process id="Process_1" isExecutable="false"> + <bpmn:startEvent id="StartEvent_1" /> + </bpmn:process> + <bpmndi:BPMNDiagram id="BPMNDiagram_1"> + <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1"> + <bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1"> + <dc:Bounds x="173" y="102" width="36" height="36" /> + </bpmndi:BPMNShape> + </bpmndi:BPMNPlane> + </bpmndi:BPMNDiagram> + </bpmn:definitions> + ` + + await bpmnModeler.value.importXML(diagram) + } catch (err) { + console.error('Error rendering diagram', err) + message.error('鍒濆鍖栨祦绋嬪浘缂栬緫鍣ㄥけ璐�: ' + err.message) + } +} + +// 鏄剧ず鍒涘缓鏂版祦绋嬫ā鎬佹 +const showCreateModal = () => { + isCreateMode.value = true + editorTitle.value = '鍒涘缓鏂版祦绋嬪浘' + editorVisible.value = true + + // 閲嶇疆琛ㄥ崟 + newProcess.value = { + name: '', + key: '', + description: '' + } + + // 鍒濆鍖栫紪杈戝櫒 + initBpmnEditor() +} + +// 缂栬緫娴佺▼鍥� +const editDiagram = async (record) => { + isCreateMode.value = false + currentProcessDefinition.value = record + editorTitle.value = `缂栬緫娴佺▼ - ${record.name}` + editorVisible.value = true + + // 妯℃嫙鍔犺浇娴佺▼瀹氫箟XML + const mockXml = ` + <?xml version="1.0" encoding="UTF-8"?> + <bpmn:definitions + xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" + xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" + xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" + xmlns:di="http://www.omg.org/spec/DD/20100524/DI" + id="Definitions_1" + targetNamespace="http://bpmn.io/schema/bpmn"> + <bpmn:process id="${record.id}" name="${record.name}" isExecutable="true"> + <bpmn:startEvent id="StartEvent_1" name="寮�濮�" /> + <bpmn:userTask id="UserTask_1" name="鎻愪氦鐢宠" /> + <bpmn:sequenceFlow id="Flow_1" sourceRef="StartEvent_1" targetRef="UserTask_1" /> + <bpmn:endEvent id="EndEvent_1" name="缁撴潫" /> + <bpmn:sequenceFlow id="Flow_2" sourceRef="UserTask_1" targetRef="EndEvent_1" /> + </bpmn:process> + <bpmndi:BPMNDiagram id="BPMNDiagram_1"> + <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="${record.id}"> + <bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1"> + <dc:Bounds x="173" y="102" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="UserTask_1_di" bpmnElement="UserTask_1"> + <dc:Bounds x="280" y="80" width="100" height="80" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNShape id="EndEvent_1_di" bpmnElement="EndEvent_1"> + <dc:Bounds x="450" y="102" width="36" height="36" /> + </bpmndi:BPMNShape> + <bpmndi:BPMNEdge id="Flow_1_di" bpmnElement="Flow_1"> + <di:waypoint x="209" y="120" /> + <di:waypoint x="280" y="120" /> + </bpmndi:BPMNEdge> + <bpmndi:BPMNEdge id="Flow_2_di" bpmnElement="Flow_2"> + <di:waypoint x="380" y="120" /> + <di:waypoint x="450" y="120" /> + </bpmndi:BPMNEdge> + </bpmndi:BPMNPlane> + </bpmndi:BPMNDiagram> + </bpmn:definitions> + ` + + // 鍒濆鍖栫紪杈戝櫒骞跺姞杞絏ML + initBpmnEditor(mockXml) +} + +// 淇濆瓨娴佺▼鍥句慨鏀� +const handleEditorOk = async () => { + editorSaving.value = true + + try { + if (isCreateMode.value) { + // 楠岃瘉琛ㄥ崟 + if (!newProcess.value.name || !newProcess.value.key) { + message.error('璇峰~鍐欐祦绋嬪悕绉板拰Key') + return + } + + // 鑾峰彇XML + const { xml } = await bpmnModeler.value.saveXML({ format: true }) + console.log('鏂版祦绋媂ML:', xml) + + // 妯℃嫙鍒涘缓鏂版祦绋� + await new Promise(resolve => setTimeout(resolve, 1000)) + + // 娣诲姞鍒板垪琛� + const newId = Math.max(...definitions.value.map(d => parseInt(d.id))) + 1 + definitions.value.unshift({ + id: newId.toString(), + name: newProcess.value.name, + key: newProcess.value.key, + version: 1 + }) + + message.success('鏂版祦绋嬪垱寤烘垚鍔�') + } else { + // 鑾峰彇淇敼鍚庣殑XML + const { xml } = await bpmnModeler.value.saveXML({ format: true }) + console.log('淇敼鍚庣殑XML:', xml) + + // 妯℃嫙淇濆瓨 + await new Promise(resolve => setTimeout(resolve, 1000)) + + message.success('娴佺▼鍥句繚瀛樻垚鍔�') + } + + editorVisible.value = false + } catch (error) { + console.error('Error saving BPMN diagram', error) + message.error('鎿嶄綔澶辫触: ' + error.message) + } finally { + editorSaving.value = false + } +} + +// 鍒犻櫎娴佺▼瀹氫箟 +const deleteDefinition = (record) => { + Modal.confirm({ + title: '纭鍒犻櫎娴佺▼?', + content: `纭畾瑕佸垹闄ゆ祦绋� "${record.name}" 鍚楋紵姝ゆ搷浣滀笉鍙仮澶嶃�俙, + okText: '纭', + okType: 'danger', + cancelText: '鍙栨秷', + onOk() { + // 妯℃嫙鍒犻櫎 + definitions.value = definitions.value.filter(item => item.id !== record.id) + message.success('娴佺▼鍒犻櫎鎴愬姛') + } + }) +} + +// 妯℃�佹鍏抽棴鍚庢竻鐞� +const handleEditorAfterClose = () => { + destroyBpmnEditor() +} + +const handleEditorCancel = () => { + editorVisible.value = false +} + +const handleDiagramCancel = () => { + diagramVisible.value = false +} + +// 鍒濆鍖栧姞杞芥暟鎹� +onMounted(() => { + const params = { + page: 1, + size: 10 + } + fetchProcessDefinitions(params) +}) +</script> + +<style scoped> +.process-definition-container { + padding: 20px; + background: #fff; +} + +.table-actions { + margin-bottom: 16px; + display: flex; + justify-content: flex-end; +} + +.editor-container { + height: 600px; + display: flex; + flex-direction: column; +} +.bpmn-editor { + flex: 1; + border: 1px solid #d9d9d9; + border-radius: 2px; + margin-top: 16px; + min-height: 500px; /* 纭繚缂栬緫鍣ㄦ湁瓒冲楂樺害 */ +} + +.create-form { + padding: 16px; + background: #fafafa; + border-radius: 2px; + border: 1px solid #d9d9d9; + margin-bottom: 16px; +} + +/* 闅愯棌BPMN姘村嵃 */ +.bpmn-editor :deep(.bjs-powered-by) { + display: none !important; +} +.editor-container { + flex: 1; + display: flex; + flex-direction: column; + height: 100%; + overflow: hidden; +} + +.bpmn-editor { + flex: 1; + min-height: 0; /* 閲嶈锛氬厑璁竑lex瀹瑰櫒鏀剁缉 */ + border: 1px solid #d9d9d9; + border-radius: 2px; + margin-top: 16px; +} + +.create-form { + padding: 16px; + background: #fafafa; + border-radius: 2px; + border: 1px solid #d9d9d9; + margin-bottom: 16px; +} + +/* 闅愯棌BPMN姘村嵃 */ +.bpmn-editor :deep(.bjs-powered-by) { + display: none !important; +} + +/* 纭繚BPMN宸ュ叿鏍忓彲瑙� */ +.bpmn-editor :deep(.djs-palette) { + top: 20px; + left: 20px; +} +</style> diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/dynamicForm/index.vue b/ruoyi-ui/apps/web-antd/src/views/tool/dynamicForm/index.vue index 0bd9f76..aba7965 100644 --- a/ruoyi-ui/apps/web-antd/src/views/tool/dynamicForm/index.vue +++ b/ruoyi-ui/apps/web-antd/src/views/tool/dynamicForm/index.vue @@ -1,5 +1,5 @@ <template> - <fc-designer ref="designer" /> + <fc-designer ref="designer" :config="config" @save="handleSave" /> </template> <script setup> @@ -16,4 +16,12 @@ const loadJson = (json) => { designer.value.setJson(json); }; +const config = ref({ + showSaveBtn: true, + showPreviewBtn: true, +}); +function handleSave(data) { + //淇濆瓨璁捐瑙勫垯 + console.log(data); +} </script> diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/data.tsx b/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/data.tsx new file mode 100644 index 0000000..365557c --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/data.tsx @@ -0,0 +1,109 @@ +import type { FormSchemaGetter } from '#/adapter/form'; +import type { VxeGridProps } from '#/adapter/vxe-table'; +import { h } from 'vue'; +import { FolderIcon, VbenIcon } from '@vben/icons'; + +export const querySchema: FormSchemaGetter = () => [ + { + component: 'Input', + fieldName: 'name', + label: '椤甸潰鍚嶇О', + }, + { + component: 'Select', + componentProps: { + options: [ + { label: '姝e父', value: '0' }, + { label: '鍋滅敤', value: '1' }, + ], + }, + fieldName: 'status', + label: '椤甸潰鐘舵��', + }, +]; + +export const columns: VxeGridProps['columns'] = [ + { + title: '椤甸潰鍚嶇О', + field: 'name', + }, + { + title: '涓婄骇鐩綍', + field: 'menuParentName', + + }, + { + title: '鐘舵��', + field: 'status', + slots: { + default: ({ row }) => { + return row.status === '0' ? '姝e父' : '鍋滅敤'; + }, + }, + }, + { + title: '鍒涘缓鏃堕棿', + field: 'createTime', + }, + { + field: 'action', + fixed: 'right', + slots: { default: 'action' }, + title: '鎿嶄綔', + }, +]; + +export const drawerSchema = () => [ + { + component: 'Input', + fieldName: 'name', + label: '椤甸潰鍚嶇О', + rules: 'required', + }, + { + component: 'TreeSelect', + fieldName: 'menuParentId', + label: '涓婄骇鐩綍', + componentProps: { + allowClear: true, + showSearch: true, + }, + rules: 'selectRequired', + }, + { + component: 'Select', + fieldName: 'status', + label: '鐘舵��', + componentProps: { + options: [ + { label: '姝e父', value: '0' }, + { label: '鍋滅敤', value: '1' }, + ], + }, + rules: 'selectRequired', + }, + { + component: 'CheckboxGroup', + fieldName: 'actionsFunc', + label: '鍚敤鍔熻兘', + defaultValue: ['add', 'edit', 'delete', 'query'], + componentProps: { + options: [ + { label: '鏂板', value: 'add' }, + { label: '缂栬緫', value: 'edit' }, + { label: '鍒犻櫎', value: 'delete' }, + { label: '鏌ヨ', value: 'query' }, + ], + }, + rules: 'required', + }, + { + component: 'Input', + fieldName: 'remark', + label: '澶囨敞', + componentProps: { + type: 'textarea', + rows: 2, + }, + }, +]; diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/index.vue b/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/index.vue new file mode 100644 index 0000000..aa8342d --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/index.vue @@ -0,0 +1,217 @@ +<template> + <Page v-if="isAdmin" :auto-content-height="true"> + <BasicTable table-title="椤甸潰璁捐鍣�" > + <template #toolbar-tools> + <Space> + <a-button type="primary" @click="handleAdd">鏂板</a-button> + </Space> + </template> + <template #action="{ row }"> + <Space> + <ghost-button @click="handleEdit(row)">缂栬緫</ghost-button> + <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)"> + <ghost-button danger @click.stop="">鍒犻櫎</ghost-button> + </Popconfirm> + </Space> + </template> + </BasicTable> + <PageDrawer ref="pageModalRef" @reload="tableApi.query()" :menu-array="menuArray" /> + </Page> + <Fallback v-else description="鎮ㄦ病鏈夐〉闈㈢敓鎴愬櫒鐨勮闂潈闄�" status="403" /> +</template> + +<script setup lang="ts"> +import type { VbenFormProps } from '@vben/common-ui'; +import type { VxeGridProps } from '#/adapter/vxe-table'; +import { computed, ref, onMounted } from 'vue'; +import { useAccess } from '@vben/access'; +import { Fallback, Page, useVbenDrawer } from '@vben/common-ui'; +import { eachTree, getVxePopupContainer } from '@vben/utils'; +import { Popconfirm, Space } from 'ant-design-vue'; +import { useVbenVxeGrid } from '#/adapter/vxe-table'; +import { columns, querySchema } from './data'; +import PageDrawer from './page-drawer.vue'; +import FcDesigner from '@form-create/designer'; +import { pageList, pageRemove } from '#/api/tool/page-designer'; +import { menuList } from '../../../api/system/menu'; +import { listToTree} from '@vben/utils'; +// 绉婚櫎mock鏁版嵁 +// const pageList = async (params: any) => { ... }; +// const pageRemove = async (ids: number[]) => {}; +const menuArray = ref([]); +const processedMenuTree = ref([]); +onMounted(async () => { + try { + // 鑾峰彇鍘熷鑿滃崟鏁版嵁 + const rawMenuData = await menuList(); + menuArray.value = rawMenuData; + + // 澶勭悊鑿滃崟鏁版嵁 + processMenuData(); + } catch (error) { + console.error('鑾峰彇鑿滃崟鏁版嵁澶辫触:', error); + } +}); +// 澶勭悊鑿滃崟鏁版嵁鐨勫嚱鏁� +const processMenuData = () => { + if (!menuArray.value || menuArray.value.length === 0) return; + + // 1. 杩囨护鎺夋寜閽被鍨�(F)鍜岃彍鍗曠被鍨�(C) + const filteredList = menuArray.value.filter(item => + item.menuType !== 'F' && item.menuType !== 'C' + ); + + // 2. 杞崲涓烘爲褰㈢粨鏋� + const treeData = listToTree(filteredList, { + id: 'menuId', + pid: 'parentId' + }); + + // 3. 娣诲姞鏍硅妭鐐� + processedMenuTree.value = [ + { + menuId: 0, + parentId: 0, + menuName: '鏍圭洰褰�', + children: treeData + } + ]; +}; +const formOptions: VbenFormProps = { + commonConfig: { + labelWidth: 80, + componentProps: { + allowClear: true, + }, + }, + schema: querySchema(), + wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4', +}; +const getFullMenuPath = (id: number) => { + if (!processedMenuTree.value || processedMenuTree.value.length === 0) return ''; + + // 閫掑綊鏌ユ壘鑿滃崟璺緞 + const findPath = (tree, currentId, path = []): string[] | null => { + for (const item of tree) { + if (item.menuId === currentId) { + return [...path, item.menuName]; + } + if (item.children && item.children.length > 0) { + const found = findPath(item.children, currentId, [...path, item.menuName]); + if (found) return found; + } + } + return null; + }; + + const path = findPath(processedMenuTree.value, id); + return path ? path.join(' / ') : '鏍圭洰褰�'; +}; +const gridOptions: VxeGridProps = { + columns, + height: 'auto', + keepSource: true, + pagerConfig: { + enabled: true, + }, + proxyConfig: { + ajax: { + query: async ({ page }, formValues = {}) => { + const resp = await pageList({ + pageNum: page.currentPage, + pageSize: page.pageSize, + ...formValues, + }); + + // 澶勭悊杩斿洖鏁版嵁锛屾坊鍔爉enuParentName + const processedRows = resp.rows.map(row => { + return { + ...row, + menuParentName: getFullMenuPath(row.menuParentId) || '鏍圭洰褰�' + }; + }); + return { + rows: processedRows, // 浣跨敤澶勭悊鍚庣殑鏁版嵁 + total: resp.total, + }; + }, + }, + }, + rowConfig: { + keyField: 'id', + }, + id: 'tool-page-designer-index', + columnConfig: { resizable: true }, +}; + +const [BasicTable, tableApi] = useVbenVxeGrid({ + formOptions, + gridOptions, +}); + +const designer = ref(); +const pageModalRef = ref(); + +function getFormJson() { + // 鑾峰彇璁捐缁撴灉 + const json = designer.value.getRule(); + // 浣犲彲浠ュ皢 json 瀛樺埌鍚庣 +} + +function setFormJson(json) { + // 鍔犺浇宸叉湁璁捐 + designer.value.setRule(json); +} + +function handleAdd() { + pageModalRef.value.open({ update: false }); +} + +function handleEdit(record) { + pageModalRef.value.open({ id: record.id, update: true }); +} + +async function handleDelete(row: any) { + await pageRemove([row.id]); + await tableApi.query(); +} + +function handleSubAdd(row) { + pageModalRef.value.open({ id: row.id, update: false }); +} + +const { hasAccessByRoles } = useAccess(); +const isAdmin = computed(() => { + return hasAccessByRoles(['admin', 'superadmin']); +}); +</script> + +<style scoped> +.designer-page { + background: #f5f6fa; + padding: 16px; + min-height: 100vh; +} +.designer-query-form { + background: #fff; + padding: 16px 16px 0 16px; + border-radius: 6px; + margin-bottom: 12px; + display: flex; + flex-wrap: wrap; + align-items: center; +} +.designer-toolbar { + background: #fff; + padding: 12px 16px; + border-radius: 6px; + margin-bottom: 12px; + display: flex; + gap: 8px; +} +.designer-table { + background: #fff; + border-radius: 6px; + padding: 0 0 16px 0; +} +</style> diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/page-drawer.vue b/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/page-drawer.vue new file mode 100644 index 0000000..b8ac9be --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/tool/page-designer/page-drawer.vue @@ -0,0 +1,337 @@ +<script setup lang="ts"> +import { computed, ref, watch, nextTick, onMounted } from 'vue'; +import { Modal, message, FormItem } from 'ant-design-vue'; +import { $t } from '@vben/locales'; +import { useVbenForm } from '#/adapter/form'; +import { drawerSchema } from './data'; +import FcDesigner from '@form-create/designer'; + +import { listToTree, addFullName, getPopupContainer } from '@vben/utils'; +import { pageAdd, pageUpdate, pageInfo } from '#/api/tool/page-designer'; + +interface ModalProps { + id?: number | string; + update: boolean; +} + + +const emit = defineEmits<{ reload: [] }>(); + +const isUpdate = ref(false); +const title = computed(() => { + return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add'); +}); + +const [BasicForm, formApi] = useVbenForm({ + commonConfig: { + componentProps: { + class: 'w-full', + }, + formItemClass: 'col-span-1', + labelWidth: 90, + }, + schema: drawerSchema(), + showDefaultActions: false, + wrapperClass: 'grid-cols-5', +}); + +const designer = ref(); +const selectedFields = ref([]); // 澶氶�夋閫変腑鐨勫瓧娈祂ey +const fieldOptions = ref([]); // 璁捐鍖烘墍鏈夊瓧娈� +const modalVisible = ref(false); +const modalLoading = ref(false); +const currentEditId = ref<string | number>(''); // 褰撳墠缂栬緫鐨処D +const fullMenuTree = ref([]); +const props=defineProps({ + menuArray: { + type: Array, + required: true, + default: () => [] + } +}); +// 鎵撳紑寮圭獥 +const open = async (params: ModalProps = { update: false }) => { + try { + + modalVisible.value = true; + modalLoading.value = true; + isUpdate.value = params.update; + currentEditId.value = params.id || ''; // 淇濆瓨褰撳墠缂栬緫鐨処D + await setupPageSelect(); + + if (params.id) { + await formApi.setFieldValue('menuParentId', params.id); + if (params.update) { + // 鑾峰彇璇︽儏鏁版嵁 + const record = await pageInfo(params.id); + + // 璁剧疆鍩虹琛ㄥ崟鏁版嵁 + const menuParentId = String(record.menuParentId || record.parentId || ''); + await formApi.setValues({ + name: record.name, + menuParentId: menuParentId, // 鐢� menuParentId 瀛楁 + status: record.status, + remark: record.remark, + actionsFunc: record.actionsFunc ? JSON.parse(record.actionsFunc) : ['add', 'edit', 'delete', 'query'] + }); + + // 鍔犺浇琛ㄥ崟璁捐鏁版嵁 + if (record.formJson) { + try { + const formRule = JSON.parse(record.formJson); + console.log('璁捐鍣ㄨ鍒�:', formRule); + designer.value.setRule(formRule); + + // 鏇存柊瀛楁閫夐」 + await nextTick(); + updateFieldOptions(); + + // 鎭㈠閫変腑鐨勫瓧娈� + if (record.showColumn) { + selectedFields.value = JSON.parse(record.showColumn); + } + } catch (e) { + console.error('鍔犺浇琛ㄥ崟璁捐鏁版嵁澶辫触:', e); + message.error('鍔犺浇琛ㄥ崟璁捐鏁版嵁澶辫触'); + } + } + } + } else { + // 鏂板鏃堕噸缃暟鎹� + designer.value?.setRule([]); + selectedFields.value = []; + await formApi.resetForm(); + } + } catch (error) { + console.error('鎵撳紑寮圭獥澶辫触:', error); + message.error('鍔犺浇鏁版嵁澶辫触'); + } finally { + modalLoading.value = false; + } +}; +const close = () => { + modalVisible.value = false; +}; + +defineExpose({ open, close }); + +async function setupPageSelect() { + // 鑾峰彇鑿滃崟鏁版嵁 + if (!props.menuArray || props.menuArray.length === 0) { + await nextTick(); // 绛夊緟鍙兘鐨勫紓姝ュ姞杞� + if (!props.menuArray || props.menuArray.length === 0) { + console.warn('menuArray is empty'); + return; + } + } + // 杩囨护鎺夋寜閽被鍨� + const filteredList = props.menuArray.filter(item => item.menuType !== 'F' && item.menuType !== 'C'); + // 鏀寔i18n + filteredList.forEach(item => { item.menuName = $t(item.menuName); }); + // 杞负鏍戠粨鏋� + const menuTree = listToTree(filteredList, { id: 'menuId', pid: 'parentId' }); + // 閫掑綊鏄犲皠 menuId -> menuParentId + function mapMenuIdToParentId(list) { + return list.map(item => { + const newItem = { ...item, menuParentId: item.menuId }; + if (item.children) { + newItem.children = mapMenuIdToParentId(item.children); + } + return newItem; + }); + } + fullMenuTree.value = [ + { + menuId: 0, + menuParentId: 0, + menuName: $t('menu.root'), + children: mapMenuIdToParentId(menuTree), + }, + ]; + // 鐢熸垚鍏ㄨ矾寰勫悕 + addFullName(fullMenuTree.value, 'menuName', ' / '); + + formApi.updateSchema([ + { + componentProps: { + fieldNames: { + label: 'menuName', + value: 'menuId', // 鐢� menuId + children: 'children' + }, + getPopupContainer, + listHeight: 300, + showSearch: true, + treeData: fullMenuTree.value, + treeDefaultExpandAll: false, + treeDefaultExpandedKeys: [0], + treeLine: { showLeafIcon: false }, + treeNodeFilterProp: 'menuName', + treeNodeLabelProp: 'fullName', + }, + fieldName: 'menuParentId', // 鐢� menuParentId + }, + ]); +} + + +// 鍚屾鎵�鏈夊瓧娈靛埌閫変腑鐘舵�� +const syncAllFields = () => { + // 鑾峰彇琛ㄥ崟缁勪欢鐨勮鍒欐弿杩� + const formDesc = designer.value?.getFormDescription?.(); + + if (!formDesc || !Array.isArray(formDesc)) { + message.warning('鏆傛棤璁捐鏁版嵁'); + return; + } + + // 鎻愬彇瀛楁淇℃伅 + const allFields = formDesc + .filter(item => item && item.field && item.title) + .map(item => ({ + title: item.title, + field: item.field + })); + + + if (allFields.length === 0) { + message.warning('鏈壘鍒板彲鐢ㄥ瓧娈�'); + return; + } + + // 鏇存柊瀛楁閫夐」 + fieldOptions.value = allFields.map(item => ({ + label: item.title, + value: item.field + })); + + // 閫変腑鎵�鏈夊瓧娈� + selectedFields.value = allFields.map(item => item.field); + message.success(`宸插悓姝� ${allFields.length} 涓瓧娈礰); +}; + +// 澶勭悊璁捐鍣ㄥ彉鍖� +const handleDesignerChange = () => { + nextTick(() => { + updateFieldOptions(); + }); +}; + +// 褰撹璁″櫒鍐呭鍙樺寲鏃舵洿鏂板瓧娈甸�夐」 +const updateFieldOptions = () => { + // 鑾峰彇琛ㄥ崟缁勪欢鐨勮鍒欐弿杩� + const formDesc = designer.value?.getFormDescription?.(); + if (!formDesc || !Array.isArray(formDesc)) return; + + const fields = formDesc + .filter(item => item && item.field && item.title) + .map(item => ({ + title: item.title, + field: item.field + })); + + fieldOptions.value = fields.map(item => ({ + label: item.title, + value: item.field + })); +}; + +// 鐩戝惉璁捐鍣ㄥ唴瀹瑰彉鍖� +watch(() => modalVisible.value, (val) => { + if (val) { + nextTick(() => updateFieldOptions()); + } +}); + +async function handleOk() { + try { + modalLoading.value = true; + const { valid } = await formApi.validate(); + if (!valid) { + return; + } + const data = await formApi.getValues(); + + // 濡傛灉鏄紪杈戞ā寮忥紝娣诲姞id瀛楁 + if (isUpdate.value) { + data.id = currentEditId.value; + } + + // 鑾峰彇琛ㄥ崟璁捐 JSON + data.formJson = designer.value.getJson(); + // 娣诲姞閫変腑鐨勫瓧娈� + data.showColumn = JSON.stringify(selectedFields.value); + // 杞崲鍚敤鍔熻兘涓篔SON瀛楃涓� + data.actionsFunc = JSON.stringify(data.actionsFunc); + + // 鍚屾涓�娆″瓧娈靛閫� + updateFieldOptions(); + await (isUpdate.value ? pageUpdate(data) : pageAdd(data)); + emit('reload'); + close(); + message.success('淇濆瓨鎴愬姛'); + } catch (error) { + console.error(error); + } finally { + modalLoading.value = false; + } +} + +function handleCancel() { + close(); +} +</script> + +<template> + <a-modal + v-model:open="modalVisible" + :title="title" + :width="'80vw'" + :confirm-loading="modalLoading" + @ok="handleOk" + @cancel="handleCancel" + :bodyStyle="{ padding: '24px', minHeight: '60vh' }" + destroyOnClose + wrapClassName="page-designer-modal" + > + <template #closeIcon> + <span></span> + </template> + <BasicForm /> + <div style="margin-top: 16px;"> + <FcDesigner + ref="designer" + @update="handleDesignerChange" + @change="handleDesignerChange" + @add-rule="handleDesignerChange" + @remove-rule="handleDesignerChange" + + /> + <div style="margin-top: 8px; display: flex; justify-content: flex-end;"> + <a-button type="primary" ghost @click="syncAllFields"> + 鍚屾璁捐瀛楁鍒拌〃鏍� + </a-button> + </div> + </div> + <FormItem label="琛ㄦ牸瀛楁" style="margin-top: 24px;"> + <a-checkbox-group + v-model:value="selectedFields" + :options="fieldOptions" + style="width:100%;display:flex;flex-wrap:wrap;gap:8px" + /> + </FormItem> + <template #empty> + <div style="padding: 32px 0; color: #999; text-align: center;"> + 鏆傛棤鏁版嵁 + </div> + </template> + </a-modal> +</template> + +<style scoped> +.page-designer-modal .ant-modal { + max-width: 1200px; +} + + +</style> diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx b/ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx new file mode 100644 index 0000000..62d35c1 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/tool/template/data.tsx @@ -0,0 +1,86 @@ +import type { FormSchemaGetter } from '#/adapter/form'; +import type { VxeGridProps } from '#/adapter/vxe-table'; + +export const querySchema: FormSchemaGetter = () => [ + { + component: 'Input', + fieldName: 'name', + label: '妯$増鍚嶇О', + }, + { + component: 'Select', + componentProps: { + options: [ + { label: '姝e父', value: '1' }, + { label: '鍋滅敤', value: '0' }, + ], + }, + fieldName: 'status', + label: '妯$増鐘舵��', + }, +]; + +export const columns = [ + { + title: '濮撳悕', + dataIndex: 'name', + auth: 'test', // 鏍规嵁鏉冮檺鎺у埗鏄惁鏄剧ず: 鏃犳潈闄愶紝涓嶆樉绀� + } +]; + +export const drawerSchema = () => [ + { + component: 'Input', + fieldName: 'name', + label: '妯$増鍚嶇О', + rules: 'required', + }, + { + component: 'Select', + fieldName: 'pageDesignId', + label: '椤甸潰璁捐', + componentProps: { + allowClear: true, + showSearch: true, + filterOption: (input: string, option: any) => { + return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0; + }, + }, + rules: 'selectRequired', + }, + { + component: 'Select', + fieldName: 'templateType', + label: '妯$増绫诲瀷', + componentProps: { + options: [ + { label: '鍒楄〃椤�', value: 'list' }, + { label: '琛ㄥ崟椤�', value: 'form' }, + { label: '璇︽儏椤�', value: 'detail' }, + { label: '浠〃鏉�', value: 'dashboard' }, + ], + }, + rules: 'selectRequired', + }, + { + component: 'Select', + fieldName: 'status', + label: '鐘舵��', + componentProps: { + options: [ + { label: '姝e父', value: '1' }, + { label: '鍋滅敤', value: '0' }, + ], + }, + rules: 'selectRequired', + }, + { + component: 'Input', + fieldName: 'remark', + label: '澶囨敞', + componentProps: { + type: 'textarea', + rows: 2, + }, + }, +]; \ No newline at end of file diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue b/ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue new file mode 100644 index 0000000..a37a390 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/tool/template/index.vue @@ -0,0 +1,397 @@ +<template> + <Page v-if="isAdmin && pageId" :auto-content-height="true"> + <BasicTable + :key="tableKey" + :table-title="pageDesignDetail?.name || '妯℃澘鍒楄〃'" + :grid-options="gridOptions" + > + <template #toolbar-tools> + <Space> + <a-button v-if="showAction('add')" type="primary" @click="handleAdd">鏂板</a-button> + </Space> + </template> + <template #action="{ row }"> + <Space> + <ghost-button v-if="showAction('edit')" @click="handleEdit(row)">缂栬緫</ghost-button> + <Popconfirm v-if="showAction('delete')" :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)"> + <ghost-button danger @click.stop="">鍒犻櫎</ghost-button> + </Popconfirm> + </Space> + </template> + </BasicTable> + <TemplateDrawer ref="templateModalRef" @reload="tableApi.query()" /> + </Page> + <Fallback v-else description="鏈寚瀹� pageId锛屾棤娉曡闂椤甸潰" status="403" /> +</template> + +<script setup lang="ts"> +import type { VbenFormProps } from '@vben/common-ui'; +import type { VxeGridProps } from '#/adapter/vxe-table'; +import { computed, ref, onMounted, watch } from 'vue'; +import { useRoute, useRouter } from 'vue-router'; +import { useAccess } from '@vben/access'; +import { Fallback, Page } from '@vben/common-ui'; +import { getVxePopupContainer } from '@vben/utils'; +import { Popconfirm, Space, Spin as ASpin } from 'ant-design-vue'; +import { useVbenVxeGrid } from '#/adapter/vxe-table'; +import { columns as baseColumns, querySchema } from './data'; +import TemplateDrawer from './template-drawer.vue'; +import { templateList, templateRemove } from '#/api/tool/template'; +import { pageInfo } from '#/api/tool/page-designer'; + +const route = useRoute(); +const router = useRouter(); +const pageId = ref<string | number>(''); +const pageDesignDetail = ref<any>(null); // 椤甸潰璁捐璇︽儏 +const loading = ref(true); // 鍔犺浇涓� + +// 鍔ㄦ�乧olumns +const dynamicColumns = ref([ + { field: 'id', title: 'ID', width: 100 }, + { field: 'formData', title: '琛ㄥ崟鏁版嵁', minWidth: 160 }, + { field: 'action', title: '鎿嶄綔', width: 160, slots: { default: 'action' } } +]); + +// 鐢ㄤ簬琛ㄦ牸閲嶆柊娓叉煋鐨� key +const tableKey = ref(0); + +// 鏇存柊鍔ㄦ�佸垪鐨勫嚱鏁� +function updateDynamicColumns() { + if (!pageDesignDetail.value || !pageDesignDetail.value.showColumn || !pageDesignDetail.value.formJson) { + console.log('浣跨敤榛樿鍒�'); + return; + } + + try { + const showFields = JSON.parse(pageDesignDetail.value.showColumn); + const formFields = JSON.parse(pageDesignDetail.value.formJson); + const cols = showFields.map(field => { + const fieldDef = formFields.find(f => f.field === field); + return { + field: field, + title: fieldDef ? fieldDef.title : field, + minWidth: 120, + align: 'center', + }; + }); + + cols.push({ + field: 'action', + title: '鎿嶄綔', + width: 160, + slots: { default: 'action' }, + }); + + dynamicColumns.value = cols; + gridOptions.value = { ...gridOptions.value, columns: cols }; + tableKey.value++; + } catch (error) { + const fallbackCols = [ + { field: 'id', title: 'ID', width: 100 }, + { field: 'formData', title: '琛ㄥ崟鏁版嵁', minWidth: 160 }, + { field: 'action', title: '鎿嶄綔', width: 160, slots: { default: 'action' } } + ]; + dynamicColumns.value = fallbackCols; + gridOptions.value = { ...gridOptions.value, columns: fallbackCols }; + tableKey.value++; + } +} + + +// 鍔ㄦ�佹寜閽� +function showAction(action: string) { + if (!pageDesignDetail.value || !pageDesignDetail.value.actionsFunc) { + return true; + } + + try { + const actions = JSON.parse(pageDesignDetail.value.actionsFunc); + if (!Array.isArray(actions)) { + console.warn('actionsFunc 涓嶆槸鏁扮粍鏍煎紡:', pageDesignDetail.value.actionsFunc); + return true; + } + + return actions.includes(action); + } catch (error) { + console.error('瑙f瀽 actionsFunc 澶辫触:', error); + return true; + } +} + +// 鑾峰彇 pageId锛屽彧鐢� params +function getPageId() { + const segments = window.location.pathname.split('/'); + return segments[segments.length - 1] || ''; +} + +onMounted(() => { + const initialPageId = getPageId(); + console.log('鑾峰彇鍒扮殑 pageId:', initialPageId); + + if (initialPageId) { + pageId.value = initialPageId; + handlePageIdChange(); + } else { + loading.value = false; + } +}); + +// 鐩戝惉璺敱鍙樺寲锛岃嚜鍔ㄦ洿鏂� pageId +watch( + () => [route.meta.pageId, route.params.pageId, route.query.pageId], + (newValues, oldValues) => { + // 鍙湁褰撳�肩湡姝e彉鍖栨椂鎵嶅鐞� + if (JSON.stringify(newValues) !== JSON.stringify(oldValues)) { + const newPageId = getPageId(); + console.log('璺敱鍙樺寲鍚� pageId:', newPageId); + + // 鍙湁褰� pageId 鐪熸鍙樺寲鏃舵墠鏇存柊 + if (newPageId !== pageId.value) { + pageId.value = newPageId; + handlePageIdChange(); + tableApi.query(); + } + } + }, + { deep: true } +); + +// pageId鍙樺寲鏃惰嚜鍔ㄨ幏鍙栭〉闈㈣璁¤鎯� +async function handlePageIdChange() { + loading.value = true; + console.log(`[handlePageIdChange] 寮�濮嬪鐞� pageId: ${pageId.value}`); + try { + if (pageId.value) { + const detail = await pageInfo(pageId.value); + console.log('[handlePageIdChange] 鑾峰彇鍒扮殑椤甸潰璁捐璇︽儏 (detail):', JSON.parse(JSON.stringify(detail))); + + // 澶勭悊鏁版嵁锛岄伩鍏嶅惊鐜紩鐢� + const safeDetail = { + id: detail.id, + name: detail.name, + menuParentId: detail.menuId, + status: detail.status, + remark: detail.remark, + formJson: detail.formJson, + showColumn: detail.showColumn, + actionsFunc: detail.actionsFunc, + createTime: detail.createTime, + updateTime: detail.updateTime, + createBy: detail.createBy, + updateBy: detail.updateBy, + createDept: detail.createDept + }; + + pageDesignDetail.value = safeDetail; + console.log('[handlePageIdChange] 璁剧疆鐨� pageDesignDetail.value:', JSON.parse(JSON.stringify(pageDesignDetail.value))); + updateDynamicColumns(); + } else { + pageDesignDetail.value = null; + updateDynamicColumns(); + } + } catch (error) { + console.error('[handlePageIdChange] 鑾峰彇椤甸潰璁捐璇︽儏澶辫触:', error); + pageDesignDetail.value = null; + updateDynamicColumns(); + } finally { + loading.value = false; + } +} + +const formOptions: VbenFormProps = { + commonConfig: { + labelWidth: 80, + componentProps: { + allowClear: true, + }, + }, + schema: querySchema(), + wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4', +}; + +const gridOptions = ref<VxeGridProps>({ + columns: dynamicColumns.value, + height: 'auto', + keepSource: true, + pagerConfig: { + enabled: true, + }, + proxyConfig: { + ajax: { + query: async ({ page }, formValues = {}) => { + try { + console.log('鏌ヨ鍙傛暟:', { page, formValues }); + const queryParams = { + pageNum: page.currentPage, + pageSize: page.pageSize, + ...formValues, + }; + if (pageId.value) { + queryParams.pageId = pageId.value; + } + const resp = await templateList(queryParams); + // 澶勭悊姣忔潯 row 鐨� formData + const rows = (resp.rows || []).map(row => { + let formData = {}; + try { + if (row.formData) { + formData = JSON.parse(row.formData); + console.log('瑙f瀽鍚庣殑 formData:', formData); + // 鍒犻櫎鍘熷鐨� formData 瀛楁锛屽洜涓烘垜浠凡缁忓睍寮�瀹冪殑鍐呭 + const { formData: _, ...restRow } = row; + // 杩斿洖灞曞紑鍚庣殑鏁版嵁 + return { + ...restRow, + ...formData + }; + } + } catch (e) { + console.error('瑙f瀽 formData 澶辫触:', e); + } + return row; + }); + console.log('澶勭悊鍚庣殑 rows:', rows); + return { + rows, + total: resp.total || 0, + }; + } catch (error) { + console.error('鏌ヨ妯℃澘鍒楄〃澶辫触:', error); + return { + rows: [], + total: 0, + }; + } + }, + }, + }, + rowConfig: { + keyField: 'id', + }, + id: 'tool-template-index', + columnConfig: { resizable: true }, +}); + +const [BasicTable, tableApi] = useVbenVxeGrid({ + formOptions, + gridOptions: computed(() => ({ + ...gridOptions.value, + columns: dynamicColumns.value + })), +}); + +const templateModalRef = ref(); +const generateModalRef = ref(); + +function handleAdd() { + // 濡傛灉鏈� pageId锛屼紶閫掔粰鏂板 + const params: any = { update: false }; + if (pageId.value) { + params.pageId = pageId.value; + } + // 鍔ㄦ�佷紶閫抐ormJson锛屽厛JSON.parse锛屼繚璇佹槸绾璞� + if (pageDesignDetail.value && pageDesignDetail.value.formJson) { + try { + const formJson = JSON.parse(pageDesignDetail.value.formJson); + params.formJson = formJson; + console.log('浼犻�掑姩鎬佽〃鍗曞瓧娈�:', formJson); + } catch (error) { + console.error('瑙f瀽 formJson 澶辫触:', error); + params.formJson = undefined; + } + } + templateModalRef.value.open(params); +} + +function handleEdit(record) { + // 缂栬緫鏃朵篃浼犻�抐ormJson锛屽厛JSON.parse锛屼繚璇佹槸绾璞� + const params: any = { + id: record.id, + update: true, + pageId: pageId.value, // 浼犻�掗〉闈㈣璁D + record: record // 浼犻�掑畬鏁寸殑璁板綍鏁版嵁 + }; + + if (pageDesignDetail.value && pageDesignDetail.value.formJson) { + try { + const formJson = JSON.parse(pageDesignDetail.value.formJson); + params.formJson = formJson; + console.log('缂栬緫鏃朵紶閫掓暟鎹�:', { record, formJson, pageId: pageId.value }); + } catch (error) { + console.error('瑙f瀽 formJson 澶辫触:', error); + params.formJson = undefined; + } + } + templateModalRef.value.open(params); +} + +async function handleDelete(row: any) { + try { + await templateRemove([row.id]); + await tableApi.query(); + } catch (error) { + console.error('鍒犻櫎妯℃澘澶辫触:', error); + } +} + +function handleGenerate(row) { + try { + generateModalRef.value.open(row); + } catch (error) { + console.error('鎵撳紑鐢熸垚椤甸潰澶辫触:', error); + } +} + +function handlePreview(row) { + try { + // 鎵撳紑棰勮绐楀彛 + const url = `/tool/template/preview/${row.id}`; + window.open(url, '_blank'); + } catch (error) { + console.error('鎵撳紑棰勮澶辫触:', error); + } +} + +const { hasAccessByRoles } = useAccess(); +const isAdmin = computed(() => { + try { + return hasAccessByRoles(['admin', 'superadmin']); + } catch (error) { + console.error('妫�鏌ユ潈闄愬け璐�:', error); + return false; + } +}); + +const isReady = computed(() => { + try { + // 绠�鍖栧垽鏂�昏緫锛屽噺灏戜笉蹇呰鐨勮绠� + return !!(pageDesignDetail.value && !loading.value); + } catch (error) { + console.error('妫�鏌ラ〉闈㈠噯澶囩姸鎬佸け璐�:', error); + return false; + } +}); +</script> + +<style scoped> +.template-page { + background: #f5f6fa; + padding: 16px; + min-height: 100vh; + height: 100vh; + overflow: hidden; +} + +/* 纭繚琛ㄦ牸瀹瑰櫒楂樺害绋冲畾 */ +:deep(.vxe-table--main-wrapper) { + height: 600px !important; +} + +/* 纭繚鍒嗛〉鍣ㄤ綅缃浐瀹� */ +:deep(.vxe-pager) { + position: sticky; + bottom: 0; + background: white; + z-index: 10; +} +</style> \ No newline at end of file diff --git a/ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue b/ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue new file mode 100644 index 0000000..a3d88e0 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/tool/template/template-drawer.vue @@ -0,0 +1,224 @@ +<script setup lang="ts"> +import { computed, ref, watch, nextTick } from 'vue'; +import { Modal, message, FormItem } from 'ant-design-vue'; +import { $t } from '@vben/locales'; +import { templateAdd, templateUpdate, templateInfo } from '#/api/tool/template'; +import { pageList } from '#/api/tool/page-designer'; +import formCreate from '@form-create/element-ui'; + +interface ModalProps { + id?: number | string; + update: boolean; + pageId?: string | number; + formJson?: any; +} + +const emit = defineEmits<{ reload: [] }>(); + +const isUpdate = ref(false); +const title = computed(() => { + return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add'); +}); + +const modalVisible = ref(false); +const modalLoading = ref(false); +const currentEditId = ref<string | number>(''); +const dynamicFormRef = ref(); +const dynamicFormRule = ref([]); +const dynamicFormOption = ref({ + submitBtn: false, + resetBtn: false +}); +const showOkBtn = ref(true); +const currentPageId = ref(''); +const formApi = ref(); + +// 鍒ゆ柇鏄惁鏈夋彁浜ゆ寜閽� +type RuleItem = { type?: string }; +const hasSubmitBtn = (rules: any[] = []) => { + return rules.some((item: RuleItem) => item.type === 'submit'); +}; +// 鏇村交搴曠殑閫掑綊绉婚櫎鎵�鏈� submit 鎸夐挳锛屾敮鎸� children銆乥ody銆乧olumns銆乴ist銆乷ptions銆乼abs 绛夊鍣� +function removeSubmitBtn(rules = []) { + return rules + .filter(item => item.type !== 'submit') + .map(item => { + if (item.children) item.children = removeSubmitBtn(item.children); + if (item.body) item.body = removeSubmitBtn(item.body); + if (item.columns) item.columns = item.columns.map(col => ({ + ...col, + list: removeSubmitBtn(col.list || []) + })); + if (item.list) item.list = removeSubmitBtn(item.list); + if (item.options && Array.isArray(item.options)) item.options = removeSubmitBtn(item.options); + if (item.tabs) item.tabs = item.tabs.map(tab => ({ + ...tab, + list: removeSubmitBtn(tab.list || []) + })); + return item; + }); +} + +// 鎵撳紑寮圭獥 +const open = async (params: ModalProps = { update: false }) => { + try { + console.log('鎵撳紑寮圭獥锛屽弬鏁�:', params); + modalVisible.value = true; + modalLoading.value = true; + isUpdate.value = params.update; + currentEditId.value = params.id || ''; + currentPageId.value = params.pageId || ''; + + // 璁剧疆鍔ㄦ�佽〃鍗曞瓧娈碉紝濮嬬粓绉婚櫎鎵�鏈塻ubmit鎸夐挳 + if (params.formJson) { + console.log('璁剧疆鍔ㄦ�佽〃鍗曡鍒�:', params.formJson); + dynamicFormRule.value = removeSubmitBtn(params.formJson); + showOkBtn.value = true; // 濮嬬粓鏄剧ず纭畾鎸夐挳 + } else { + dynamicFormRule.value = []; + showOkBtn.value = true; + } + + // 缂栬緫妯″紡 + if (params.id && params.update) { + console.log('缂栬緫妯″紡锛岃幏鍙栬鎯呮暟鎹�'); + try { + // 鑾峰彇璇︽儏鏁版嵁 + const record = await templateInfo(params.id); + console.log('鑾峰彇鍒扮殑璁板綍鏁版嵁:', record); + + // 璁剧疆鍔ㄦ�佽〃鍗曟暟鎹� + if (record.formData) { + try { + const dynamicData = JSON.parse(record.formData); + console.log('瑙f瀽鍚庣殑琛ㄥ崟鏁版嵁:', dynamicData); + + await nextTick(); + if (formApi.value) { + console.log('鍑嗗璁剧疆琛ㄥ崟鏁版嵁鍒扮粍浠�'); + // 浣跨敤 form-create 鐨� API 璁剧疆鍊� + Object.keys(dynamicData).forEach(key => { + formApi.value.setValue(key, dynamicData[key]); + }); + console.log('琛ㄥ崟鏁版嵁璁剧疆瀹屾垚'); + } else { + console.warn('琛ㄥ崟API鏈氨缁�'); + message.error('琛ㄥ崟鏈氨缁紝璇烽噸璇�'); + } + } catch (error) { + console.error('瑙f瀽鍔ㄦ�佸瓧娈垫暟鎹け璐�:', error); + message.error('鍔犺浇琛ㄥ崟鏁版嵁澶辫触'); + } + } else { + console.log('璁板綍涓病鏈� formData 鏁版嵁'); + } + } catch (error) { + console.error('澶勭悊琛ㄥ崟鏁版嵁澶辫触:', error); + message.error('鍔犺浇琛ㄥ崟鏁版嵁澶辫触锛岃閲嶈瘯'); + } + } else { + // 鏂板鏃堕噸缃暟鎹� + console.log('鏂板妯″紡锛岄噸缃〃鍗�'); + await nextTick(); + if (formApi.value) { + formApi.value.resetFields && formApi.value.resetFields(); + } + } + } catch (error) { + console.error('鎵撳紑寮圭獥澶辫触:', error); + message.error('鍔犺浇鏁版嵁澶辫触'); + } finally { + modalLoading.value = false; + } +}; + +const close = () => { + modalVisible.value = false; +}; + +defineExpose({ open, close }); + +function onFormMounted(api) { + formApi.value = api; +} + +// handleOk 鍙礋璐hЕ鍙戣〃鍗� submit +async function handleOk() { + await nextTick(); + console.log('handleOk formApi:', formApi.value); + if (!dynamicFormRule.value || dynamicFormRule.value.length === 0) { + message.error('琛ㄥ崟瑙勫垯鏈姞杞斤紝鏃犳硶鎻愪氦'); + return; + } + if (!formApi.value) { + message.error('琛ㄥ崟鏈覆鏌撳畬鎴愶紝璇风◢鍚庨噸璇�'); + return; + } + try { + modalLoading.value = true; + const valid = await formApi.value.validate(); + if (!valid) { + modalLoading.value = false; + return; + } + const formData = formApi.value.formData(); + await onFormSubmit(formData); + } catch (error) { + console.error('淇濆瓨澶辫触:', error); + message.error('淇濆瓨澶辫触'); + modalLoading.value = false; + } +} + +// form-create 鐨� submit 浜嬩欢澶勭悊 +async function onFormSubmit(dynamicData: any) { + try { + modalLoading.value = true; + // 鏋勫缓淇濆瓨鏁版嵁 + const finalData = { + pageId: currentPageId.value, + formData: Object.keys(dynamicData).length > 0 ? JSON.stringify(dynamicData) : undefined + }; + if (isUpdate.value) { + finalData.id = currentEditId.value; + } + console.log(finalData) + await (isUpdate.value ? templateUpdate(finalData) : templateAdd(finalData)); + emit('reload'); + close(); + message.success('淇濆瓨鎴愬姛'); + } catch (error) { + console.error('淇濆瓨澶辫触:', error); + message.error('淇濆瓨澶辫触'); + } finally { + modalLoading.value = false; + } +} + +function handleCancel() { + close(); +} +</script> + +<template> + <a-modal + v-model:open="modalVisible" + :title="title" + :width="'80vw'" + :confirm-loading="modalLoading" + @ok="handleOk" + @cancel="handleCancel" + :bodyStyle="{ padding: '24px', minHeight: '60vh' }" + destroyOnClose + :ok-button-props="{ style: showOkBtn ? {} : { display: 'none' } }" + > + <!-- 鍔ㄦ�佽〃鍗曞尯鍩� --> + <form-create + ref="dynamicFormRef" + :rule="dynamicFormRule" + :option="dynamicFormOption" + @submit="onFormSubmit" + @mounted="onFormMounted" + /> + </a-modal> +</template> \ No newline at end of file diff --git a/ruoyi-ui/apps/web-antd/src/views/work/Issued/index.vue b/ruoyi-ui/apps/web-antd/src/views/work/Issued/index.vue new file mode 100644 index 0000000..d884f8b --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/work/Issued/index.vue @@ -0,0 +1,13 @@ +<template> + <div>宸ヤ綔涓嬪彂</div> +</template> + +<script> +export default { + name: "index" +} +</script> + +<style scoped> + +</style> diff --git a/ruoyi-ui/apps/web-antd/src/views/work/myWork/index.vue b/ruoyi-ui/apps/web-antd/src/views/work/myWork/index.vue new file mode 100644 index 0000000..7dabebf --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/work/myWork/index.vue @@ -0,0 +1,13 @@ +<template> + <div>鎴戠殑宸ヤ綔</div> +</template> + +<script> +export default { + name: "index" +} +</script> + +<style scoped> + +</style> diff --git a/ruoyi-ui/apps/web-antd/src/views/work/statistics/index.vue b/ruoyi-ui/apps/web-antd/src/views/work/statistics/index.vue new file mode 100644 index 0000000..f5bd867 --- /dev/null +++ b/ruoyi-ui/apps/web-antd/src/views/work/statistics/index.vue @@ -0,0 +1,13 @@ +<template> +<div>宸ヤ綔缁熻</div> +</template> + +<script> +export default { + name: "index" +} +</script> + +<style scoped> + +</style> -- Gitblit v1.9.3