Commit 805c4053c1e14cb2753d59ab6f8911b98f264073
1 parent
789277c4
JeecgBoot 3.1.0 版本发布,基于代码生成器的企业级低代码平台
Showing
237 changed files
with
11319 additions
and
849 deletions
jeecg-boot/README.md
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java deleted
1 | -package org.jeecg.common.bpm.api; | |
2 | - | |
3 | -import org.jeecg.common.api.vo.Result; | |
4 | -import org.jeecg.common.constant.ServiceNameConstants; | |
5 | -import org.jeecg.common.online.api.factory.OnlineBaseExtAPIFallbackFactory; | |
6 | -import org.springframework.cloud.openfeign.FeignClient; | |
7 | -import org.springframework.stereotype.Component; | |
8 | -import org.springframework.web.bind.annotation.PostMapping; | |
9 | -import org.springframework.web.bind.annotation.RequestParam; | |
10 | - | |
11 | -/** | |
12 | - * 流程接口 | |
13 | - * | |
14 | - * @author scott | |
15 | - */ | |
16 | -@Component | |
17 | -@FeignClient(contextId = "bpmBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE, | |
18 | - fallbackFactory = OnlineBaseExtAPIFallbackFactory.class) | |
19 | -public interface IBpmBaseExtAPI { | |
20 | - /** | |
21 | - * 23. 流程提交接口(online,自定义开发) | |
22 | - * | |
23 | - * @param flowCode | |
24 | - * 流程业务关联 例如:joa_leave_01 | |
25 | - * @param id | |
26 | - * 表单业务数据data id | |
27 | - * @param formUrl | |
28 | - * 流程审批时附件页面默认展示的PC端表单组件(地址) | |
29 | - * @param formUrlMobile | |
30 | - * 流程审批时附件页面默认展示的移动端表单组件(地址) | |
31 | - * @param username | |
32 | - * 流程发起人账号 | |
33 | - * @param jsonData | |
34 | - * Json串,额外扩展的流程变量值 【非必填】 | |
35 | - * @return | |
36 | - * @throws Exception | |
37 | - */ | |
38 | - @PostMapping(value = "/act/process/extActProcess/startMutilProcess") | |
39 | - Result<String> startMutilProcess(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id, | |
40 | - @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile, | |
41 | - @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception; | |
42 | - | |
43 | - /** | |
44 | - * 24. 流程提交接口(自定义表单设计器) | |
45 | - * | |
46 | - * @param flowCode | |
47 | - * 流程业务关联 例如:joa_leave_01 | |
48 | - * @param id | |
49 | - * 表单业务数据data id | |
50 | - * @param formUrl | |
51 | - * 流程审批时附件页面默认展示的PC端表单组件(地址) | |
52 | - * @param formUrlMobile | |
53 | - * 流程审批时附件页面默认展示的移动端表单组件(地址) | |
54 | - * @param username | |
55 | - * 流程发起人账号 | |
56 | - * @param jsonData | |
57 | - * Json串,额外扩展的流程变量值 【非必填】 | |
58 | - * @return | |
59 | - * @throws Exception | |
60 | - */ | |
61 | - @PostMapping(value = "/act/process/extActProcess/startDesFormMutilProcess") | |
62 | - Result<String> startDesFormMutilProcess(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id, | |
63 | - @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile, | |
64 | - @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception; | |
65 | - | |
66 | - /** | |
67 | - * 25. 保存流程草稿箱接口(自定义开发表单、online表单) | |
68 | - * | |
69 | - * @param flowCode | |
70 | - * 流程业务关联 例如:joa_leave_01 | |
71 | - * @param id | |
72 | - * 表单业务数据data id | |
73 | - * @param formUrl | |
74 | - * 流程审批时附件页面默认展示的PC端表单组件(地址) 【非必填】 | |
75 | - * @param formUrlMobile | |
76 | - * 流程审批时附件页面默认展示的移动端表单组件(地址) 【非必填】 | |
77 | - * @param username | |
78 | - * 流程发起人账号 | |
79 | - * @param jsonData | |
80 | - * Json串,额外扩展的流程变量值 【非必填】 | |
81 | - * @return | |
82 | - * @throws Exception | |
83 | - */ | |
84 | - @PostMapping(value = "/act/process/extActProcess/saveMutilProcessDraft") | |
85 | - Result<String> saveMutilProcessDraft(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id, | |
86 | - @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile, | |
87 | - @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception; | |
88 | - | |
89 | -} |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java deleted
1 | -package org.jeecg.common.bpm.api.factory; | |
2 | - | |
3 | -import org.jeecg.common.bpm.api.IBpmBaseExtAPI; | |
4 | -import org.jeecg.common.bpm.api.fallback.BpmBaseExtAPIFallback; | |
5 | -import org.springframework.stereotype.Component; | |
6 | - | |
7 | -import feign.hystrix.FallbackFactory; | |
8 | - | |
9 | -@Component | |
10 | -public class BpmBaseExtAPIFallbackFactory implements FallbackFactory<IBpmBaseExtAPI> { | |
11 | - | |
12 | - @Override | |
13 | - public IBpmBaseExtAPI create(Throwable throwable) { | |
14 | - BpmBaseExtAPIFallback fallback = new BpmBaseExtAPIFallback(); | |
15 | - fallback.setCause(throwable); | |
16 | - return fallback; | |
17 | - } | |
18 | -} | |
19 | 0 | \ No newline at end of file |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java deleted
1 | -package org.jeecg.common.bpm.api.fallback; | |
2 | - | |
3 | -import java.util.List; | |
4 | -import java.util.Map; | |
5 | - | |
6 | -import org.jeecg.common.api.vo.Result; | |
7 | -import org.jeecg.common.bpm.api.IBpmBaseExtAPI; | |
8 | -import org.jeecg.common.online.api.IOnlineBaseExtAPI; | |
9 | -import org.jeecg.common.system.vo.DictModel; | |
10 | - | |
11 | -import com.alibaba.fastjson.JSONObject; | |
12 | - | |
13 | -import lombok.Setter; | |
14 | -import lombok.extern.slf4j.Slf4j; | |
15 | - | |
16 | -/** | |
17 | - * 进入fallback的方法 检查是否token未设置 | |
18 | - */ | |
19 | -@Slf4j | |
20 | -public class BpmBaseExtAPIFallback implements IBpmBaseExtAPI { | |
21 | - | |
22 | - @Setter | |
23 | - private Throwable cause; | |
24 | - | |
25 | - @Override | |
26 | - public Result<String> startMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile, | |
27 | - String username, String jsonData) throws Exception { | |
28 | - return null; | |
29 | - } | |
30 | - | |
31 | - @Override | |
32 | - public Result<String> startDesFormMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile, | |
33 | - String username, String jsonData) throws Exception { | |
34 | - return null; | |
35 | - } | |
36 | - | |
37 | - @Override | |
38 | - public Result<String> saveMutilProcessDraft(String flowCode, String id, String formUrl, String formUrlMobile, | |
39 | - String username, String jsonData) throws Exception { | |
40 | - return null; | |
41 | - } | |
42 | -} |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java
... | ... | @@ -15,7 +15,8 @@ import java.util.Map; |
15 | 15 | * 【Online】Feign API接口 |
16 | 16 | */ |
17 | 17 | @Component |
18 | -@FeignClient(contextId = "onlineBaseRemoteApi", value = ServiceNameConstants.SYSTEM_ONLINE, fallbackFactory = OnlineBaseExtAPIFallbackFactory.class) | |
18 | +@FeignClient(contextId = "onlineBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = OnlineBaseExtAPIFallbackFactory.class) | |
19 | +//@FeignClient(contextId = "onlineBaseRemoteApi", value = ServiceNameConstants.SYSTEM_ONLINE, fallbackFactory = OnlineBaseExtAPIFallbackFactory.class) | |
19 | 20 | public interface IOnlineBaseExtAPI { |
20 | 21 | |
21 | 22 | /** |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java deleted
1 | -package org.jeecg.common.bpm.api; | |
2 | - | |
3 | -import java.util.List; | |
4 | -import java.util.Map; | |
5 | - | |
6 | -import org.jeecg.common.api.vo.Result; | |
7 | -import org.jeecg.common.system.vo.DictModel; | |
8 | - | |
9 | -import com.alibaba.fastjson.JSONObject; | |
10 | - | |
11 | -/** | |
12 | - * 流程接口 | |
13 | - * | |
14 | - * @author scott | |
15 | - */ | |
16 | -public interface IBpmBaseExtAPI { | |
17 | - /** | |
18 | - * 23. 流程提交接口(online,自定义开发) | |
19 | - * @param flowCode 流程业务关联 例如:joa_leave_01 | |
20 | - * @param id 表单业务数据data id | |
21 | - * @param formUrl 流程审批时附件页面默认展示的PC端表单组件(地址) | |
22 | - * @param formUrlMobile 流程审批时附件页面默认展示的移动端表单组件(地址) | |
23 | - * @param username 流程发起人账号 | |
24 | - * @param jsonData Json串,额外扩展的流程变量值 【非必填】 | |
25 | - * @return | |
26 | - * @throws Exception | |
27 | - */ | |
28 | - Result<String> startMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,String username, String jsonData) throws Exception; | |
29 | - | |
30 | - /** | |
31 | - * 24. 流程提交接口(自定义表单设计器) | |
32 | - * @param flowCode 流程业务关联 例如:joa_leave_01 | |
33 | - * @param id 表单业务数据data id | |
34 | - * @param formUrl 流程审批时附件页面默认展示的PC端表单组件(地址) | |
35 | - * @param formUrlMobile 流程审批时附件页面默认展示的移动端表单组件(地址) | |
36 | - * @param username 流程发起人账号 | |
37 | - * @param jsonData Json串,额外扩展的流程变量值 【非必填】 | |
38 | - * @return | |
39 | - * @throws Exception | |
40 | - */ | |
41 | - Result<String> startDesFormMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,String username,String jsonData) throws Exception; | |
42 | - /** | |
43 | - * 25. 保存流程草稿箱接口(自定义开发表单、online表单) | |
44 | - * @param flowCode 流程业务关联 例如:joa_leave_01 | |
45 | - * @param id 表单业务数据data id | |
46 | - * @param formUrl 流程审批时附件页面默认展示的PC端表单组件(地址) 【非必填】 | |
47 | - * @param formUrlMobile 流程审批时附件页面默认展示的移动端表单组件(地址) 【非必填】 | |
48 | - * @param username 流程发起人账号 | |
49 | - * @param jsonData Json串,额外扩展的流程变量值 【非必填】 | |
50 | - * @return | |
51 | - * @throws Exception | |
52 | - */ | |
53 | - Result<String> saveMutilProcessDraft(String flowCode, String id, String formUrl, String formUrlMobile,String username,String jsonData) throws Exception; | |
54 | - | |
55 | -} |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java
... | ... | @@ -103,6 +103,7 @@ public class Result<T> implements Serializable { |
103 | 103 | return r; |
104 | 104 | } |
105 | 105 | |
106 | + @Deprecated | |
106 | 107 | public static<T> Result<T> OK(String msg) { |
107 | 108 | Result<T> r = new Result<T>(); |
108 | 109 | r.setSuccess(true); |
... | ... | @@ -157,6 +158,7 @@ public class Result<T> implements Serializable { |
157 | 158 | this.success = false; |
158 | 159 | return this; |
159 | 160 | } |
161 | + | |
160 | 162 | /** |
161 | 163 | * 无权限访问返回结果 |
162 | 164 | */ |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java
... | ... | @@ -2,6 +2,7 @@ package org.jeecg.common.aspect; |
2 | 2 | |
3 | 3 | import com.alibaba.fastjson.JSON; |
4 | 4 | import com.alibaba.fastjson.JSONObject; |
5 | +import com.alibaba.fastjson.parser.Feature; | |
5 | 6 | import com.baomidou.mybatisplus.core.metadata.IPage; |
6 | 7 | import com.fasterxml.jackson.annotation.JsonFormat; |
7 | 8 | import com.fasterxml.jackson.core.JsonProcessingException; |
... | ... | @@ -18,6 +19,7 @@ import org.jeecg.common.constant.CommonConstant; |
18 | 19 | import org.jeecg.common.system.vo.DictModel; |
19 | 20 | import org.jeecg.common.util.oConvertUtils; |
20 | 21 | import org.springframework.beans.factory.annotation.Autowired; |
22 | +import org.springframework.context.annotation.Lazy; | |
21 | 23 | import org.springframework.data.redis.core.RedisTemplate; |
22 | 24 | import org.springframework.stereotype.Component; |
23 | 25 | import org.springframework.util.StringUtils; |
... | ... | @@ -38,14 +40,14 @@ import java.util.stream.Collectors; |
38 | 40 | @Component |
39 | 41 | @Slf4j |
40 | 42 | public class DictAspect { |
41 | - | |
43 | + @Lazy | |
42 | 44 | @Autowired |
43 | 45 | private CommonAPI commonAPI; |
44 | 46 | @Autowired |
45 | 47 | public RedisTemplate redisTemplate; |
46 | 48 | |
47 | 49 | // 定义切点Pointcut |
48 | - @Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..))") | |
50 | + @Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..)) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)") | |
49 | 51 | public void excudeService() { |
50 | 52 | } |
51 | 53 | |
... | ... | @@ -103,7 +105,10 @@ public class DictAspect { |
103 | 105 | } catch (JsonProcessingException e) { |
104 | 106 | log.error("json解析失败"+e.getMessage(),e); |
105 | 107 | } |
106 | - JSONObject item = JSONObject.parseObject(json); | |
108 | + //update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 ----- | |
109 | + JSONObject item = JSONObject.parseObject(json, Feature.OrderedField); | |
110 | + //update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 ----- | |
111 | + | |
107 | 112 | //update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------ |
108 | 113 | //for (Field field : record.getClass().getDeclaredFields()) { |
109 | 114 | // 遍历所有字段,把字典Code取出来,放到 map 里 |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
... | ... | @@ -8,6 +8,7 @@ import org.aspectj.lang.annotation.Pointcut; |
8 | 8 | import org.aspectj.lang.reflect.MethodSignature; |
9 | 9 | import org.jeecg.common.api.CommonAPI; |
10 | 10 | import org.jeecg.common.aspect.annotation.PermissionData; |
11 | +import org.jeecg.common.constant.CommonConstant; | |
11 | 12 | import org.jeecg.common.system.util.JeecgDataAutorUtils; |
12 | 13 | import org.jeecg.common.system.util.JwtUtil; |
13 | 14 | import org.jeecg.common.system.vo.SysPermissionDataRuleModel; |
... | ... | @@ -15,6 +16,7 @@ import org.jeecg.common.system.vo.SysUserCacheInfo; |
15 | 16 | import org.jeecg.common.util.SpringContextUtils; |
16 | 17 | import org.jeecg.common.util.oConvertUtils; |
17 | 18 | import org.springframework.beans.factory.annotation.Autowired; |
19 | +import org.springframework.context.annotation.Lazy; | |
18 | 20 | import org.springframework.stereotype.Component; |
19 | 21 | |
20 | 22 | import javax.servlet.http.HttpServletRequest; |
... | ... | @@ -31,7 +33,7 @@ import java.util.List; |
31 | 33 | @Component |
32 | 34 | @Slf4j |
33 | 35 | public class PermissionDataAspect { |
34 | - | |
36 | + @Lazy | |
35 | 37 | @Autowired |
36 | 38 | private CommonAPI commonAPI; |
37 | 39 | |
... | ... | @@ -47,11 +49,21 @@ public class PermissionDataAspect { |
47 | 49 | Method method = signature.getMethod(); |
48 | 50 | PermissionData pd = method.getAnnotation(PermissionData.class); |
49 | 51 | String component = pd.pageComponent(); |
50 | - | |
51 | 52 | String requestMethod = request.getMethod(); |
52 | 53 | String requestPath = request.getRequestURI().substring(request.getContextPath().length()); |
53 | 54 | requestPath = filterUrl(requestPath); |
54 | - log.debug("拦截请求 >> "+requestPath+";请求类型 >> "+requestMethod); | |
55 | + //update-begin-author:taoyan date:20211027 for:JTC-132【online报表权限】online报表带参数的菜单配置数据权限无效 | |
56 | + //先判断是否online报表请求 | |
57 | + // TODO 参数顺序调整有隐患 | |
58 | + if(requestPath.indexOf(UrlMatchEnum.CGREPORT_DATA.getMatch_url())>=0){ | |
59 | + // 获取地址栏参数 | |
60 | + String urlParamString = request.getParameter(CommonConstant.ONL_REP_URL_PARAM_STR); | |
61 | + if(oConvertUtils.isNotEmpty(urlParamString)){ | |
62 | + requestPath+="?"+urlParamString; | |
63 | + } | |
64 | + } | |
65 | + //update-end-author:taoyan date:20211027 for:JTC-132【online报表权限】online报表带参数的菜单配置数据权限无效 | |
66 | + log.info("拦截请求 >> {} ; 请求类型 >> {} . ", requestPath, requestMethod); | |
55 | 67 | String username = JwtUtil.getUserNameByToken(request); |
56 | 68 | //查询数据权限信息 |
57 | 69 | //TODO 微服务情况下也得支持缓存机制 |
... | ... | @@ -86,6 +98,7 @@ public class PermissionDataAspect { |
86 | 98 | * @param request |
87 | 99 | * @return |
88 | 100 | */ |
101 | + @Deprecated | |
89 | 102 | private String getJgAuthRequsetPath(HttpServletRequest request) { |
90 | 103 | String queryString = request.getQueryString(); |
91 | 104 | String requestPath = request.getRequestURI(); |
... | ... | @@ -106,6 +119,7 @@ public class PermissionDataAspect { |
106 | 119 | return filterUrl(requestPath); |
107 | 120 | } |
108 | 121 | |
122 | + @Deprecated | |
109 | 123 | private boolean moHuContain(List<String> list,String key){ |
110 | 124 | for(String str : list){ |
111 | 125 | if(key.contains(str)){ |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/UrlMatchEnum.java
... | ... | @@ -10,8 +10,8 @@ public enum UrlMatchEnum { |
10 | 10 | CGFORM_EXCEL_DATA("/online/cgform/api/exportXls/", "/online/cgformList/"), |
11 | 11 | CGFORM_TREE_DATA("/online/cgform/api/getTreeData/", "/online/cgformList/"), |
12 | 12 | CGREPORT_DATA("/online/cgreport/api/getColumnsAndData/", "/online/cgreport/"), |
13 | - CGREPORT_EXCEL_DATA("/online/cgreport/api/exportXls/", "/online/cgreport/"); | |
14 | - | |
13 | + CGREPORT_EXCEL_DATA("/online/cgreport/api/exportXls/", "/online/cgreport/"), | |
14 | + CGREPORT_EXCEL_DATA2("/online/cgreport/api/exportManySheetXls/", "/online/cgreport/"); | |
15 | 15 | |
16 | 16 | UrlMatchEnum(String url, String match_url) { |
17 | 17 | this.url = url; |
... | ... | @@ -47,8 +47,10 @@ public enum UrlMatchEnum { |
47 | 47 | return null; |
48 | 48 | } |
49 | 49 | |
50 | - | |
51 | -// public static void main(String[] args) { | |
50 | + public String getMatch_url() { | |
51 | + return match_url; | |
52 | + } | |
53 | + // public static void main(String[] args) { | |
52 | 54 | // /** |
53 | 55 | // * 比如request真实请求URL: /online/cgform/api/getData/81fcf7d8922d45069b0d5ba983612d3a |
54 | 56 | // * 转换匹配路由URL后(对应配置的菜单路径):/online/cgformList/81fcf7d8922d45069b0d5ba983612d3a |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoDict.java
0 → 100644
1 | +package org.jeecg.common.aspect.annotation; | |
2 | + | |
3 | +import java.lang.annotation.*; | |
4 | + | |
5 | +/** | |
6 | + * 通过此注解声明的接口,自动实现字典翻译 | |
7 | + * | |
8 | + * @Author scott | |
9 | + * @email jeecgos@163.com | |
10 | + * @Date 2022年01月05日 | |
11 | + */ | |
12 | +@Target(ElementType.METHOD) | |
13 | +@Retention(RetentionPolicy.RUNTIME) | |
14 | +@Documented | |
15 | +public @interface AutoDict { | |
16 | + | |
17 | + /** | |
18 | + * 暂时无用 | |
19 | + * @return | |
20 | + */ | |
21 | + String value() default ""; | |
22 | + | |
23 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoLowApp.java
0 → 100644
1 | +package org.jeecg.common.aspect.annotation; | |
2 | + | |
3 | +import java.lang.annotation.*; | |
4 | + | |
5 | +import org.jeecg.common.constant.enums.LowAppAopEnum; | |
6 | + | |
7 | +/** | |
8 | + * 自动注入low_app_id | |
9 | + * | |
10 | + * @Author scott | |
11 | + * @email jeecgos@163.com | |
12 | + * @Date 2022年01月05日 | |
13 | + */ | |
14 | +@Target(ElementType.METHOD) | |
15 | +@Retention(RetentionPolicy.RUNTIME) | |
16 | +@Documented | |
17 | +public @interface AutoLowApp { | |
18 | + | |
19 | + /** | |
20 | + * 切面类型(add、delete、db_import等其他操作) | |
21 | + * | |
22 | + * @return | |
23 | + */ | |
24 | + LowAppAopEnum action(); | |
25 | + | |
26 | + /** | |
27 | + * 业务类型(cgform等) | |
28 | + * | |
29 | + * @return | |
30 | + */ | |
31 | + String bizType(); | |
32 | + | |
33 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
... | ... | @@ -77,7 +77,13 @@ public interface CommonConstant { |
77 | 77 | public static final String PREFIX_USER_TOKEN = "prefix_user_token_"; |
78 | 78 | /** Token缓存时间:3600秒即一小时 */ |
79 | 79 | public static final int TOKEN_EXPIRE_TIME = 3600; |
80 | - | |
80 | + | |
81 | + /** 登录二维码 */ | |
82 | + public static final String LOGIN_QRCODE_PRE = "QRCODELOGIN:"; | |
83 | + public static final String LOGIN_QRCODE = "LQ:"; | |
84 | + /** 登录二维码token */ | |
85 | + public static final String LOGIN_QRCODE_TOKEN = "LQT:"; | |
86 | + | |
81 | 87 | |
82 | 88 | /** |
83 | 89 | * 0:一级菜单 |
... | ... | @@ -91,7 +97,7 @@ public interface CommonConstant { |
91 | 97 | * 2:按钮权限 |
92 | 98 | */ |
93 | 99 | public static final Integer MENU_TYPE_2 = 2; |
94 | - | |
100 | + | |
95 | 101 | /**通告对象类型(USER:指定用户,ALL:全体用户)*/ |
96 | 102 | public static final String MSG_TYPE_UESR = "USER"; |
97 | 103 | public static final String MSG_TYPE_ALL = "ALL"; |
... | ... | @@ -229,6 +235,9 @@ public interface CommonConstant { |
229 | 235 | public static final String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no"; |
230 | 236 | /** sys_user 表 phone 唯一键索引 */ |
231 | 237 | public static final String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone"; |
238 | + /** 达梦数据库升提示。违反表[SYS_USER]唯一性约束 */ | |
239 | + public static final String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束"; | |
240 | + | |
232 | 241 | /** sys_user 表 email 唯一键索引 */ |
233 | 242 | public static final String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email"; |
234 | 243 | /** sys_quartz_job 表 job_class_name 唯一键索引 */ |
... | ... | @@ -239,6 +248,8 @@ public interface CommonConstant { |
239 | 248 | public static final String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code"; |
240 | 249 | /** sys_depart 表 code 唯一键索引 */ |
241 | 250 | public static final String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code"; |
251 | + /** sys_category 表 code 唯一键索引 */ | |
252 | + public static final String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code"; | |
242 | 253 | /** |
243 | 254 | * 在线聊天 是否为默认分组 |
244 | 255 | */ |
... | ... | @@ -325,4 +336,7 @@ public interface CommonConstant { |
325 | 336 | /** 系统通告消息状态:2=已撤销 */ |
326 | 337 | String ANNOUNCEMENT_SEND_STATUS_2 = "2"; |
327 | 338 | |
339 | + /**ONLINE 报表权限用 从request中获取地址栏后的参数*/ | |
340 | + String ONL_REP_URL_PARAM_STR="onlRepUrlParamStr"; | |
341 | + | |
328 | 342 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
... | ... | @@ -29,7 +29,7 @@ public class ProvinceCityArea { |
29 | 29 | |
30 | 30 | public String getCode(String text){ |
31 | 31 | this.initAreaList(); |
32 | - if(areaList!=null || areaList.size()>0){ | |
32 | + if(areaList!=null && areaList.size()>0){ | |
33 | 33 | for(int i=areaList.size()-1;i>=0;i--){ |
34 | 34 | if(text.indexOf(areaList.get(i).getText())>=0){ |
35 | 35 | return areaList.get(i).getId(); |
... | ... | @@ -39,6 +39,73 @@ public class ProvinceCityArea { |
39 | 39 | return null; |
40 | 40 | } |
41 | 41 | |
42 | + // update-begin-author:sunjianlei date:20220121 for:【JTC-704】数据导入错误 省市区组件,文件中为北京市,导入后,导为了山西省 | |
43 | + /** | |
44 | + * 获取省市区code,精准匹配 | |
45 | + * @param texts 文本数组,省,市,区 | |
46 | + * @return 返回 省市区的code | |
47 | + */ | |
48 | + public String[] getCode(String[] texts) { | |
49 | + if (texts == null || texts.length == 0) { | |
50 | + return null; | |
51 | + } | |
52 | + this.initAreaList(); | |
53 | + if (areaList == null || areaList.size() == 0) { | |
54 | + return null; | |
55 | + } | |
56 | + String[] codes = new String[texts.length]; | |
57 | + String code = null; | |
58 | + for (int i = 0; i < texts.length; i++) { | |
59 | + String text = texts[i]; | |
60 | + Area area; | |
61 | + if (code == null) { | |
62 | + area = getAreaByText(text); | |
63 | + } else { | |
64 | + area = getAreaByPidAndText(code, text); | |
65 | + } | |
66 | + if (area != null) { | |
67 | + code = area.id; | |
68 | + codes[i] = code; | |
69 | + } else { | |
70 | + return null; | |
71 | + } | |
72 | + } | |
73 | + return codes; | |
74 | + } | |
75 | + | |
76 | + /** | |
77 | + * 根据text获取area | |
78 | + * @param text | |
79 | + * @return | |
80 | + */ | |
81 | + public Area getAreaByText(String text) { | |
82 | + for (Area area : areaList) { | |
83 | + if (text.equals(area.getText())) { | |
84 | + return area; | |
85 | + } | |
86 | + } | |
87 | + return null; | |
88 | + } | |
89 | + | |
90 | + /** | |
91 | + * 通过pid获取 area 对象 | |
92 | + * @param pCode 父级编码 | |
93 | + * @param text | |
94 | + * @return | |
95 | + */ | |
96 | + public Area getAreaByPidAndText(String pCode, String text) { | |
97 | + this.initAreaList(); | |
98 | + if (this.areaList != null && this.areaList.size() > 0) { | |
99 | + for (Area area : this.areaList) { | |
100 | + if (area.getPid().equals(pCode) && area.getText().equals(text)) { | |
101 | + return area; | |
102 | + } | |
103 | + } | |
104 | + } | |
105 | + return null; | |
106 | + } | |
107 | + // update-end-author:sunjianlei date:20220121 for:【JTC-704】数据导入错误 省市区组件,文件中为北京市,导入后,导为了山西省 | |
108 | + | |
42 | 109 | public void getAreaByCode(String code,List<String> ls){ |
43 | 110 | for(Area area: areaList){ |
44 | 111 | if(area.getId().equals(code)){ |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
0 → 100644
1 | +package org.jeecg.common.constant.enums; | |
2 | + | |
3 | +/** | |
4 | + * LowApp 切面注解枚举 | |
5 | + * @date 2022-1-5 | |
6 | + */ | |
7 | +public enum LowAppAopEnum { | |
8 | + | |
9 | + /** | |
10 | + * 新增方法 | |
11 | + */ | |
12 | + ADD, | |
13 | + /** | |
14 | + * 删除方法(包含单个和批量删除) | |
15 | + */ | |
16 | + DELETE, | |
17 | + | |
18 | + /** | |
19 | + * Online表单专用:数据库表转Online表单 | |
20 | + */ | |
21 | + CGFORM_DB_IMPORT | |
22 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java
1 | 1 | package org.jeecg.common.constant.enums; |
2 | 2 | |
3 | +import org.jeecg.common.util.oConvertUtils; | |
4 | + | |
3 | 5 | import java.util.List; |
4 | 6 | |
5 | 7 | /** |
6 | 8 | * 首页自定义 |
7 | 9 | * 通过角色编码与首页组件路径配置 |
10 | + * 枚举的顺序有权限高低权重作用(也就是配置多个角色,在前面的角色首页,会优先生效) | |
8 | 11 | */ |
9 | 12 | public enum RoleIndexConfigEnum { |
10 | - /** | |
11 | - * 管理员 | |
12 | - */ | |
13 | - ADMIN("admin1", "dashboard/Analysis2"), | |
14 | - /** | |
15 | - * 测试 | |
16 | - */ | |
17 | - TEST("test", "dashboard/Analysis"), | |
18 | - /** | |
19 | - * hr | |
20 | - */ | |
21 | - HR("hr", "dashboard/Analysis1"); | |
13 | + | |
14 | + ADMIN("admin", "dashboard/Analysis"), | |
15 | + //TEST("test", "dashboard/IndexChart"), | |
16 | + HR("hr", "dashboard/IndexBdc"); | |
17 | + //DM("dm", "dashboard/IndexTask"), | |
22 | 18 | |
23 | 19 | /** |
24 | 20 | * 角色编码 |
... | ... | @@ -44,7 +40,7 @@ public enum RoleIndexConfigEnum { |
44 | 40 | * @param roleCode 角色编码 |
45 | 41 | * @return |
46 | 42 | */ |
47 | - public static RoleIndexConfigEnum getEnumByCode(String roleCode) { | |
43 | + private static RoleIndexConfigEnum getEnumByCode(String roleCode) { | |
48 | 44 | for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) { |
49 | 45 | if (e.roleCode.equals(roleCode)) { |
50 | 46 | return e; |
... | ... | @@ -57,7 +53,7 @@ public enum RoleIndexConfigEnum { |
57 | 53 | * @param roleCode 角色编码 |
58 | 54 | * @return |
59 | 55 | */ |
60 | - public static String getIndexByCode(String roleCode) { | |
56 | + private static String getIndexByCode(String roleCode) { | |
61 | 57 | for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) { |
62 | 58 | if (e.roleCode.equals(roleCode)) { |
63 | 59 | return e.componentUrl; |
... | ... | @@ -67,11 +63,10 @@ public enum RoleIndexConfigEnum { |
67 | 63 | } |
68 | 64 | |
69 | 65 | public static String getIndexByRoles(List<String> roles) { |
70 | - for (String role : roles) { | |
71 | - for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) { | |
72 | - if (e.roleCode.equals(role)) { | |
73 | - return e.componentUrl; | |
74 | - } | |
66 | + String[] rolesArray = roles.toArray(new String[roles.size()]); | |
67 | + for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) { | |
68 | + if (oConvertUtils.isIn(e.roleCode,rolesArray)){ | |
69 | + return e.componentUrl; | |
75 | 70 | } |
76 | 71 | } |
77 | 72 | return null; |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
... | ... | @@ -180,8 +180,15 @@ public class JeecgController<T, S extends IService<T>> { |
180 | 180 | //update-end-author:taoyan date:20190528 for:批量插入数据 |
181 | 181 | return Result.ok("文件导入成功!数据行数:" + list.size()); |
182 | 182 | } catch (Exception e) { |
183 | - log.error(e.getMessage(), e); | |
184 | - return Result.error("文件导入失败:" + e.getMessage()); | |
183 | + //update-begin-author:taoyan date:20211124 for: 导入数据重复增加提示 | |
184 | + String msg = e.getMessage(); | |
185 | + log.error(msg, e); | |
186 | + if(msg!=null && msg.indexOf("Duplicate entry")>=0){ | |
187 | + return Result.error("文件导入失败:有重复数据!"); | |
188 | + }else{ | |
189 | + return Result.error("文件导入失败:" + e.getMessage()); | |
190 | + } | |
191 | + //update-end-author:taoyan date:20211124 for: 导入数据重复增加提示 | |
185 | 192 | } finally { |
186 | 193 | try { |
187 | 194 | file.getInputStream().close(); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
... | ... | @@ -25,7 +25,6 @@ import org.jeecg.common.util.oConvertUtils; |
25 | 25 | import org.springframework.util.NumberUtils; |
26 | 26 | |
27 | 27 | import com.alibaba.fastjson.JSON; |
28 | -import com.baomidou.mybatisplus.annotation.DbType; | |
29 | 28 | import com.baomidou.mybatisplus.annotation.TableField; |
30 | 29 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
31 | 30 | |
... | ... | @@ -145,20 +144,23 @@ public class QueryGenerator { |
145 | 144 | //区间查询 |
146 | 145 | doIntervalQuery(queryWrapper, parameterMap, type, name, column); |
147 | 146 | //判断单值 参数带不同标识字符串 走不同的查询 |
148 | - //TODO 这种前后带逗号的支持分割后模糊查询需要否 使多选字段的查询生效 | |
147 | + //TODO 这种前后带逗号的支持分割后模糊查询(多选字段查询生效) 示例:,1,3, | |
149 | 148 | if (null != value && value.toString().startsWith(COMMA) && value.toString().endsWith(COMMA)) { |
150 | 149 | String multiLikeval = value.toString().replace(",,", COMMA); |
151 | 150 | String[] vals = multiLikeval.substring(1, multiLikeval.length()).split(COMMA); |
152 | 151 | final String field = oConvertUtils.camelToUnderline(column); |
153 | 152 | if(vals.length>1) { |
154 | 153 | queryWrapper.and(j -> { |
154 | + log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}", field, "like", vals[0]); | |
155 | 155 | j = j.like(field,vals[0]); |
156 | 156 | for (int k=1;k<vals.length;k++) { |
157 | 157 | j = j.or().like(field,vals[k]); |
158 | + log.info("---查询过滤器,Query规则 .or()---field:{}, rule:{}, value:{}", field, "like", vals[k]); | |
158 | 159 | } |
159 | 160 | //return j; |
160 | 161 | }); |
161 | 162 | }else { |
163 | + log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}", field, "like", vals[0]); | |
162 | 164 | queryWrapper.and(j -> j.like(field,vals[0])); |
163 | 165 | } |
164 | 166 | }else { |
... | ... | @@ -224,7 +226,7 @@ public class QueryGenerator { |
224 | 226 | if(parameterMap!=null&& parameterMap.containsKey(ORDER_TYPE)) { |
225 | 227 | order = parameterMap.get(ORDER_TYPE)[0]; |
226 | 228 | } |
227 | - log.info("排序规则>>列:" + column + ",排序方式:" + order); | |
229 | + log.debug("排序规则>>列:" + column + ",排序方式:" + order); | |
228 | 230 | if (oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) { |
229 | 231 | //字典字段,去掉字典翻译文本后缀 |
230 | 232 | if(column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) { |
... | ... | @@ -270,10 +272,21 @@ public class QueryGenerator { |
270 | 272 | if (conditions == null || conditions.size() == 0) { |
271 | 273 | return; |
272 | 274 | } |
273 | - log.info("---高级查询参数-->" + conditions.toString()); | |
275 | + // update-begin-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and | |
276 | + List<QueryCondition> filterConditions = conditions.stream().filter( | |
277 | + rule -> oConvertUtils.isNotEmpty(rule.getField()) | |
278 | + && oConvertUtils.isNotEmpty(rule.getRule()) | |
279 | + && oConvertUtils.isNotEmpty(rule.getVal()) | |
280 | + ).collect(Collectors.toList()); | |
281 | + if (filterConditions.size() == 0) { | |
282 | + return; | |
283 | + } | |
284 | + // update-end-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and | |
285 | + log.info("---高级查询参数-->" + filterConditions); | |
286 | + | |
274 | 287 | queryWrapper.and(andWrapper -> { |
275 | - for (int i = 0; i < conditions.size(); i++) { | |
276 | - QueryCondition rule = conditions.get(i); | |
288 | + for (int i = 0; i < filterConditions.size(); i++) { | |
289 | + QueryCondition rule = filterConditions.get(i); | |
277 | 290 | if (oConvertUtils.isNotEmpty(rule.getField()) |
278 | 291 | && oConvertUtils.isNotEmpty(rule.getRule()) |
279 | 292 | && oConvertUtils.isNotEmpty(rule.getVal())) { |
... | ... | @@ -324,7 +337,7 @@ public class QueryGenerator { |
324 | 337 | //update-end-author:taoyan date:20201228 for: 【高级查询】 oracle 日期等于查询报错 |
325 | 338 | |
326 | 339 | // 如果拼接方式是OR,就拼接OR |
327 | - if (MatchTypeEnum.OR == matchType && i < (conditions.size() - 1)) { | |
340 | + if (MatchTypeEnum.OR == matchType && i < (filterConditions.size() - 1)) { | |
328 | 341 | andWrapper.or(); |
329 | 342 | } |
330 | 343 | } |
... | ... | @@ -457,15 +470,37 @@ public class QueryGenerator { |
457 | 470 | |
458 | 471 | private static void addQueryByRule(QueryWrapper<?> queryWrapper,String name,String type,String value,QueryRuleEnum rule) throws ParseException { |
459 | 472 | if(oConvertUtils.isNotEmpty(value)) { |
460 | - Object temp; | |
473 | + //update-begin--Author:sunjianlei Date:20220104 for:【JTC-409】修复逗号分割情况下没有转换类型,导致类型严格的数据库查询报错 ------------------- | |
461 | 474 | // 针对数字类型字段,多值查询 |
462 | - if(value.indexOf(COMMA)!=-1){ | |
463 | - temp = value; | |
475 | + if(value.contains(COMMA)){ | |
476 | + Object[] temp = Arrays.stream(value.split(COMMA)).map(v -> { | |
477 | + try { | |
478 | + return QueryGenerator.parseByType(v, type, rule); | |
479 | + } catch (ParseException e) { | |
480 | + e.printStackTrace(); | |
481 | + return v; | |
482 | + } | |
483 | + }).toArray(); | |
464 | 484 | addEasyQuery(queryWrapper, name, rule, temp); |
465 | 485 | return; |
466 | 486 | } |
487 | + Object temp = QueryGenerator.parseByType(value, type, rule); | |
488 | + addEasyQuery(queryWrapper, name, rule, temp); | |
489 | + //update-end--Author:sunjianlei Date:20220104 for:【JTC-409】修复逗号分割情况下没有转换类型,导致类型严格的数据库查询报错 ------------------- | |
490 | + } | |
491 | + } | |
467 | 492 | |
468 | - switch (type) { | |
493 | + /** | |
494 | + * 根据类型转换给定的值 | |
495 | + * @param value | |
496 | + * @param type | |
497 | + * @param rule | |
498 | + * @return | |
499 | + * @throws ParseException | |
500 | + */ | |
501 | + private static Object parseByType(String value, String type, QueryRuleEnum rule) throws ParseException { | |
502 | + Object temp; | |
503 | + switch (type) { | |
469 | 504 | case "class java.lang.Integer": |
470 | 505 | temp = Integer.parseInt(value); |
471 | 506 | break; |
... | ... | @@ -490,9 +525,8 @@ public class QueryGenerator { |
490 | 525 | default: |
491 | 526 | temp = value; |
492 | 527 | break; |
493 | - } | |
494 | - addEasyQuery(queryWrapper, name, rule, temp); | |
495 | 528 | } |
529 | + return temp; | |
496 | 530 | } |
497 | 531 | |
498 | 532 | /** |
... | ... | @@ -527,12 +561,12 @@ public class QueryGenerator { |
527 | 561 | * @param rule 查询规则 |
528 | 562 | * @param value 查询条件值 |
529 | 563 | */ |
530 | - private static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) { | |
564 | + public static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) { | |
531 | 565 | if (value == null || rule == null || oConvertUtils.isEmpty(value)) { |
532 | 566 | return; |
533 | 567 | } |
534 | 568 | name = oConvertUtils.camelToUnderline(name); |
535 | - log.info("--查询规则-->"+name+" "+rule.getValue()+" "+value); | |
569 | + log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}",name,rule.getValue(),value); | |
536 | 570 | switch (rule) { |
537 | 571 | case GT: |
538 | 572 | queryWrapper.gt(name, value); |
... | ... | @@ -555,7 +589,7 @@ public class QueryGenerator { |
555 | 589 | break; |
556 | 590 | case IN: |
557 | 591 | if(value instanceof String) { |
558 | - queryWrapper.in(name, (Object[])value.toString().split(",")); | |
592 | + queryWrapper.in(name, (Object[])value.toString().split(COMMA)); | |
559 | 593 | }else if(value instanceof String[]) { |
560 | 594 | queryWrapper.in(name, (Object[]) value); |
561 | 595 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
... | ... | @@ -34,8 +34,8 @@ import org.jeecg.common.util.oConvertUtils; |
34 | 34 | **/ |
35 | 35 | public class JwtUtil { |
36 | 36 | |
37 | - // Token过期时间30分钟(用户登录过期时间是此时间的两倍,以token在reids缓存时间为准) | |
38 | - public static final long EXPIRE_TIME = 30 * 60 * 1000; | |
37 | + // Token过期时间2小时(用户登录过期时间是此时间的两倍,以token在reids缓存时间为准) | |
38 | + public static final long EXPIRE_TIME = 2 * 60 * 60 * 1000; | |
39 | 39 | |
40 | 40 | /** |
41 | 41 | * |
... | ... | @@ -155,7 +155,6 @@ public class JwtUtil { |
155 | 155 | * @param user |
156 | 156 | * @return |
157 | 157 | */ |
158 | - //TODO 急待改造 sckjkdsjsfjdk | |
159 | 158 | public static String getUserSystemData(String key,SysUserCacheInfo user) { |
160 | 159 | if(user==null) { |
161 | 160 | user = JeecgDataAutorUtils.loadUserInfo(); |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModel.java
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
... | ... | @@ -14,6 +14,7 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource; |
14 | 14 | import org.springframework.util.FileCopyUtils; |
15 | 15 | import org.springframework.web.multipart.MultipartFile; |
16 | 16 | |
17 | +import javax.servlet.http.HttpServletRequest; | |
17 | 18 | import javax.sql.DataSource; |
18 | 19 | import java.io.ByteArrayInputStream; |
19 | 20 | import java.io.File; |
... | ... | @@ -282,4 +283,39 @@ public class CommonUtils { |
282 | 283 | return DB_TYPE; |
283 | 284 | |
284 | 285 | } |
286 | + /** | |
287 | + * 获取服务器地址 | |
288 | + * | |
289 | + * @param request | |
290 | + * @return | |
291 | + */ | |
292 | + public static String getBaseUrl(HttpServletRequest request) { | |
293 | + //1.【兼容】兼容微服务下的 base path------- | |
294 | + String x_gateway_base_path = request.getHeader("X_GATEWAY_BASE_PATH"); | |
295 | + if(oConvertUtils.isNotEmpty(x_gateway_base_path)){ | |
296 | + log.info("x_gateway_base_path = "+ x_gateway_base_path); | |
297 | + return x_gateway_base_path; | |
298 | + } | |
299 | + //2.【兼容】SSL认证之后,request.getScheme()获取不到https的问题 | |
300 | + // https://blog.csdn.net/weixin_34376986/article/details/89767950 | |
301 | + String scheme = request.getHeader("X-Forwarded-Scheme"); | |
302 | + if(oConvertUtils.isEmpty(scheme)){ | |
303 | + scheme = request.getScheme(); | |
304 | + } | |
305 | + | |
306 | + //3.常规操作 | |
307 | + String serverName = request.getServerName(); | |
308 | + int serverPort = request.getServerPort(); | |
309 | + String contextPath = request.getContextPath(); | |
310 | + | |
311 | + //返回 host domain | |
312 | + String baseDomainPath = null; | |
313 | + if(80 == serverPort){ | |
314 | + baseDomainPath = scheme + "://" + serverName + contextPath ; | |
315 | + }else{ | |
316 | + baseDomainPath = scheme + "://" + serverName + ":" + serverPort + contextPath ; | |
317 | + } | |
318 | + log.info("-----Common getBaseUrl----- : " + baseDomainPath); | |
319 | + return baseDomainPath; | |
320 | + } | |
285 | 321 | } |
286 | 322 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java
1 | 1 | package org.jeecg.common.util; |
2 | 2 | |
3 | 3 | import io.minio.*; |
4 | +import io.minio.http.Method; | |
4 | 5 | import lombok.extern.slf4j.Slf4j; |
5 | 6 | import org.jeecg.common.util.filter.FileTypeFilter; |
6 | 7 | import org.jeecg.common.util.filter.StrAttackFilter; |
... | ... | @@ -158,9 +159,11 @@ public class MinioUtil { |
158 | 159 | public static String getObjectURL(String bucketName, String objectName, Integer expires) { |
159 | 160 | initMinio(minioUrl, minioName,minioPass); |
160 | 161 | try{ |
162 | + //update-begin---author:liusq Date:20220121 for:获取文件外链报错提示method不能为空,导致文件下载和预览失败---- | |
161 | 163 | GetPresignedObjectUrlArgs objectArgs = GetPresignedObjectUrlArgs.builder().object(objectName) |
162 | 164 | .bucket(bucketName) |
163 | - .expiry(expires).build(); | |
165 | + .expiry(expires).method(Method.GET).build(); | |
166 | + //update-begin---author:liusq Date:20220121 for:获取文件外链报错提示method不能为空,导致文件下载和预览失败---- | |
164 | 167 | String url = minioClient.getPresignedObjectUrl(objectArgs); |
165 | 168 | return URLDecoder.decode(url,"UTF-8"); |
166 | 169 | }catch (Exception e){ |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
... | ... | @@ -17,7 +17,7 @@ public class SqlInjectionUtil { |
17 | 17 | * (上线修改值 20200501,同步修改前端的盐值) |
18 | 18 | */ |
19 | 19 | private final static String TABLE_DICT_SIGN_SALT = "20200501"; |
20 | - private final static String xssStr = "'|and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+"; | |
20 | + private final static String xssStr = "and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()"; | |
21 | 21 | |
22 | 22 | /* |
23 | 23 | * 针对表字典进行额外的sign签名校验(增加安全机制) |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java
... | ... | @@ -25,7 +25,7 @@ public class DbTypeUtils { |
25 | 25 | dialectMap.put("postgresql", "org.hibernate.dialect.PostgreSQLDialect"); //1 -- |
26 | 26 | dialectMap.put("sqlserver2005", "org.hibernate.dialect.SQLServer2005Dialect"); |
27 | 27 | dialectMap.put("sqlserver", "org.hibernate.dialect.SQLServerDialect"); //1 |
28 | - dialectMap.put("dm", "org.hibernate.dialect.OracleDialect");//达梦数据库 [国产] 1-- | |
28 | + dialectMap.put("dm", "org.hibernate.dialect.DmDialect");//达梦数据库 [国产] 1-- | |
29 | 29 | dialectMap.put("xugu", "org.hibernate.dialect.HSQLDialect"); //虚谷数据库 |
30 | 30 | dialectMap.put("kingbasees", "org.hibernate.dialect.PostgreSQLDialect"); //人大金仓 [国产] 1 |
31 | 31 | dialectMap.put("phoenix", "org.hibernate.dialect.HSQLDialect"); // Phoenix HBase数据库 |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java
... | ... | @@ -258,6 +258,9 @@ public class OssBootUtil { |
258 | 258 | newBucket = bucket; |
259 | 259 | } |
260 | 260 | initOSS(endPoint, accessKeyId, accessKeySecret); |
261 | + //update-begin---author:liusq Date:20220120 for:替换objectName前缀,防止key不一致导致获取不到文件---- | |
262 | + objectName = OssBootUtil.replacePrefix(objectName,bucket); | |
263 | + //update-end---author:liusq Date:20220120 for:替换objectName前缀,防止key不一致导致获取不到文件---- | |
261 | 264 | OSSObject ossObject = ossClient.getObject(newBucket,objectName); |
262 | 265 | inputStream = new BufferedInputStream(ossObject.getObjectContent()); |
263 | 266 | }catch (Exception e){ |
... | ... | @@ -266,14 +269,14 @@ public class OssBootUtil { |
266 | 269 | return inputStream; |
267 | 270 | } |
268 | 271 | |
269 | - /** | |
270 | - * 获取文件流 | |
271 | - * @param objectName | |
272 | - * @return | |
273 | - */ | |
274 | - public static InputStream getOssFile(String objectName){ | |
275 | - return getOssFile(objectName,null); | |
276 | - } | |
272 | + ///** | |
273 | + // * 获取文件流 | |
274 | + // * @param objectName | |
275 | + // * @return | |
276 | + // */ | |
277 | + //public static InputStream getOssFile(String objectName){ | |
278 | + // return getOssFile(objectName,null); | |
279 | + //} | |
277 | 280 | |
278 | 281 | /** |
279 | 282 | * 获取文件外链 |
... | ... | @@ -285,6 +288,9 @@ public class OssBootUtil { |
285 | 288 | public static String getObjectURL(String bucketName, String objectName, Date expires) { |
286 | 289 | initOSS(endPoint, accessKeyId, accessKeySecret); |
287 | 290 | try{ |
291 | + //update-begin---author:liusq Date:20220120 for:替换objectName前缀,防止key不一致导致获取不到文件---- | |
292 | + objectName = OssBootUtil.replacePrefix(objectName,bucketName); | |
293 | + //update-end---author:liusq Date:20220120 for:替换objectName前缀,防止key不一致导致获取不到文件---- | |
288 | 294 | if(ossClient.doesObjectExist(bucketName,objectName)){ |
289 | 295 | URL url = ossClient.generatePresignedUrl(bucketName,objectName,expires); |
290 | 296 | return URLDecoder.decode(url.toString(),"UTF-8"); |
... | ... | @@ -334,5 +340,27 @@ public class OssBootUtil { |
334 | 340 | return FILE_URL; |
335 | 341 | } |
336 | 342 | |
337 | - | |
343 | + /** | |
344 | + * 替换前缀,防止key不一致导致获取不到文件 | |
345 | + * @param objectName 文件上传路径 key | |
346 | + * @param customBucket 自定义桶 | |
347 | + * @date 2022-01-20 | |
348 | + * @author lsq | |
349 | + * @return | |
350 | + */ | |
351 | + private static String replacePrefix(String objectName,String customBucket){ | |
352 | + log.info("------replacePrefix---替换前---objectName:{}",objectName); | |
353 | + if(oConvertUtils.isNotEmpty(staticDomain)){ | |
354 | + objectName= objectName.replace(staticDomain+"/",""); | |
355 | + }else{ | |
356 | + String newBucket = bucketName; | |
357 | + if(oConvertUtils.isNotEmpty(customBucket)){ | |
358 | + newBucket = customBucket; | |
359 | + } | |
360 | + String path ="https://" + newBucket + "." + endPoint + "/"; | |
361 | + objectName = objectName.replace(path,""); | |
362 | + } | |
363 | + log.info("------replacePrefix---替换后---objectName:{}",objectName); | |
364 | + return objectName; | |
365 | + } | |
338 | 366 | } |
339 | 367 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiDictConfig.java
1 | 1 | package org.jeecg.config; |
2 | 2 | |
3 | -import lombok.extern.slf4j.Slf4j; | |
3 | +import java.util.ArrayList; | |
4 | +import java.util.List; | |
5 | + | |
6 | +import javax.annotation.Resource; | |
7 | + | |
4 | 8 | import org.jeecg.common.api.CommonAPI; |
5 | 9 | import org.jeecg.common.system.vo.DictModel; |
6 | 10 | import org.jeecg.common.util.oConvertUtils; |
... | ... | @@ -8,9 +12,7 @@ import org.jeecgframework.dict.service.AutoPoiDictServiceI; |
8 | 12 | import org.springframework.context.annotation.Lazy; |
9 | 13 | import org.springframework.stereotype.Service; |
10 | 14 | |
11 | -import javax.annotation.Resource; | |
12 | -import java.util.ArrayList; | |
13 | -import java.util.List; | |
15 | +import lombok.extern.slf4j.Slf4j; | |
14 | 16 | |
15 | 17 | /** |
16 | 18 | * 描述:AutoPoi Excel注解支持字典参数设置 |
... | ... | @@ -25,6 +27,9 @@ import java.util.List; |
25 | 27 | @Slf4j |
26 | 28 | @Service |
27 | 29 | public class AutoPoiDictConfig implements AutoPoiDictServiceI { |
30 | + final static String EXCEL_SPLIT_TAG = "_"; | |
31 | + final static String TEMP_EXCEL_SPLIT_TAG = "---"; | |
32 | + | |
28 | 33 | @Lazy |
29 | 34 | @Resource |
30 | 35 | private CommonAPI commonAPI; |
... | ... | @@ -53,7 +58,14 @@ public class AutoPoiDictConfig implements AutoPoiDictServiceI { |
53 | 58 | } |
54 | 59 | for (DictModel t : dictList) { |
55 | 60 | if(t!=null){ |
56 | - dictReplaces.add(t.getText() + "_" + t.getValue()); | |
61 | + //update-begin---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- | |
62 | + if(t.getValue().contains(EXCEL_SPLIT_TAG)){ | |
63 | + String val = t.getValue().replace(EXCEL_SPLIT_TAG,TEMP_EXCEL_SPLIT_TAG); | |
64 | + dictReplaces.add(t.getText() + EXCEL_SPLIT_TAG + val); | |
65 | + }else{ | |
66 | + dictReplaces.add(t.getText() + EXCEL_SPLIT_TAG + t.getValue()); | |
67 | + } | |
68 | + //update-end---author:20211220 Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- | |
57 | 69 | } |
58 | 70 | } |
59 | 71 | if (dictReplaces != null && dictReplaces.size() != 0) { |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java
1 | 1 | package org.jeecg.config; |
2 | 2 | |
3 | +import org.jeecg.config.vo.Shiro; | |
3 | 4 | import org.springframework.boot.context.properties.ConfigurationProperties; |
4 | 5 | import org.springframework.stereotype.Component; |
5 | 6 | |
... | ... | @@ -14,6 +15,15 @@ public class JeeccgBaseConfig { |
14 | 15 | * 是否启用安全模式 |
15 | 16 | */ |
16 | 17 | private Boolean safeMode = false; |
18 | + /** | |
19 | + * shiro拦截排除 | |
20 | + */ | |
21 | + private Shiro shiro; | |
22 | + /** | |
23 | + * 签名密钥串(字典等敏感接口) | |
24 | + * @TODO 降低使用成本加的默认值,实际以 yml配置 为准 | |
25 | + */ | |
26 | + private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a"; | |
17 | 27 | |
18 | 28 | public Boolean getSafeMode() { |
19 | 29 | return safeMode; |
... | ... | @@ -22,4 +32,20 @@ public class JeeccgBaseConfig { |
22 | 32 | public void setSafeMode(Boolean safeMode) { |
23 | 33 | this.safeMode = safeMode; |
24 | 34 | } |
35 | + | |
36 | + public String getSignatureSecret() { | |
37 | + return signatureSecret; | |
38 | + } | |
39 | + | |
40 | + public void setSignatureSecret(String signatureSecret) { | |
41 | + this.signatureSecret = signatureSecret; | |
42 | + } | |
43 | + | |
44 | + public Shiro getShiro() { | |
45 | + return shiro; | |
46 | + } | |
47 | + | |
48 | + public void setShiro(Shiro shiro) { | |
49 | + this.shiro = shiro; | |
50 | + } | |
25 | 51 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java
... | ... | @@ -20,11 +20,11 @@ public class StaticConfig { |
20 | 20 | @Value(value = "${spring.mail.username}") |
21 | 21 | private String emailFrom; |
22 | 22 | |
23 | - /** | |
24 | - * 签名密钥串 | |
25 | - */ | |
26 | - @Value(value = "${jeecg.signatureSecret}") | |
27 | - private String signatureSecret; | |
23 | +// /** | |
24 | +// * 签名密钥串 | |
25 | +// */ | |
26 | +// @Value(value = "${jeecg.signatureSecret}") | |
27 | +// private String signatureSecret; | |
28 | 28 | |
29 | 29 | |
30 | 30 | /*@Bean |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
1 | + | |
1 | 2 | package org.jeecg.config.shiro; |
2 | 3 | |
3 | 4 | import lombok.extern.slf4j.Slf4j; |
... | ... | @@ -15,6 +16,7 @@ import org.crazycake.shiro.RedisClusterManager; |
15 | 16 | import org.crazycake.shiro.RedisManager; |
16 | 17 | import org.jeecg.common.constant.CommonConstant; |
17 | 18 | import org.jeecg.common.util.oConvertUtils; |
19 | +import org.jeecg.config.JeeccgBaseConfig; | |
18 | 20 | import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean; |
19 | 21 | import org.jeecg.config.shiro.filters.JwtFilter; |
20 | 22 | import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; |
... | ... | @@ -43,13 +45,12 @@ import java.util.*; |
43 | 45 | @Configuration |
44 | 46 | public class ShiroConfig { |
45 | 47 | |
46 | - @Value("${jeecg.shiro.excludeUrls}") | |
47 | - private String excludeUrls; | |
48 | 48 | @Resource |
49 | 49 | LettuceConnectionFactory lettuceConnectionFactory; |
50 | 50 | @Autowired |
51 | 51 | private Environment env; |
52 | - | |
52 | + @Autowired | |
53 | + JeeccgBaseConfig jeeccgBaseConfig; | |
53 | 54 | |
54 | 55 | /** |
55 | 56 | * Filter Chain定义说明 |
... | ... | @@ -64,8 +65,9 @@ public class ShiroConfig { |
64 | 65 | shiroFilterFactoryBean.setSecurityManager(securityManager); |
65 | 66 | // 拦截器 |
66 | 67 | Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); |
67 | - if(oConvertUtils.isNotEmpty(excludeUrls)){ | |
68 | - String[] permissionUrl = excludeUrls.split(","); | |
68 | + String shiroExcludeUrls = jeeccgBaseConfig.getShiro().getExcludeUrls(); | |
69 | + if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){ | |
70 | + String[] permissionUrl = shiroExcludeUrls.split(","); | |
69 | 71 | for(String url : permissionUrl){ |
70 | 72 | filterChainDefinitionMap.put(url,"anon"); |
71 | 73 | } |
... | ... | @@ -89,6 +91,12 @@ public class ShiroConfig { |
89 | 91 | filterChainDefinitionMap.put("/sys/common/static/**", "anon");//图片预览 &下载文件不限制token |
90 | 92 | filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览 |
91 | 93 | filterChainDefinitionMap.put("/generic/**", "anon");//pdf预览需要文件 |
94 | + | |
95 | + filterChainDefinitionMap.put("/sys/getLoginQrcode/**", "anon"); //登录二维码 | |
96 | + filterChainDefinitionMap.put("/sys/getQrcodeToken/**", "anon"); //监听扫码 | |
97 | + filterChainDefinitionMap.put("/sys/checkAuth", "anon"); //授权接口排除 | |
98 | + | |
99 | + | |
92 | 100 | filterChainDefinitionMap.put("/", "anon"); |
93 | 101 | filterChainDefinitionMap.put("/doc.html", "anon"); |
94 | 102 | filterChainDefinitionMap.put("/**/*.js", "anon"); |
... | ... | @@ -130,6 +138,9 @@ public class ShiroConfig { |
130 | 138 | filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块 |
131 | 139 | filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例 |
132 | 140 | |
141 | + //wps | |
142 | + filterChainDefinitionMap.put("/v1/**","anon"); | |
143 | + | |
133 | 144 | //性能监控 TODO 存在安全漏洞泄露TOEKN(durid连接池也有) |
134 | 145 | filterChainDefinitionMap.put("/actuator/**", "anon"); |
135 | 146 | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
... | ... | @@ -137,9 +137,12 @@ public class ShiroRealm extends AuthorizingRealm { |
137 | 137 | if(oConvertUtils.isNotEmpty(userTenantIds)){ |
138 | 138 | String contextTenantId = TenantContext.getTenant(); |
139 | 139 | if(oConvertUtils.isNotEmpty(contextTenantId) && !"0".equals(contextTenantId)){ |
140 | - if(String.join(",",userTenantIds).indexOf(contextTenantId)<0){ | |
140 | + //update-begin-author:taoyan date:20211227 for: /issues/I4O14W 用户租户信息变更判断漏洞 | |
141 | + String[] arr = userTenantIds.split(","); | |
142 | + if(!oConvertUtils.isIn(contextTenantId, arr)){ | |
141 | 143 | throw new AuthenticationException("用户租户信息变更,请重新登陆!"); |
142 | 144 | } |
145 | + //update-end-author:taoyan date:20211227 for: /issues/I4O14W 用户租户信息变更判断漏洞 | |
143 | 146 | } |
144 | 147 | } |
145 | 148 | //update-end-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致 |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
... | ... | @@ -5,7 +5,7 @@ import lombok.extern.slf4j.Slf4j; |
5 | 5 | import org.jeecg.common.exception.JeecgBootException; |
6 | 6 | import org.jeecg.common.util.SpringContextUtils; |
7 | 7 | import org.jeecg.common.util.oConvertUtils; |
8 | -import org.jeecg.config.StaticConfig; | |
8 | +import org.jeecg.config.JeeccgBaseConfig; | |
9 | 9 | import org.springframework.util.DigestUtils; |
10 | 10 | import org.springframework.util.StringUtils; |
11 | 11 | |
... | ... | @@ -46,8 +46,9 @@ public class SignUtil { |
46 | 46 | params.remove("_t"); |
47 | 47 | String paramsJsonStr = JSONObject.toJSONString(params); |
48 | 48 | log.info("Param paramsJsonStr : {}", paramsJsonStr); |
49 | - StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class); | |
50 | - String signatureSecret = staticConfig.getSignatureSecret(); | |
49 | + //设置签名秘钥 | |
50 | + JeeccgBaseConfig jeeccgBaseConfig = SpringContextUtils.getBean(JeeccgBaseConfig.class); | |
51 | + String signatureSecret = jeeccgBaseConfig.getSignatureSecret(); | |
51 | 52 | if(oConvertUtils.isEmpty(signatureSecret) || signatureSecret.contains("${")){ |
52 | 53 | throw new JeecgBootException("签名密钥 ${jeecg.signatureSecret} 缺少配置 !!"); |
53 | 54 | } |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Shiro.java
0 → 100644
1 | +package org.jeecg.config.vo; | |
2 | + | |
3 | +/** | |
4 | + * @Description: TODO | |
5 | + * @author: scott | |
6 | + * @date: 2022年01月21日 14:23 | |
7 | + */ | |
8 | +public class Shiro { | |
9 | + private String excludeUrls = ""; | |
10 | + | |
11 | + public String getExcludeUrls() { | |
12 | + return excludeUrls; | |
13 | + } | |
14 | + | |
15 | + public void setExcludeUrls(String excludeUrls) { | |
16 | + this.excludeUrls = excludeUrls; | |
17 | + } | |
18 | +} | |
... | ... |
jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml
jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java
jeecg-boot/jeecg-boot-base/pom.xml
jeecg-boot/jeecg-boot-module-demo/pom.xml
jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/mock/MockController.java
... | ... | @@ -31,7 +31,7 @@ public class MockController { |
31 | 31 | * @return |
32 | 32 | */ |
33 | 33 | @RequestMapping(value = "/json/{filename}", method = RequestMethod.GET) |
34 | - public String getJsonData(@PathVariable String filename) { | |
34 | + public String getJsonData(@PathVariable("filename") String filename) { | |
35 | 35 | String jsonpath = "classpath:org/jeecg/modules/demo/mock/json/"+filename+".json"; |
36 | 36 | return readJson(jsonpath); |
37 | 37 | } |
... | ... |
jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/online/OnlCgformDemoController.java
0 → 100644
1 | +package org.jeecg.modules.demo.online; | |
2 | + | |
3 | +import com.alibaba.fastjson.JSONArray; | |
4 | +import com.alibaba.fastjson.JSONObject; | |
5 | +import lombok.extern.slf4j.Slf4j; | |
6 | +import org.jeecg.common.api.vo.Result; | |
7 | +import org.jeecg.common.system.vo.DictModel; | |
8 | +import org.jeecg.common.util.oConvertUtils; | |
9 | +import org.springframework.web.bind.annotation.PostMapping; | |
10 | +import org.springframework.web.bind.annotation.RequestBody; | |
11 | +import org.springframework.web.bind.annotation.RequestMapping; | |
12 | +import org.springframework.web.bind.annotation.RestController; | |
13 | + | |
14 | +import java.util.ArrayList; | |
15 | +import java.util.List; | |
16 | + | |
17 | +/** | |
18 | + * Online表单开发 demo 示例 | |
19 | + * | |
20 | + * @author sunjianlei | |
21 | + * @date 2021-12-16 | |
22 | + */ | |
23 | +@Slf4j | |
24 | +@RestController("onlCgformDemoController") | |
25 | +@RequestMapping("/demo/online/cgform") | |
26 | +public class OnlCgformDemoController { | |
27 | + | |
28 | + /** | |
29 | + * Online表单 http 增强,list增强示例 | |
30 | + * @param params | |
31 | + * @return | |
32 | + */ | |
33 | + @PostMapping("/enhanceJavaListHttp") | |
34 | + public Result<?> enhanceJavaListHttp(@RequestBody JSONObject params) { | |
35 | + log.info(" --- params:" + params.toJSONString()); | |
36 | + JSONArray dataList = params.getJSONArray("dataList"); | |
37 | + List<DictModel> dict = virtualDictData(); | |
38 | + for (int i = 0; i < dataList.size(); i++) { | |
39 | + JSONObject record = dataList.getJSONObject(i); | |
40 | + String province = record.getString("province"); | |
41 | + if (province == null) { | |
42 | + continue; | |
43 | + } | |
44 | + String text = dict.stream() | |
45 | + .filter(p -> province.equals(p.getValue())) | |
46 | + .map(DictModel::getText) | |
47 | + .findAny() | |
48 | + .orElse(province); | |
49 | + record.put("province", text); | |
50 | + } | |
51 | + Result<?> res = Result.OK(dataList); | |
52 | + res.setCode(1); | |
53 | + return res; | |
54 | + } | |
55 | + | |
56 | + /** | |
57 | + * 模拟字典数据 | |
58 | + * | |
59 | + * @return | |
60 | + */ | |
61 | + private List<DictModel> virtualDictData() { | |
62 | + List<DictModel> dict = new ArrayList<>(); | |
63 | + dict.add(new DictModel("bj", "北京")); | |
64 | + dict.add(new DictModel("sd", "山东")); | |
65 | + dict.add(new DictModel("ah", "安徽")); | |
66 | + return dict; | |
67 | + } | |
68 | + | |
69 | + | |
70 | + /** | |
71 | + * Online表单 http 增强,add、edit增强示例 | |
72 | + * @param params | |
73 | + * @return | |
74 | + */ | |
75 | + @PostMapping("/enhanceJavaHttp") | |
76 | + public Result<?> enhanceJavaHttp(@RequestBody JSONObject params) { | |
77 | + log.info(" --- params:" + params.toJSONString()); | |
78 | + String tableName = params.getString("tableName"); | |
79 | + JSONObject record = params.getJSONObject("record"); | |
80 | + /* | |
81 | + * 业务场景一: 获取提交表单数据,进行其他业务关联操作 | |
82 | + * (比如:根据入库单,同步更改库存) | |
83 | + */ | |
84 | + log.info(" --- tableName:" + tableName); | |
85 | + log.info(" --- 行数据:" + record.toJSONString()); | |
86 | + /* | |
87 | + * 业务场景二: 保存数据之前进行数据的校验 | |
88 | + * 直接返回错误状态即可 | |
89 | + */ | |
90 | + String phone = record.getString("phone"); | |
91 | + if (oConvertUtils.isEmpty(phone)) { | |
92 | + return Result.error("手机号不能为空!"); | |
93 | + } | |
94 | + /* | |
95 | + * 业务场景三: 保存数据之对数据的处理 | |
96 | + * 直接操作 record 即可 | |
97 | + */ | |
98 | + record.put("phone", "010-" + phone); | |
99 | + | |
100 | + /* 其他业务场景自行实现 */ | |
101 | + | |
102 | + // 返回场景一: 不对 record 做任何修改的情况下,可以直接返回 code, | |
103 | + // 返回 0 = 丢弃当前数据 | |
104 | + // 返回 1 = 新增当前数据 | |
105 | + // 返回 2 = 修改当前数据 TODO(?)存疑 | |
106 | +// return Result.OK(1); | |
107 | + | |
108 | + // 返回场景二: 需要对 record 做修改的情况下,需要返回一个JSONObject对象(或者Map也行) | |
109 | + JSONObject res = new JSONObject(); | |
110 | + res.put("code", 1); | |
111 | + // 将 record 返回以进行修改 | |
112 | + res.put("record", record); | |
113 | + // TODO 不要 code 的概念 | |
114 | + return Result.OK(res); | |
115 | + } | |
116 | + | |
117 | +} | |
... | ... |
jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java
... | ... | @@ -62,6 +62,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe |
62 | 62 | public Result<?> list(JeecgDemo jeecgDemo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, |
63 | 63 | HttpServletRequest req) { |
64 | 64 | QueryWrapper<JeecgDemo> queryWrapper = QueryGenerator.initQueryWrapper(jeecgDemo, req.getParameterMap()); |
65 | + queryWrapper.orderByDesc("create_time"); | |
65 | 66 | Page<JeecgDemo> page = new Page<JeecgDemo>(pageNo, pageSize); |
66 | 67 | |
67 | 68 | IPage<JeecgDemo> pageList = jeecgDemoService.page(page, queryWrapper); |
... | ... | @@ -92,9 +93,9 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe |
92 | 93 | * @param jeecgDemo |
93 | 94 | * @return |
94 | 95 | */ |
95 | - @PutMapping(value = "/edit") | |
96 | - @ApiOperation(value = "编辑DEMO", notes = "编辑DEMO") | |
97 | 96 | @AutoLog(value = "编辑DEMO", operateType = CommonConstant.OPERATE_TYPE_3) |
97 | + @ApiOperation(value = "编辑DEMO", notes = "编辑DEMO") | |
98 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
98 | 99 | public Result<?> edit(@RequestBody JeecgDemo jeecgDemo) { |
99 | 100 | jeecgDemoService.updateById(jeecgDemo); |
100 | 101 | return Result.OK("更新成功!"); |
... | ... | @@ -316,5 +317,9 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe |
316 | 317 | return Result.OK("1"); |
317 | 318 | } |
318 | 319 | |
320 | + @GetMapping(value = "/hello") | |
321 | + public String hello(HttpServletRequest req) { | |
322 | + return "hello world!"; | |
323 | + } | |
319 | 324 | |
320 | 325 | } |
... | ... |
jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderTabMainController.java renamed to jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderErpMainController.java
1 | 1 | package org.jeecg.modules.demo.test.controller; |
2 | 2 | |
3 | -import java.util.Arrays; | |
4 | -import java.util.List; | |
5 | - | |
6 | -import javax.servlet.http.HttpServletRequest; | |
7 | - | |
3 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |
4 | +import com.baomidou.mybatisplus.core.metadata.IPage; | |
5 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |
6 | +import lombok.extern.slf4j.Slf4j; | |
8 | 7 | import org.jeecg.common.api.vo.Result; |
9 | 8 | import org.jeecg.common.system.query.QueryGenerator; |
10 | 9 | import org.jeecg.modules.demo.test.entity.JeecgOrderCustomer; |
... | ... | @@ -16,20 +15,10 @@ import org.jeecg.modules.demo.test.service.IJeecgOrderTicketService; |
16 | 15 | import org.jeecg.modules.demo.test.vo.JeecgOrderMainPage; |
17 | 16 | import org.springframework.beans.BeanUtils; |
18 | 17 | import org.springframework.beans.factory.annotation.Autowired; |
19 | -import org.springframework.web.bind.annotation.DeleteMapping; | |
20 | -import org.springframework.web.bind.annotation.GetMapping; | |
21 | -import org.springframework.web.bind.annotation.PostMapping; | |
22 | -import org.springframework.web.bind.annotation.PutMapping; | |
23 | -import org.springframework.web.bind.annotation.RequestBody; | |
24 | -import org.springframework.web.bind.annotation.RequestMapping; | |
25 | -import org.springframework.web.bind.annotation.RequestParam; | |
26 | -import org.springframework.web.bind.annotation.RestController; | |
18 | +import org.springframework.web.bind.annotation.*; | |
27 | 19 | |
28 | -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | |
29 | -import com.baomidou.mybatisplus.core.metadata.IPage; | |
30 | -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |
31 | - | |
32 | -import lombok.extern.slf4j.Slf4j; | |
20 | +import javax.servlet.http.HttpServletRequest; | |
21 | +import java.util.Arrays; | |
33 | 22 | |
34 | 23 | /** |
35 | 24 | * @Description: 一对多示例(ERP TAB风格) |
... | ... | @@ -40,7 +29,7 @@ import lombok.extern.slf4j.Slf4j; |
40 | 29 | @Slf4j |
41 | 30 | @RestController |
42 | 31 | @RequestMapping("/test/order") |
43 | -public class JeecgOrderTabMainController { | |
32 | +public class JeecgOrderErpMainController { | |
44 | 33 | |
45 | 34 | @Autowired |
46 | 35 | private IJeecgOrderMainService jeecgOrderMainService; |
... | ... | @@ -89,7 +78,7 @@ public class JeecgOrderTabMainController { |
89 | 78 | * @param jeecgOrderMainPage |
90 | 79 | * @return |
91 | 80 | */ |
92 | - @PutMapping("/edit") | |
81 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
93 | 82 | public Result<?> edit(@RequestBody JeecgOrderMainPage jeecgOrderMainPage) { |
94 | 83 | JeecgOrderMain jeecgOrderMain = new JeecgOrderMain(); |
95 | 84 | BeanUtils.copyProperties(jeecgOrderMainPage, jeecgOrderMain); |
... | ... | @@ -186,7 +175,7 @@ public class JeecgOrderTabMainController { |
186 | 175 | * @param jeecgOrderCustomer |
187 | 176 | * @return |
188 | 177 | */ |
189 | - @PutMapping("/editCustomer") | |
178 | + @RequestMapping(value = "/editCustomer", method = {RequestMethod.PUT,RequestMethod.POST}) | |
190 | 179 | public Result<?> editCustomer(@RequestBody JeecgOrderCustomer jeecgOrderCustomer) { |
191 | 180 | jeecgOrderCustomerService.updateById(jeecgOrderCustomer); |
192 | 181 | return Result.ok("添加成功!"); |
... | ... | @@ -234,7 +223,7 @@ public class JeecgOrderTabMainController { |
234 | 223 | * @param jeecgOrderTicket |
235 | 224 | * @return |
236 | 225 | */ |
237 | - @PutMapping("/editTicket") | |
226 | + @RequestMapping(value = "/editTicket", method = {RequestMethod.PUT,RequestMethod.POST}) | |
238 | 227 | public Result<?> editTicket(@RequestBody JeecgOrderTicket jeecgOrderTicket) { |
239 | 228 | jeecgOrderTicketService.updateById(jeecgOrderTicket); |
240 | 229 | return Result.ok("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderMainController.java
... | ... | @@ -104,7 +104,7 @@ public class JeecgOrderMainController extends JeecgController<JeecgOrderMain, IJ |
104 | 104 | * @param jeecgOrderMainPage |
105 | 105 | * @return |
106 | 106 | */ |
107 | - @PutMapping(value = "/edit") | |
107 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
108 | 108 | public Result<?> eidt(@RequestBody JeecgOrderMainPage jeecgOrderMainPage) { |
109 | 109 | JeecgOrderMain jeecgOrderMain = new JeecgOrderMain(); |
110 | 110 | BeanUtils.copyProperties(jeecgOrderMainPage, jeecgOrderMain); |
... | ... |
jeecg-boot/jeecg-boot-module-system/Dockerfile
... | ... | @@ -11,6 +11,6 @@ WORKDIR /jeecg-boot |
11 | 11 | EXPOSE 8080 |
12 | 12 | |
13 | 13 | ADD ./src/main/resources/jeecg ./config/jeecg |
14 | -ADD ./target/jeecg-boot-module-system-3.0.jar ./ | |
14 | +ADD ./target/jeecg-boot-module-system-3.1.0.jar ./ | |
15 | 15 | |
16 | -CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.0.jar | |
17 | 16 | \ No newline at end of file |
17 | +CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.1.0.jar | |
18 | 18 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/pom.xml
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | <parent> |
5 | 5 | <groupId>org.jeecgframework.boot</groupId> |
6 | 6 | <artifactId>jeecg-boot-parent</artifactId> |
7 | - <version>3.0</version> | |
7 | + <version>3.1.0</version> | |
8 | 8 | </parent> |
9 | 9 | <modelVersion>4.0.0</modelVersion> |
10 | 10 | |
... | ... | @@ -38,7 +38,7 @@ |
38 | 38 | <dependency> |
39 | 39 | <groupId>org.jeecgframework</groupId> |
40 | 40 | <artifactId>jeewx-api</artifactId> |
41 | - <version>1.4.6</version> | |
41 | + <version>1.4.7</version> | |
42 | 42 | <exclusions> |
43 | 43 | <exclusion> |
44 | 44 | <artifactId>commons-beanutils</artifactId> |
... | ... | @@ -54,7 +54,7 @@ |
54 | 54 | <dependency> |
55 | 55 | <groupId>org.jeecgframework.jimureport</groupId> |
56 | 56 | <artifactId>jimureport-spring-boot-starter</artifactId> |
57 | - <version>1.4.0</version> | |
57 | + <version>1.4.2</version> | |
58 | 58 | </dependency> |
59 | 59 | |
60 | 60 | |
... | ... | @@ -62,7 +62,7 @@ |
62 | 62 | <dependency> |
63 | 63 | <groupId>org.jeecgframework.boot</groupId> |
64 | 64 | <artifactId>jeecg-boot-module-demo</artifactId> |
65 | - <version>3.0</version> | |
65 | + <version>3.1.0</version> | |
66 | 66 | </dependency> |
67 | 67 | |
68 | 68 | </dependencies> |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/JeecgSystemApplication.java
1 | 1 | package org.jeecg; |
2 | 2 | |
3 | 3 | import lombok.extern.slf4j.Slf4j; |
4 | +import org.apache.catalina.Context; | |
5 | +import org.apache.tomcat.util.scan.StandardJarScanner; | |
4 | 6 | import org.jeecg.common.util.oConvertUtils; |
5 | 7 | import org.springframework.boot.SpringApplication; |
8 | +//import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | |
9 | +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | |
6 | 10 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
11 | +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; | |
7 | 12 | import org.springframework.boot.builder.SpringApplicationBuilder; |
13 | +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; | |
8 | 14 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; |
9 | 15 | import org.springframework.context.ConfigurableApplicationContext; |
16 | +import org.springframework.context.annotation.Bean; | |
10 | 17 | import org.springframework.core.env.Environment; |
11 | 18 | |
12 | 19 | import java.net.InetAddress; |
... | ... | @@ -17,6 +24,7 @@ import java.net.UnknownHostException; |
17 | 24 | */ |
18 | 25 | @Slf4j |
19 | 26 | @SpringBootApplication |
27 | +@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class}) | |
20 | 28 | public class JeecgSystemApplication extends SpringBootServletInitializer { |
21 | 29 | |
22 | 30 | @Override |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java
1 | 1 | package org.jeecg.config.jimureport; |
2 | 2 | |
3 | -import org.jeecg.common.constant.DataBaseConstant; | |
3 | +import lombok.extern.slf4j.Slf4j; | |
4 | 4 | import org.jeecg.common.system.api.ISysBaseAPI; |
5 | 5 | import org.jeecg.common.system.util.JwtUtil; |
6 | 6 | import org.jeecg.common.system.vo.SysUserCacheInfo; |
... | ... | @@ -20,6 +20,9 @@ import java.util.Map; |
20 | 20 | * * 1.自定义获取登录token |
21 | 21 | * * 2.自定义获取登录用户 |
22 | 22 | */ |
23 | + | |
24 | + | |
25 | +@Slf4j | |
23 | 26 | @Component |
24 | 27 | public class JimuReportTokenService implements JmReportTokenServiceI { |
25 | 28 | @Autowired |
... | ... | @@ -45,10 +48,16 @@ public class JimuReportTokenService implements JmReportTokenServiceI { |
45 | 48 | |
46 | 49 | @Override |
47 | 50 | public Map<String, Object> getUserInfo(String token) { |
51 | + Map<String, Object> map = new HashMap<String, Object>(); | |
48 | 52 | String username = JwtUtil.getUsername(token); |
49 | 53 | //此处通过token只能拿到一个信息 用户账号 后面的就是根据账号获取其他信息 查询数据或是走redis 用户根据自身业务可自定义 |
50 | - SysUserCacheInfo userInfo = sysBaseAPI.getCacheUser(username); | |
51 | - Map<String, Object> map = new HashMap<String, Object>(); | |
54 | + SysUserCacheInfo userInfo = null; | |
55 | + try { | |
56 | + userInfo = sysBaseAPI.getCacheUser(username); | |
57 | + } catch (Exception e) { | |
58 | + log.error("获取用户信息异常:"+ e.getMessage()); | |
59 | + return map; | |
60 | + } | |
52 | 61 | //设置账号名 |
53 | 62 | map.put(SYS_USER_CODE, userInfo.getSysUserCode()); |
54 | 63 | //设置部门编码 |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/aop/LogRecordAspect.java
1 | -package org.jeecg.modules.ngalain.aop; | |
2 | - | |
3 | -import javax.servlet.http.HttpServletRequest; | |
4 | - | |
5 | -import org.aspectj.lang.ProceedingJoinPoint; | |
6 | -import org.aspectj.lang.annotation.Around; | |
7 | -import org.aspectj.lang.annotation.Aspect; | |
8 | -import org.aspectj.lang.annotation.Pointcut; | |
9 | -import org.springframework.context.annotation.Configuration; | |
10 | -import org.springframework.web.context.request.RequestAttributes; | |
11 | -import org.springframework.web.context.request.RequestContextHolder; | |
12 | -import org.springframework.web.context.request.ServletRequestAttributes; | |
13 | -import org.slf4j.Logger; | |
14 | -import org.slf4j.LoggerFactory;; | |
15 | - | |
16 | - | |
17 | -// 暂时注释掉,提高系统性能 | |
18 | -//@Aspect //定义一个切面 | |
19 | -//@Configuration | |
20 | -public class LogRecordAspect { | |
21 | -private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class); | |
22 | - | |
23 | - // 定义切点Pointcut | |
24 | - @Pointcut("execution(public * org.jeecg.modules.*.*.*Controller.*(..))") | |
25 | - public void excudeService() { | |
26 | - } | |
27 | - | |
28 | - @Around("excudeService()") | |
29 | - public Object doAround(ProceedingJoinPoint pjp) throws Throwable { | |
30 | - RequestAttributes ra = RequestContextHolder.getRequestAttributes(); | |
31 | - ServletRequestAttributes sra = (ServletRequestAttributes) ra; | |
32 | - HttpServletRequest request = sra.getRequest(); | |
33 | - | |
34 | - String url = request.getRequestURL().toString(); | |
35 | - String method = request.getMethod(); | |
36 | - String uri = request.getRequestURI(); | |
37 | - String queryString = request.getQueryString(); | |
38 | - logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString); | |
39 | - | |
40 | - // result的值就是被拦截方法的返回值 | |
41 | - Object result = pjp.proceed(); | |
42 | - | |
43 | - logger.info("请求结束,controller的返回值是 " + result); | |
44 | - return result; | |
45 | - } | |
46 | -} | |
47 | 1 | \ No newline at end of file |
2 | +//package org.jeecg.modules.ngalain.aop; | |
3 | +// | |
4 | +//import javax.servlet.http.HttpServletRequest; | |
5 | +// | |
6 | +//import org.aspectj.lang.ProceedingJoinPoint; | |
7 | +//import org.aspectj.lang.annotation.Around; | |
8 | +//import org.aspectj.lang.annotation.Aspect; | |
9 | +//import org.aspectj.lang.annotation.Pointcut; | |
10 | +//import org.springframework.context.annotation.Configuration; | |
11 | +//import org.springframework.web.context.request.RequestAttributes; | |
12 | +//import org.springframework.web.context.request.RequestContextHolder; | |
13 | +//import org.springframework.web.context.request.ServletRequestAttributes; | |
14 | +//import org.slf4j.Logger; | |
15 | +//import org.slf4j.LoggerFactory;; | |
16 | +// | |
17 | +// | |
18 | +//// 暂时注释掉,提高系统性能 | |
19 | +////@Aspect //定义一个切面 | |
20 | +////@Configuration | |
21 | +//public class LogRecordAspect { | |
22 | +//private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class); | |
23 | +// | |
24 | +// // 定义切点Pointcut | |
25 | +// @Pointcut("execution(public * org.jeecg.modules.*.*.*Controller.*(..))") | |
26 | +// public void excudeService() { | |
27 | +// } | |
28 | +// | |
29 | +// @Around("excudeService()") | |
30 | +// public Object doAround(ProceedingJoinPoint pjp) throws Throwable { | |
31 | +// RequestAttributes ra = RequestContextHolder.getRequestAttributes(); | |
32 | +// ServletRequestAttributes sra = (ServletRequestAttributes) ra; | |
33 | +// HttpServletRequest request = sra.getRequest(); | |
34 | +// | |
35 | +// String url = request.getRequestURL().toString(); | |
36 | +// String method = request.getMethod(); | |
37 | +// String uri = request.getRequestURI(); | |
38 | +// String queryString = request.getQueryString(); | |
39 | +// logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString); | |
40 | +// | |
41 | +// // result的值就是被拦截方法的返回值 | |
42 | +// Object result = pjp.proceed(); | |
43 | +// | |
44 | +// logger.info("请求结束,controller的返回值是 " + result); | |
45 | +// return result; | |
46 | +// } | |
47 | +//} | |
48 | 48 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/controller/NgAlainController.java
1 | -package org.jeecg.modules.ngalain.controller; | |
2 | - | |
3 | -import java.util.ArrayList; | |
4 | -import java.util.List; | |
5 | -import java.util.Map; | |
6 | - | |
7 | -import javax.servlet.http.HttpServletRequest; | |
8 | - | |
9 | -import org.apache.shiro.SecurityUtils; | |
10 | -import org.jeecg.common.api.vo.Result; | |
11 | -import org.jeecg.common.system.vo.DictModel; | |
12 | -import org.jeecg.common.system.vo.LoginUser; | |
13 | -import org.jeecg.modules.ngalain.service.NgAlainService; | |
14 | -import org.jeecg.modules.system.service.ISysDictService; | |
15 | -import org.springframework.beans.factory.annotation.Autowired; | |
16 | -import org.springframework.web.bind.annotation.PathVariable; | |
17 | -import org.springframework.web.bind.annotation.RequestMapping; | |
18 | -import org.springframework.web.bind.annotation.RequestMethod; | |
19 | -import org.springframework.web.bind.annotation.ResponseBody; | |
20 | -import org.springframework.web.bind.annotation.RestController; | |
21 | - | |
22 | -import com.alibaba.fastjson.JSONObject; | |
23 | - | |
24 | -import lombok.extern.slf4j.Slf4j; | |
25 | - | |
26 | -@Slf4j | |
27 | -@RestController | |
28 | -@RequestMapping("/sys/ng-alain") | |
29 | -public class NgAlainController { | |
30 | - @Autowired | |
31 | - private NgAlainService ngAlainService; | |
32 | - @Autowired | |
33 | - private ISysDictService sysDictService; | |
34 | - | |
35 | - @RequestMapping(value = "/getAppData") | |
36 | - @ResponseBody | |
37 | - public JSONObject getAppData(HttpServletRequest request) throws Exception { | |
38 | - String token=request.getHeader("X-Access-Token"); | |
39 | - JSONObject j = new JSONObject(); | |
40 | - LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); | |
41 | - JSONObject userObjcet = new JSONObject(); | |
42 | - userObjcet.put("name", user.getUsername()); | |
43 | - userObjcet.put("avatar", user.getAvatar()); | |
44 | - userObjcet.put("email", user.getEmail()); | |
45 | - userObjcet.put("token", token); | |
46 | - j.put("user", userObjcet); | |
47 | - j.put("menu",ngAlainService.getMenu(user.getUsername())); | |
48 | - JSONObject app = new JSONObject(); | |
49 | - app.put("name", "jeecg-boot-angular"); | |
50 | - app.put("description", "jeecg+ng-alain整合版本"); | |
51 | - j.put("app", app); | |
52 | - return j; | |
53 | - } | |
54 | - | |
55 | - @RequestMapping(value = "/getDictItems/{dictCode}", method = RequestMethod.GET) | |
56 | - public Object getDictItems(@PathVariable String dictCode) { | |
57 | - log.info(" dictCode : "+ dictCode); | |
58 | - Result<List<DictModel>> result = new Result<List<DictModel>>(); | |
59 | - List<DictModel> ls = null; | |
60 | - try { | |
61 | - ls = sysDictService.queryDictItemsByCode(dictCode); | |
62 | - result.setSuccess(true); | |
63 | - result.setResult(ls); | |
64 | - } catch (Exception e) { | |
65 | - log.error(e.getMessage(),e); | |
66 | - result.error500("操作失败"); | |
67 | - return result; | |
68 | - } | |
69 | - List<JSONObject> dictlist=new ArrayList<>(); | |
70 | - for (DictModel l : ls) { | |
71 | - JSONObject dict=new JSONObject(); | |
72 | - try { | |
73 | - dict.put("value",Integer.parseInt(l.getValue())); | |
74 | - } catch (NumberFormatException e) { | |
75 | - dict.put("value",l.getValue()); | |
76 | - } | |
77 | - dict.put("label",l.getText()); | |
78 | - dictlist.add(dict); | |
79 | - } | |
80 | - return dictlist; | |
81 | - } | |
82 | - @RequestMapping(value = "/getDictItemsByTable/{table}/{key}/{value}", method = RequestMethod.GET) | |
83 | - public Object getDictItemsByTable(@PathVariable String table,@PathVariable String key,@PathVariable String value) { | |
84 | - return this.ngAlainService.getDictByTable(table,key,value); | |
85 | - } | |
86 | -} | |
1 | +//package org.jeecg.modules.ngalain.controller; | |
2 | +// | |
3 | +//import java.util.ArrayList; | |
4 | +//import java.util.List; | |
5 | +//import java.util.Map; | |
6 | +// | |
7 | +//import javax.servlet.http.HttpServletRequest; | |
8 | +// | |
9 | +//import org.apache.shiro.SecurityUtils; | |
10 | +//import org.jeecg.common.api.vo.Result; | |
11 | +//import org.jeecg.common.system.vo.DictModel; | |
12 | +//import org.jeecg.common.system.vo.LoginUser; | |
13 | +//import org.jeecg.modules.ngalain.service.NgAlainService; | |
14 | +//import org.jeecg.modules.system.service.ISysDictService; | |
15 | +//import org.springframework.beans.factory.annotation.Autowired; | |
16 | +//import org.springframework.web.bind.annotation.PathVariable; | |
17 | +//import org.springframework.web.bind.annotation.RequestMapping; | |
18 | +//import org.springframework.web.bind.annotation.RequestMethod; | |
19 | +//import org.springframework.web.bind.annotation.ResponseBody; | |
20 | +//import org.springframework.web.bind.annotation.RestController; | |
21 | +// | |
22 | +//import com.alibaba.fastjson.JSONObject; | |
23 | +// | |
24 | +//import lombok.extern.slf4j.Slf4j; | |
25 | +// | |
26 | +//@Slf4j | |
27 | +//@RestController | |
28 | +//@RequestMapping("/sys/ng-alain") | |
29 | +//public class NgAlainController { | |
30 | +// @Autowired | |
31 | +// private NgAlainService ngAlainService; | |
32 | +// @Autowired | |
33 | +// private ISysDictService sysDictService; | |
34 | +// | |
35 | +// @RequestMapping(value = "/getAppData") | |
36 | +// @ResponseBody | |
37 | +// public JSONObject getAppData(HttpServletRequest request) throws Exception { | |
38 | +// String token=request.getHeader("X-Access-Token"); | |
39 | +// JSONObject j = new JSONObject(); | |
40 | +// LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); | |
41 | +// JSONObject userObjcet = new JSONObject(); | |
42 | +// userObjcet.put("name", user.getUsername()); | |
43 | +// userObjcet.put("avatar", user.getAvatar()); | |
44 | +// userObjcet.put("email", user.getEmail()); | |
45 | +// userObjcet.put("token", token); | |
46 | +// j.put("user", userObjcet); | |
47 | +// j.put("menu",ngAlainService.getMenu(user.getUsername())); | |
48 | +// JSONObject app = new JSONObject(); | |
49 | +// app.put("name", "jeecg-boot-angular"); | |
50 | +// app.put("description", "jeecg+ng-alain整合版本"); | |
51 | +// j.put("app", app); | |
52 | +// return j; | |
53 | +// } | |
54 | +// | |
55 | +// @RequestMapping(value = "/getDictItems/{dictCode}", method = RequestMethod.GET) | |
56 | +// public Object getDictItems(@PathVariable String dictCode) { | |
57 | +// log.info(" dictCode : "+ dictCode); | |
58 | +// Result<List<DictModel>> result = new Result<List<DictModel>>(); | |
59 | +// List<DictModel> ls = null; | |
60 | +// try { | |
61 | +// ls = sysDictService.queryDictItemsByCode(dictCode); | |
62 | +// result.setSuccess(true); | |
63 | +// result.setResult(ls); | |
64 | +// } catch (Exception e) { | |
65 | +// log.error(e.getMessage(),e); | |
66 | +// result.error500("操作失败"); | |
67 | +// return result; | |
68 | +// } | |
69 | +// List<JSONObject> dictlist=new ArrayList<>(); | |
70 | +// for (DictModel l : ls) { | |
71 | +// JSONObject dict=new JSONObject(); | |
72 | +// try { | |
73 | +// dict.put("value",Integer.parseInt(l.getValue())); | |
74 | +// } catch (NumberFormatException e) { | |
75 | +// dict.put("value",l.getValue()); | |
76 | +// } | |
77 | +// dict.put("label",l.getText()); | |
78 | +// dictlist.add(dict); | |
79 | +// } | |
80 | +// return dictlist; | |
81 | +// } | |
82 | +// @RequestMapping(value = "/getDictItemsByTable/{table}/{key}/{value}", method = RequestMethod.GET) | |
83 | +// public Object getDictItemsByTable(@PathVariable String table,@PathVariable String key,@PathVariable String value) { | |
84 | +// return this.ngAlainService.getDictByTable(table,key,value); | |
85 | +// } | |
86 | +//} | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
... | ... | @@ -6,10 +6,12 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
6 | 6 | import io.swagger.annotations.Api; |
7 | 7 | import io.swagger.annotations.ApiOperation; |
8 | 8 | import lombok.extern.slf4j.Slf4j; |
9 | +import org.apache.shiro.SecurityUtils; | |
9 | 10 | import org.apache.shiro.authz.annotation.RequiresRoles; |
10 | 11 | import org.jeecg.common.api.vo.Result; |
11 | 12 | import org.jeecg.common.constant.CommonConstant; |
12 | 13 | import org.jeecg.common.system.query.QueryGenerator; |
14 | +import org.jeecg.common.system.vo.LoginUser; | |
13 | 15 | import org.jeecg.common.util.ImportExcelUtil; |
14 | 16 | import org.jeecg.modules.quartz.entity.QuartzJob; |
15 | 17 | import org.jeecg.modules.quartz.service.IQuartzJobService; |
... | ... | @@ -145,14 +147,14 @@ public class QuartzJobController { |
145 | 147 | */ |
146 | 148 | //@RequiresRoles("admin") |
147 | 149 | @GetMapping(value = "/pause") |
148 | - @ApiOperation(value = "暂停定时任务") | |
150 | + @ApiOperation(value = "停止定时任务") | |
149 | 151 | public Result<Object> pauseJob(@RequestParam(name = "id") String id) { |
150 | 152 | QuartzJob job = quartzJobService.getById(id); |
151 | 153 | if (job == null) { |
152 | 154 | return Result.error("定时任务不存在!"); |
153 | 155 | } |
154 | 156 | quartzJobService.pause(job); |
155 | - return Result.ok("暂停定时任务成功"); | |
157 | + return Result.ok("停止定时任务成功"); | |
156 | 158 | } |
157 | 159 | |
158 | 160 | /** |
... | ... | @@ -163,7 +165,7 @@ public class QuartzJobController { |
163 | 165 | */ |
164 | 166 | //@RequiresRoles("admin") |
165 | 167 | @GetMapping(value = "/resume") |
166 | - @ApiOperation(value = "恢复定时任务") | |
168 | + @ApiOperation(value = "启动定时任务") | |
167 | 169 | public Result<Object> resumeJob(@RequestParam(name = "id") String id) { |
168 | 170 | QuartzJob job = quartzJobService.getById(id); |
169 | 171 | if (job == null) { |
... | ... | @@ -171,7 +173,7 @@ public class QuartzJobController { |
171 | 173 | } |
172 | 174 | quartzJobService.resumeJob(job); |
173 | 175 | //scheduler.resumeJob(JobKey.jobKey(job.getJobClassName().trim())); |
174 | - return Result.ok("恢复定时任务成功"); | |
176 | + return Result.ok("启动定时任务成功"); | |
175 | 177 | } |
176 | 178 | |
177 | 179 | /** |
... | ... | @@ -202,8 +204,12 @@ public class QuartzJobController { |
202 | 204 | // 导出文件名称 |
203 | 205 | mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表"); |
204 | 206 | mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class); |
205 | - mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:Jeecg", "导出信息")); | |
206 | - mv.addObject(NormalExcelConstants.DATA_LIST, pageList); | |
207 | + //获取当前登录用户 | |
208 | + //update-begin---author:wangshuai ---date:20211227 for:[JTC-116]导出人写死了------------ | |
209 | + LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); | |
210 | + mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:"+user.getRealname(), "导出信息")); | |
211 | + //update-end---author:wangshuai ---date:20211227 for:[JTC-116]导出人写死了------------ | |
212 | + mv.addObject(NormalExcelConstants.DATA_LIST, pageList); | |
207 | 213 | return mv; |
208 | 214 | } |
209 | 215 | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/job/SampleJob.java
... | ... | @@ -17,7 +17,7 @@ public class SampleJob implements Job { |
17 | 17 | |
18 | 18 | @Override |
19 | 19 | public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { |
20 | - | |
20 | + log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey()); | |
21 | 21 | log.info(String.format(" Jeecg-Boot 普通定时任务 SampleJob ! 时间:" + DateUtils.getTimestamp())); |
22 | 22 | } |
23 | 23 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java
... | ... | @@ -47,6 +47,15 @@ public class DuplicateCheckController { |
47 | 47 | //SQL注入校验(只限制非法串改数据库) |
48 | 48 | final String[] sqlInjCheck = {duplicateCheckVo.getTableName(),duplicateCheckVo.getFieldName()}; |
49 | 49 | SqlInjectionUtil.filterContent(sqlInjCheck); |
50 | + // update-begin-author:taoyan date:20211227 for: JTC-25 【online报表】oracle 操作问题 录入弹框啥都不填直接保存 ①编码不是应该提示必填么?②报错也应该是具体文字提示,不是后台错误日志 | |
51 | + if(StringUtils.isEmpty(duplicateCheckVo.getFieldVal())){ | |
52 | + Result rs = new Result(); | |
53 | + rs.setCode(500); | |
54 | + rs.setSuccess(true); | |
55 | + rs.setMessage("数据为空,不作处理!"); | |
56 | + return rs; | |
57 | + } | |
58 | + // update-end-author:taoyan date:20211227 for: JTC-25 【online报表】oracle 操作问题 录入弹框啥都不填直接保存 ①编码不是应该提示必填么?②报错也应该是具体文字提示,不是后台错误日志 | |
50 | 59 | if (StringUtils.isNotBlank(duplicateCheckVo.getDataId())) { |
51 | 60 | // [2].编辑页面校验 |
52 | 61 | num = sysDictMapper.duplicateCheckCountSql(duplicateCheckVo); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
... | ... | @@ -4,6 +4,7 @@ import cn.hutool.core.util.RandomUtil; |
4 | 4 | import com.alibaba.fastjson.JSONObject; |
5 | 5 | import com.aliyuncs.exceptions.ClientException; |
6 | 6 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
7 | +import com.baomidou.mybatisplus.core.toolkit.IdWorker; | |
7 | 8 | import io.swagger.annotations.Api; |
8 | 9 | import io.swagger.annotations.ApiOperation; |
9 | 10 | import lombok.extern.slf4j.Slf4j; |
... | ... | @@ -58,8 +59,6 @@ public class LoginController { |
58 | 59 | @Resource |
59 | 60 | private BaseCommonService baseCommonService; |
60 | 61 | |
61 | - private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890"; | |
62 | - | |
63 | 62 | @ApiOperation("登录接口") |
64 | 63 | @RequestMapping(value = "/login", method = RequestMethod.POST) |
65 | 64 | public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel){ |
... | ... | @@ -82,6 +81,7 @@ public class LoginController { |
82 | 81 | Object checkCode = redisUtil.get(realKey); |
83 | 82 | //当进入登录页时,有一定几率出现验证码错误 #1714 |
84 | 83 | if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) { |
84 | + log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode); | |
85 | 85 | result.error500("验证码错误"); |
86 | 86 | return result; |
87 | 87 | } |
... | ... | @@ -402,7 +402,10 @@ public class LoginController { |
402 | 402 | // update-begin--Author:sunjianlei Date:20210802 for:获取用户租户信息 |
403 | 403 | String tenantIds = sysUser.getRelTenantIds(); |
404 | 404 | if (oConvertUtils.isNotEmpty(tenantIds)) { |
405 | - List<String> tenantIdList = Arrays.asList(tenantIds.split(",")); | |
405 | + List<Integer> tenantIdList = new ArrayList<>(); | |
406 | + for(String id: tenantIds.split(",")){ | |
407 | + tenantIdList.add(Integer.valueOf(id)); | |
408 | + } | |
406 | 409 | // 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。 |
407 | 410 | List<SysTenant> tenantList = sysTenantService.queryEffectiveTenant(tenantIdList); |
408 | 411 | if (tenantList.size() == 0) { |
... | ... | @@ -450,10 +453,17 @@ public class LoginController { |
450 | 453 | public Result<String> randomImage(HttpServletResponse response,@PathVariable String key){ |
451 | 454 | Result<String> res = new Result<String>(); |
452 | 455 | try { |
456 | + //生成验证码 | |
457 | + final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890"; | |
453 | 458 | String code = RandomUtil.randomString(BASE_CHECK_CODES,4); |
459 | + | |
460 | + //存到redis中 | |
454 | 461 | String lowerCaseCode = code.toLowerCase(); |
455 | 462 | String realKey = MD5Util.MD5Encode(lowerCaseCode+key, "utf-8"); |
463 | + log.info("获取验证码,Redis checkCode = {},key = {}", code, key); | |
456 | 464 | redisUtil.set(realKey, lowerCaseCode, 60); |
465 | + | |
466 | + //返回前端 | |
457 | 467 | String base64 = RandImageUtil.generate(code); |
458 | 468 | res.setSuccess(true); |
459 | 469 | res.setResult(base64); |
... | ... | @@ -495,13 +505,16 @@ public class LoginController { |
495 | 505 | if(oConvertUtils.isEmpty(orgCode)) { |
496 | 506 | //如果当前用户无选择部门 查看部门关联信息 |
497 | 507 | List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId()); |
508 | + //update-begin-author:taoyan date:20220117 for: JTC-1068【app】新建用户,没有设置部门及角色,点击登录提示暂未归属部,一直在登录页面 使用手机号登录 可正常 | |
498 | 509 | if (departs == null || departs.size() == 0) { |
499 | - result.error500("用户暂未归属部门,不可登录!"); | |
500 | - return result; | |
510 | + /*result.error500("用户暂未归属部门,不可登录!"); | |
511 | + return result;*/ | |
512 | + }else{ | |
513 | + orgCode = departs.get(0).getOrgCode(); | |
514 | + sysUser.setOrgCode(orgCode); | |
515 | + this.sysUserService.updateUserDepart(username, orgCode); | |
501 | 516 | } |
502 | - orgCode = departs.get(0).getOrgCode(); | |
503 | - sysUser.setOrgCode(orgCode); | |
504 | - this.sysUserService.updateUserDepart(username, orgCode); | |
517 | + //update-end-author:taoyan date:20220117 for: JTC-1068【app】新建用户,没有设置部门及角色,点击登录提示暂未归属部,一直在登录页面 使用手机号登录 可正常 | |
505 | 518 | } |
506 | 519 | JSONObject obj = new JSONObject(); |
507 | 520 | //用户登录信息 |
... | ... | @@ -542,5 +555,58 @@ public class LoginController { |
542 | 555 | } |
543 | 556 | return Result.ok(); |
544 | 557 | } |
558 | + /** | |
559 | + * 登录二维码 | |
560 | + */ | |
561 | + @ApiOperation(value = "登录二维码", notes = "登录二维码") | |
562 | + @GetMapping("/getLoginQrcode") | |
563 | + public Result<?> getLoginQrcode() { | |
564 | + String qrcodeId = CommonConstant.LOGIN_QRCODE_PRE+IdWorker.getIdStr(); | |
565 | + //定义二维码参数 | |
566 | + Map params = new HashMap(5); | |
567 | + params.put("qrcodeId", qrcodeId); | |
568 | + //存放二维码唯一标识30秒有效 | |
569 | + redisUtil.set(CommonConstant.LOGIN_QRCODE + qrcodeId, qrcodeId, 30); | |
570 | + return Result.OK(params); | |
571 | + } | |
572 | + /** | |
573 | + * 扫码二维码 | |
574 | + */ | |
575 | + @ApiOperation(value = "扫码登录二维码", notes = "扫码登录二维码") | |
576 | + @PostMapping("/scanLoginQrcode") | |
577 | + public Result<?> scanLoginQrcode(@RequestParam String qrcodeId, @RequestParam String token) { | |
578 | + Object check = redisUtil.get(CommonConstant.LOGIN_QRCODE + qrcodeId); | |
579 | + if (oConvertUtils.isNotEmpty(check)) { | |
580 | + //存放token给前台读取 | |
581 | + redisUtil.set(CommonConstant.LOGIN_QRCODE_TOKEN+qrcodeId, token, 60); | |
582 | + } else { | |
583 | + return Result.error("二维码已过期,请刷新后重试"); | |
584 | + } | |
585 | + return Result.OK("扫码成功"); | |
586 | + } | |
587 | + | |
588 | + | |
589 | + /** | |
590 | + * 获取用户扫码后保存的token | |
591 | + */ | |
592 | + @ApiOperation(value = "获取用户扫码后保存的token", notes = "获取用户扫码后保存的token") | |
593 | + @GetMapping("/getQrcodeToken") | |
594 | + public Result getQrcodeToken(@RequestParam String qrcodeId) { | |
595 | + Object token = redisUtil.get(CommonConstant.LOGIN_QRCODE_TOKEN + qrcodeId); | |
596 | + Map result = new HashMap(); | |
597 | + Object qrcodeIdExpire = redisUtil.get(CommonConstant.LOGIN_QRCODE + qrcodeId); | |
598 | + if (oConvertUtils.isEmpty(qrcodeIdExpire)) { | |
599 | + //二维码过期通知前台刷新 | |
600 | + result.put("token", "-2"); | |
601 | + return Result.OK(result); | |
602 | + } | |
603 | + if (oConvertUtils.isNotEmpty(token)) { | |
604 | + result.put("success", true); | |
605 | + result.put("token", token); | |
606 | + } else { | |
607 | + result.put("token", "-1"); | |
608 | + } | |
609 | + return Result.OK(result); | |
610 | + } | |
545 | 611 | |
546 | 612 | } |
547 | 613 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/MockVue3Controller.java deleted
1 | -package org.jeecg.modules.system.controller; | |
2 | - | |
3 | -import lombok.extern.slf4j.Slf4j; | |
4 | -import org.jeecg.common.api.vo.Result; | |
5 | -import org.jeecg.modules.system.entity.SysUser; | |
6 | -import org.springframework.web.bind.annotation.GetMapping; | |
7 | -import org.springframework.web.bind.annotation.RequestMapping; | |
8 | -import org.springframework.web.bind.annotation.RestController; | |
9 | - | |
10 | -/** | |
11 | - * vue3前端临时接口 | |
12 | - */ | |
13 | -@RestController | |
14 | -@RequestMapping("/") | |
15 | -@Slf4j | |
16 | -public class MockVue3Controller { | |
17 | - | |
18 | - | |
19 | -} |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
... | ... | @@ -14,6 +14,7 @@ import org.jeecg.common.constant.CommonConstant; |
14 | 14 | import org.jeecg.common.constant.CommonSendStatus; |
15 | 15 | import org.jeecg.common.constant.WebsocketConst; |
16 | 16 | import org.jeecg.common.system.api.ISysBaseAPI; |
17 | +import org.jeecg.common.system.query.QueryGenerator; | |
17 | 18 | import org.jeecg.common.system.util.JwtUtil; |
18 | 19 | import org.jeecg.common.system.vo.LoginUser; |
19 | 20 | import org.jeecg.common.util.RedisUtil; |
... | ... | @@ -93,18 +94,21 @@ public class SysAnnouncementController { |
93 | 94 | HttpServletRequest req) { |
94 | 95 | Result<IPage<SysAnnouncement>> result = new Result<IPage<SysAnnouncement>>(); |
95 | 96 | sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString()); |
96 | - QueryWrapper<SysAnnouncement> queryWrapper = new QueryWrapper<SysAnnouncement>(sysAnnouncement); | |
97 | + QueryWrapper<SysAnnouncement> queryWrapper = QueryGenerator.initQueryWrapper(sysAnnouncement, req.getParameterMap()); | |
97 | 98 | Page<SysAnnouncement> page = new Page<SysAnnouncement>(pageNo,pageSize); |
99 | + | |
100 | + //update-begin-author:lvdandan date:20211229 for: sqlserver mssql-jdbc 8.2.2.jre8版本下系统公告列表查询报错 查询SQL中生成了两个create_time DESC;故注释此段代码 | |
98 | 101 | //排序逻辑 处理 |
99 | - String column = req.getParameter("column"); | |
100 | - String order = req.getParameter("order"); | |
101 | - if(oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) { | |
102 | - if("asc".equals(order)) { | |
103 | - queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column)); | |
104 | - }else { | |
105 | - queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column)); | |
106 | - } | |
107 | - } | |
102 | +// String column = req.getParameter("column"); | |
103 | +// String order = req.getParameter("order"); | |
104 | +// if(oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) { | |
105 | +// if("asc".equals(order)) { | |
106 | +// queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column)); | |
107 | +// }else { | |
108 | +// queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column)); | |
109 | +// } | |
110 | +// } | |
111 | + //update-end-author:lvdandan date:20211229 for: sqlserver mssql-jdbc 8.2.2.jre8版本下系统公告列表查询报错 查询SQL中生成了两个create_time DESC;故注释此段代码 | |
108 | 112 | IPage<SysAnnouncement> pageList = sysAnnouncementService.page(page, queryWrapper); |
109 | 113 | result.setSuccess(true); |
110 | 114 | result.setResult(pageList); |
... | ... | @@ -337,11 +341,13 @@ public class SysAnnouncementController { |
337 | 341 | query.eq(SysAnnouncementSend::getUserId,userId); |
338 | 342 | SysAnnouncementSend one = sysAnnouncementSendService.getOne(query); |
339 | 343 | if(null==one){ |
340 | - SysAnnouncementSend announcementSend = new SysAnnouncementSend(); | |
341 | - announcementSend.setAnntId(announcements.get(i).getId()); | |
342 | - announcementSend.setUserId(userId); | |
343 | - announcementSend.setReadFlag(CommonConstant.NO_READ_FLAG); | |
344 | - sysAnnouncementSendService.save(announcementSend); | |
344 | + log.info("listByUser接口新增了SysAnnouncementSend:pageSize{}:"+pageSize); | |
345 | + SysAnnouncementSend announcementSend = new SysAnnouncementSend(); | |
346 | + announcementSend.setAnntId(announcements.get(i).getId()); | |
347 | + announcementSend.setUserId(userId); | |
348 | + announcementSend.setReadFlag(CommonConstant.NO_READ_FLAG); | |
349 | + sysAnnouncementSendService.save(announcementSend); | |
350 | + log.info("announcementSend.toString()",announcementSend.toString()); | |
345 | 351 | } |
346 | 352 | //update-end--Author:wangshuai Date:20200803 for: 通知公告消息重复LOWCOD-759------------ |
347 | 353 | } |
... | ... | @@ -373,7 +379,7 @@ public class SysAnnouncementController { |
373 | 379 | LambdaQueryWrapper<SysAnnouncement> queryWrapper = new LambdaQueryWrapper<SysAnnouncement>(sysAnnouncement); |
374 | 380 | //Step.2 AutoPoi 导出Excel |
375 | 381 | ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); |
376 | - queryWrapper.eq(SysAnnouncement::getDelFlag,CommonConstant.DEL_FLAG_0); | |
382 | + queryWrapper.eq(SysAnnouncement::getDelFlag,CommonConstant.DEL_FLAG_0.toString()); | |
377 | 383 | List<SysAnnouncement> pageList = sysAnnouncementService.list(queryWrapper); |
378 | 384 | //导出文件名称 |
379 | 385 | mv.addObject(NormalExcelConstants.FILE_NAME, "系统通告列表"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java
... | ... | @@ -10,6 +10,7 @@ import org.jeecg.common.api.vo.Result; |
10 | 10 | import org.jeecg.common.constant.CommonConstant; |
11 | 11 | import org.jeecg.common.constant.WebsocketConst; |
12 | 12 | import org.jeecg.common.system.vo.LoginUser; |
13 | +import org.jeecg.common.util.SqlInjectionUtil; | |
13 | 14 | import org.jeecg.common.util.oConvertUtils; |
14 | 15 | import org.jeecg.modules.message.websocket.WebSocket; |
15 | 16 | import org.jeecg.modules.system.entity.SysAnnouncementSend; |
... | ... | @@ -69,6 +70,11 @@ public class SysAnnouncementSendController { |
69 | 70 | //排序逻辑 处理 |
70 | 71 | String column = req.getParameter("column"); |
71 | 72 | String order = req.getParameter("order"); |
73 | + | |
74 | + //issues/3331 SQL injection vulnerability | |
75 | + SqlInjectionUtil.filterContent(column); | |
76 | + SqlInjectionUtil.filterContent(order); | |
77 | + | |
72 | 78 | if(oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) { |
73 | 79 | if("asc".equals(order)) { |
74 | 80 | queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column)); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java
... | ... | @@ -9,9 +9,11 @@ import lombok.extern.slf4j.Slf4j; |
9 | 9 | import org.apache.commons.lang.StringUtils; |
10 | 10 | import org.apache.shiro.SecurityUtils; |
11 | 11 | import org.jeecg.common.api.vo.Result; |
12 | +import org.jeecg.common.constant.CommonConstant; | |
12 | 13 | import org.jeecg.common.system.query.QueryGenerator; |
13 | 14 | import org.jeecg.common.system.vo.DictModel; |
14 | 15 | import org.jeecg.common.system.vo.LoginUser; |
16 | +import org.jeecg.common.util.ImportExcelUtil; | |
15 | 17 | import org.jeecg.common.util.oConvertUtils; |
16 | 18 | import org.jeecg.modules.system.entity.SysCategory; |
17 | 19 | import org.jeecg.modules.system.model.TreeSelectModel; |
... | ... | @@ -65,10 +67,16 @@ public class SysCategoryController { |
65 | 67 | Result<IPage<SysCategory>> result = new Result<IPage<SysCategory>>(); |
66 | 68 | |
67 | 69 | //--author:os_chengtgen---date:20190804 -----for: 分类字典页面显示错误,issues:377--------start |
68 | - //QueryWrapper<SysCategory> queryWrapper = QueryGenerator.initQueryWrapper(sysCategory, req.getParameterMap()); | |
69 | - QueryWrapper<SysCategory> queryWrapper = new QueryWrapper<SysCategory>(); | |
70 | - queryWrapper.eq("pid", sysCategory.getPid()); | |
71 | - //--author:os_chengtgen---date:20190804 -----for: 分类字典页面显示错误,issues:377--------end | |
70 | + //--author:liusq---date:20211119 -----for: 【vue3】分类字典页面查询条件配置--------start | |
71 | + QueryWrapper<SysCategory> queryWrapper = QueryGenerator.initQueryWrapper(sysCategory, req.getParameterMap()); | |
72 | + String name = sysCategory.getName(); | |
73 | + String code = sysCategory.getCode(); | |
74 | + //QueryWrapper<SysCategory> queryWrapper = new QueryWrapper<SysCategory>(); | |
75 | + if(StringUtils.isBlank(name)&&StringUtils.isBlank(code)){ | |
76 | + queryWrapper.eq("pid", sysCategory.getPid()); | |
77 | + } | |
78 | + //--author:liusq---date:20211119 -----for: 分类字典页面查询条件配置--------end | |
79 | + //--author:os_chengtgen---date:20190804 -----for:【vue3】 分类字典页面显示错误,issues:377--------end | |
72 | 80 | |
73 | 81 | Page<SysCategory> page = new Page<SysCategory>(pageNo, pageSize); |
74 | 82 | IPage<SysCategory> pageList = sysCategoryService.page(page, queryWrapper); |
... | ... | @@ -215,10 +223,13 @@ public class SysCategoryController { |
215 | 223 | * @return |
216 | 224 | */ |
217 | 225 | @RequestMapping(value = "/importExcel", method = RequestMethod.POST) |
218 | - public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) { | |
226 | + public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws IOException{ | |
219 | 227 | MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request; |
220 | 228 | Map<String, MultipartFile> fileMap = multipartRequest.getFileMap(); |
221 | - for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) { | |
229 | + // 错误信息 | |
230 | + List<String> errorMessage = new ArrayList<>(); | |
231 | + int successLines = 0, errorLines = 0; | |
232 | + for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) { | |
222 | 233 | MultipartFile file = entity.getValue();// 获取上传文件对象 |
223 | 234 | ImportParams params = new ImportParams(); |
224 | 235 | params.setTitleRows(2); |
... | ... | @@ -229,7 +240,8 @@ public class SysCategoryController { |
229 | 240 | //按照编码长度排序 |
230 | 241 | Collections.sort(listSysCategorys); |
231 | 242 | log.info("排序后的list====>",listSysCategorys); |
232 | - for (SysCategory sysCategoryExcel : listSysCategorys) { | |
243 | + for (int i = 0; i < listSysCategorys.size(); i++) { | |
244 | + SysCategory sysCategoryExcel = listSysCategorys.get(i); | |
233 | 245 | String code = sysCategoryExcel.getCode(); |
234 | 246 | if(code.length()>3){ |
235 | 247 | String pCode = sysCategoryExcel.getCode().substring(0,code.length()-3); |
... | ... | @@ -242,12 +254,25 @@ public class SysCategoryController { |
242 | 254 | }else{ |
243 | 255 | sysCategoryExcel.setPid("0"); |
244 | 256 | } |
245 | - sysCategoryService.save(sysCategoryExcel); | |
257 | + try { | |
258 | + sysCategoryService.save(sysCategoryExcel); | |
259 | + successLines++; | |
260 | + } catch (Exception e) { | |
261 | + errorLines++; | |
262 | + String message = e.getMessage().toLowerCase(); | |
263 | + int lineNumber = i + 1; | |
264 | + // 通过索引名判断出错信息 | |
265 | + if (message.contains(CommonConstant.SQL_INDEX_UNIQ_CATEGORY_CODE)) { | |
266 | + errorMessage.add("第 " + lineNumber + " 行:分类编码已经存在,忽略导入。"); | |
267 | + } else { | |
268 | + errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入"); | |
269 | + log.error(e.getMessage(), e); | |
270 | + } | |
271 | + } | |
246 | 272 | } |
247 | - return Result.ok("文件导入成功!数据行数:" + listSysCategorys.size()); | |
248 | 273 | } catch (Exception e) { |
249 | - log.error(e.getMessage(), e); | |
250 | - return Result.error("文件导入失败:"+e.getMessage()); | |
274 | + errorMessage.add("发生异常:" + e.getMessage()); | |
275 | + log.error(e.getMessage(), e); | |
251 | 276 | } finally { |
252 | 277 | try { |
253 | 278 | file.getInputStream().close(); |
... | ... | @@ -256,7 +281,7 @@ public class SysCategoryController { |
256 | 281 | } |
257 | 282 | } |
258 | 283 | } |
259 | - return Result.error("文件导入失败!"); | |
284 | + return ImportExcelUtil.imporReturnRes(errorLines,successLines,errorMessage); | |
260 | 285 | } |
261 | 286 | |
262 | 287 | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java
... | ... | @@ -112,7 +112,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh |
112 | 112 | */ |
113 | 113 | @AutoLog(value = "编码校验规则-编辑") |
114 | 114 | @ApiOperation(value = "编码校验规则-编辑", notes = "编码校验规则-编辑") |
115 | - @PutMapping(value = "/edit") | |
115 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
116 | 116 | public Result edit(@RequestBody SysCheckRule sysCheckRule) { |
117 | 117 | sysCheckRuleService.updateById(sysCheckRule); |
118 | 118 | return Result.ok("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java
... | ... | @@ -14,6 +14,7 @@ import io.swagger.annotations.Api; |
14 | 14 | import io.swagger.annotations.ApiOperation; |
15 | 15 | import lombok.extern.slf4j.Slf4j; |
16 | 16 | import org.apache.commons.lang.StringUtils; |
17 | +import org.apache.shiro.authz.annotation.RequiresRoles; | |
17 | 18 | import org.jeecg.common.api.vo.Result; |
18 | 19 | import org.jeecg.common.aspect.annotation.AutoLog; |
19 | 20 | import org.jeecg.common.system.base.controller.JeecgController; |
... | ... | @@ -57,6 +58,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys |
57 | 58 | */ |
58 | 59 | @AutoLog(value = "多数据源管理-分页列表查询") |
59 | 60 | @ApiOperation(value = "多数据源管理-分页列表查询", notes = "多数据源管理-分页列表查询") |
61 | + //@RequiresRoles("admin") | |
60 | 62 | @GetMapping(value = "/list") |
61 | 63 | public Result<?> queryPageList( |
62 | 64 | SysDataSource sysDataSource, |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
... | ... | @@ -198,7 +198,7 @@ public class SysDepartController { |
198 | 198 | * @return |
199 | 199 | */ |
200 | 200 | //@RequiresRoles({"admin"}) |
201 | - @RequestMapping(value = "/edit", method = RequestMethod.PUT) | |
201 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
202 | 202 | @CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true) |
203 | 203 | public Result<SysDepart> edit(@RequestBody SysDepart sysDepart, HttpServletRequest request) { |
204 | 204 | String username = JwtUtil.getUserNameByToken(request); |
... | ... | @@ -322,7 +322,7 @@ public class SysDepartController { |
322 | 322 | if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){ |
323 | 323 | departIds = user.getDepartIds(); |
324 | 324 | } |
325 | - List<SysDepartTreeModel> treeList = this.sysDepartService.searhBy(keyWord,myDeptSearch,departIds); | |
325 | + List<SysDepartTreeModel> treeList = this.sysDepartService.searchByKeyWord(keyWord,myDeptSearch,departIds); | |
326 | 326 | if (treeList == null || treeList.size() == 0) { |
327 | 327 | result.setSuccess(false); |
328 | 328 | result.setMessage("未查询匹配数据!"); |
... | ... | @@ -363,6 +363,8 @@ public class SysDepartController { |
363 | 363 | |
364 | 364 | /** |
365 | 365 | * 通过excel导入数据 |
366 | + * 部门导入方案1: 通过机构编码来计算出部门的父级ID,维护上下级关系; | |
367 | + * 部门导入方案2: 你也可以改造下程序,机构编码直接导入,先不设置父ID;全部导入后,写一个sql,补下父ID; | |
366 | 368 | * |
367 | 369 | * @param request |
368 | 370 | * @param response |
... | ... | @@ -418,6 +420,11 @@ public class SysDepartController { |
418 | 420 | sysDepart.setOrgType(sysDepart.getOrgCode().length()/codeLength+""); |
419 | 421 | //update-end---author:liusq Date:20210223 for:批量导入部门以后,不能追加下一级部门 #2245------------ |
420 | 422 | sysDepart.setDelFlag(CommonConstant.DEL_FLAG_0.toString()); |
423 | + //update-begin---author:wangshuai ---date:20220105 for:[JTC-363]部门导入 机构类别没有时导入失败,赋默认值------------ | |
424 | + if(oConvertUtils.isEmpty(sysDepart.getOrgCategory())){ | |
425 | + sysDepart.setOrgCategory("1"); | |
426 | + } | |
427 | + //update-end---author:wangshuai ---date:20220105 for:[JTC-363]部门导入 机构类别没有时导入失败,赋默认值------------ | |
421 | 428 | ImportExcelUtil.importDateSaveOne(sysDepart, ISysDepartService.class, errorMessageList, num, CommonConstant.SQL_INDEX_UNIQ_DEPART_ORG_CODE); |
422 | 429 | num++; |
423 | 430 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
... | ... | @@ -97,7 +97,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm |
97 | 97 | * @return |
98 | 98 | */ |
99 | 99 | @ApiOperation(value="部门权限表-编辑", notes="部门权限表-编辑") |
100 | - @PutMapping(value = "/edit") | |
100 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
101 | 101 | public Result<?> edit(@RequestBody SysDepartPermission sysDepartPermission) { |
102 | 102 | sysDepartPermissionService.updateById(sysDepartPermission); |
103 | 103 | return Result.ok("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java
... | ... | @@ -114,7 +114,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys |
114 | 114 | */ |
115 | 115 | //@RequiresRoles({"admin"}) |
116 | 116 | @ApiOperation(value="部门角色-编辑", notes="部门角色-编辑") |
117 | - @PutMapping(value = "/edit") | |
117 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
118 | 118 | public Result<?> edit(@RequestBody SysDepartRole sysDepartRole) { |
119 | 119 | sysDepartRoleService.updateById(sysDepartRole); |
120 | 120 | return Result.ok("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
... | ... | @@ -496,7 +496,7 @@ public class SysDictController { |
496 | 496 | try { |
497 | 497 | //导入Excel格式校验,看匹配的字段文本概率 |
498 | 498 | Boolean t = ExcelImportCheckUtil.check(file.getInputStream(), SysDictPage.class, params); |
499 | - if(!t){ | |
499 | + if(t!=null && !t){ | |
500 | 500 | throw new RuntimeException("导入Excel校验失败 !"); |
501 | 501 | } |
502 | 502 | List<SysDictPage> list = ExcelImportUtil.importExcel(file.getInputStream(), SysDictPage.class, params); |
... | ... | @@ -511,11 +511,22 @@ public class SysDictController { |
511 | 511 | Integer integer = sysDictService.saveMain(po, list.get(i).getSysDictItemList()); |
512 | 512 | if(integer>0){ |
513 | 513 | successLines++; |
514 | - }else{ | |
514 | + //update-begin---author:wangshuai ---date:20220211 for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------ | |
515 | + }else if(integer == -1){ | |
516 | + errorLines++; | |
517 | + errorMessage.add("字典名称:" + po.getDictName() + ",对应字典列表的字典项值不能为空,忽略导入。"); | |
518 | + }else{ | |
519 | + //update-end---author:wangshuai ---date:20220211 for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------ | |
515 | 520 | errorLines++; |
516 | 521 | int lineNumber = i + 1; |
517 | - errorMessage.add("第 " + lineNumber + " 行:字典编码已经存在,忽略导入。"); | |
518 | - } | |
522 | + //update-begin---author:wangshuai ---date:20220209 for:[JTC-1168]字典编号不能为空------------ | |
523 | + if(oConvertUtils.isEmpty(po.getDictCode())){ | |
524 | + errorMessage.add("第 " + lineNumber + " 行:字典编码不能为空,忽略导入。"); | |
525 | + }else{ | |
526 | + errorMessage.add("第 " + lineNumber + " 行:字典编码已经存在,忽略导入。"); | |
527 | + } | |
528 | + //update-end---author:wangshuai ---date:20220209 for:[JTC-1168]字典编号不能为空------------ | |
529 | + } | |
519 | 530 | } catch (Exception e) { |
520 | 531 | errorLines++; |
521 | 532 | int lineNumber = i + 1; |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java
... | ... | @@ -93,7 +93,7 @@ public class SysFillRuleController extends JeecgController<SysFillRule, ISysFill |
93 | 93 | */ |
94 | 94 | @AutoLog(value = "填值规则-编辑") |
95 | 95 | @ApiOperation(value = "填值规则-编辑", notes = "填值规则-编辑") |
96 | - @PutMapping(value = "/edit") | |
96 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
97 | 97 | public Result<?> edit(@RequestBody SysFillRule sysFillRule) { |
98 | 98 | sysFillRuleService.updateById(sysFillRule); |
99 | 99 | return Result.ok("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
... | ... | @@ -59,7 +59,7 @@ public class SysPermissionController { |
59 | 59 | |
60 | 60 | /** |
61 | 61 | * 加载数据节点 |
62 | - * | |
62 | + * | |
63 | 63 | * @return |
64 | 64 | */ |
65 | 65 | @RequestMapping(value = "/list", method = RequestMethod.GET) |
... | ... | @@ -200,7 +200,7 @@ public class SysPermissionController { |
200 | 200 | |
201 | 201 | /** |
202 | 202 | * 查询用户拥有的菜单权限和按钮权限 |
203 | - * | |
203 | + * | |
204 | 204 | * @return |
205 | 205 | */ |
206 | 206 | @RequestMapping(value = "/getUserPermissionByToken", method = RequestMethod.GET) |
... | ... | @@ -261,32 +261,49 @@ public class SysPermissionController { |
261 | 261 | } |
262 | 262 | |
263 | 263 | /** |
264 | - * 【vue3专用】查询用户拥有的按钮/表单访问权限 | |
265 | - * @return | |
264 | + * 【vue3专用】获取 | |
265 | + * 1、查询用户拥有的按钮/表单访问权限 | |
266 | + * 2、所有权限 (菜单权限配置) | |
267 | + * 3、系统安全模式 (开启则online报表的数据源必填) | |
266 | 268 | */ |
267 | 269 | @RequestMapping(value = "/getPermCode", method = RequestMethod.GET) |
268 | 270 | public Result<?> getPermCode() { |
269 | - Result<List<String>> result = new Result<List<String>>(); | |
270 | 271 | try { |
271 | - //直接获取当前用户 | |
272 | + // 直接获取当前用户 | |
272 | 273 | LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); |
273 | - //获取当前用户的权限集合 | |
274 | + if (oConvertUtils.isEmpty(loginUser)) { | |
275 | + return Result.error("请登录系统!"); | |
276 | + } | |
277 | + // 获取当前用户的权限集合 | |
274 | 278 | List<SysPermission> metaList = sysPermissionService.queryByUser(loginUser.getUsername()); |
279 | + // 按钮权限(用户拥有的权限集合) | |
280 | + List<String> codeList = metaList.stream() | |
281 | + .filter((permission) -> CommonConstant.MENU_TYPE_2.equals(permission.getMenuType()) && CommonConstant.STATUS_1.equals(permission.getStatus())) | |
282 | + .collect(ArrayList::new, (list, permission) -> list.add(permission.getPerms()), ArrayList::addAll); | |
283 | + // | |
284 | + JSONArray authArray = new JSONArray(); | |
285 | + this.getAuthJsonArray(authArray, metaList); | |
286 | + // 查询所有的权限 | |
287 | + LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<>(); | |
288 | + query.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0); | |
289 | + query.eq(SysPermission::getMenuType, CommonConstant.MENU_TYPE_2); | |
290 | + List<SysPermission> allAuthList = sysPermissionService.list(query); | |
291 | + JSONArray allAuthArray = new JSONArray(); | |
292 | + this.getAllAuthJsonArray(allAuthArray, allAuthList); | |
293 | + JSONObject result = new JSONObject(); | |
294 | + // 所拥有的权限编码 | |
295 | + result.put("codeList", codeList); | |
275 | 296 | //按钮权限(用户拥有的权限集合) |
276 | - List<String> authList = metaList.stream() | |
277 | - .filter((permission) -> permission.getMenuType().equals(CommonConstant.MENU_TYPE_2) | |
278 | - && CommonConstant.STATUS_1.equals(permission.getStatus()) | |
279 | - ) | |
280 | - .collect(() -> new ArrayList<String>(), | |
281 | - (list, permission) -> list.add(permission.getPerms()), | |
282 | - (list1, list2) -> list1.addAll(list2) | |
283 | - ); | |
284 | - result.setResult(authList); | |
297 | + result.put("auth", authArray); | |
298 | + //全部权限配置集合(按钮权限,访问权限) | |
299 | + result.put("allAuth", allAuthArray); | |
300 | + // 系统安全模式 | |
301 | + result.put("sysSafeMode", jeeccgBaseConfig.getSafeMode()); | |
302 | + return Result.OK(result); | |
285 | 303 | } catch (Exception e) { |
286 | - result.error500("查询失败:" + e.getMessage()); | |
287 | 304 | log.error(e.getMessage(), e); |
305 | + return Result.error("查询失败:" + e.getMessage()); | |
288 | 306 | } |
289 | - return result; | |
290 | 307 | } |
291 | 308 | |
292 | 309 | /** |
... | ... | @@ -374,7 +391,7 @@ public class SysPermissionController { |
374 | 391 | |
375 | 392 | /** |
376 | 393 | * 获取全部的权限树 |
377 | - * | |
394 | + * | |
378 | 395 | * @return |
379 | 396 | */ |
380 | 397 | @RequestMapping(value = "/queryTreeList", method = RequestMethod.GET) |
... | ... | @@ -720,7 +737,7 @@ public class SysPermissionController { |
720 | 737 | /** |
721 | 738 | * 判断是否外网URL 例如: http://localhost:8080/jeecg-boot/swagger-ui.html#/ 支持特殊格式: {{ |
722 | 739 | * window._CONFIG['domianURL'] }}/druid/ {{ JS代码片段 }},前台解析会自动执行JS代码片段 |
723 | - * | |
740 | + * | |
724 | 741 | * @return |
725 | 742 | */ |
726 | 743 | private boolean isWWWHttpUrl(String url) { |
... | ... | @@ -733,7 +750,7 @@ public class SysPermissionController { |
733 | 750 | /** |
734 | 751 | * 通过URL生成路由name(去掉URL前缀斜杠,替换内容中的斜杠‘/’为-) 举例: URL = /isystem/role RouteName = |
735 | 752 | * isystem-role |
736 | - * | |
753 | + * | |
737 | 754 | * @return |
738 | 755 | */ |
739 | 756 | private String urlToRouteName(String url) { |
... | ... | @@ -753,7 +770,7 @@ public class SysPermissionController { |
753 | 770 | |
754 | 771 | /** |
755 | 772 | * 根据菜单id来获取其对应的权限数据 |
756 | - * | |
773 | + * | |
757 | 774 | * @param sysPermissionDataRule |
758 | 775 | * @return |
759 | 776 | */ |
... | ... | @@ -768,7 +785,7 @@ public class SysPermissionController { |
768 | 785 | |
769 | 786 | /** |
770 | 787 | * 添加菜单权限数据 |
771 | - * | |
788 | + * | |
772 | 789 | * @param sysPermissionDataRule |
773 | 790 | * @return |
774 | 791 | */ |
... | ... | @@ -803,7 +820,7 @@ public class SysPermissionController { |
803 | 820 | |
804 | 821 | /** |
805 | 822 | * 删除菜单权限数据 |
806 | - * | |
823 | + * | |
807 | 824 | * @param id |
808 | 825 | * @return |
809 | 826 | */ |
... | ... | @@ -823,7 +840,7 @@ public class SysPermissionController { |
823 | 840 | |
824 | 841 | /** |
825 | 842 | * 查询菜单权限数据 |
826 | - * | |
843 | + * | |
827 | 844 | * @param sysPermissionDataRule |
828 | 845 | * @return |
829 | 846 | */ |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java
... | ... | @@ -8,10 +8,12 @@ import io.swagger.annotations.Api; |
8 | 8 | import io.swagger.annotations.ApiOperation; |
9 | 9 | import lombok.extern.slf4j.Slf4j; |
10 | 10 | import org.apache.poi.ss.formula.functions.T; |
11 | +import org.apache.shiro.SecurityUtils; | |
11 | 12 | import org.jeecg.common.api.vo.Result; |
12 | 13 | import org.jeecg.common.aspect.annotation.AutoLog; |
13 | 14 | import org.jeecg.common.constant.CommonConstant; |
14 | 15 | import org.jeecg.common.system.query.QueryGenerator; |
16 | +import org.jeecg.common.system.vo.LoginUser; | |
15 | 17 | import org.jeecg.common.util.ImportExcelUtil; |
16 | 18 | import org.jeecg.common.util.oConvertUtils; |
17 | 19 | import org.jeecg.modules.quartz.service.IQuartzJobService; |
... | ... | @@ -208,10 +210,11 @@ public class SysPositionController { |
208 | 210 | //Step.2 AutoPoi 导出Excel |
209 | 211 | ModelAndView mv = new ModelAndView(new JeecgEntityExcelView()); |
210 | 212 | List<SysPosition> pageList = sysPositionService.list(queryWrapper); |
213 | + LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal(); | |
211 | 214 | //导出文件名称 |
212 | 215 | mv.addObject(NormalExcelConstants.FILE_NAME, "职务表列表"); |
213 | 216 | mv.addObject(NormalExcelConstants.CLASS, SysPosition.class); |
214 | - mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("职务表列表数据", "导出人:Jeecg", "导出信息")); | |
217 | + mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("职务表列表数据", "导出人:"+user.getRealname(),"导出信息")); | |
215 | 218 | mv.addObject(NormalExcelConstants.DATA_LIST, pageList); |
216 | 219 | return mv; |
217 | 220 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
... | ... | @@ -6,9 +6,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
6 | 6 | import com.baomidou.mybatisplus.core.metadata.IPage; |
7 | 7 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
8 | 8 | import lombok.extern.slf4j.Slf4j; |
9 | +import org.apache.shiro.SecurityUtils; | |
9 | 10 | import org.jeecg.common.api.vo.Result; |
10 | 11 | import org.jeecg.common.aspect.annotation.PermissionData; |
11 | 12 | import org.jeecg.common.system.query.QueryGenerator; |
13 | +import org.jeecg.common.system.vo.LoginUser; | |
12 | 14 | import org.jeecg.common.util.oConvertUtils; |
13 | 15 | import org.jeecg.modules.system.entity.SysTenant; |
14 | 16 | import org.jeecg.modules.system.service.ISysTenantService; |
... | ... | @@ -16,9 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired; |
16 | 18 | import org.springframework.web.bind.annotation.*; |
17 | 19 | |
18 | 20 | import javax.servlet.http.HttpServletRequest; |
19 | -import java.util.ArrayList; | |
20 | -import java.util.Date; | |
21 | -import java.util.List; | |
21 | +import java.util.*; | |
22 | 22 | |
23 | 23 | /** |
24 | 24 | * 租户配置信息 |
... | ... | @@ -132,11 +132,11 @@ public class SysTenantController { |
132 | 132 | }else { |
133 | 133 | String[] ls = ids.split(","); |
134 | 134 | // 过滤掉已被引用的租户 |
135 | - List<String> idList = new ArrayList<>(); | |
135 | + List<Integer> idList = new ArrayList<>(); | |
136 | 136 | for (String id : ls) { |
137 | 137 | int userCount = sysTenantService.countUserLinkTenant(id); |
138 | 138 | if (userCount == 0) { |
139 | - idList.add(id); | |
139 | + idList.add(Integer.parseInt(id)); | |
140 | 140 | } |
141 | 141 | } |
142 | 142 | if (idList.size() > 0) { |
... | ... | @@ -190,4 +190,32 @@ public class SysTenantController { |
190 | 190 | result.setResult(ls); |
191 | 191 | return result; |
192 | 192 | } |
193 | + /** | |
194 | + * 查询当前用户的所有有效租户 【当前用于vue3版本】 | |
195 | + * @return | |
196 | + */ | |
197 | + @RequestMapping(value = "/getCurrentUserTenant", method = RequestMethod.GET) | |
198 | + public Result<Map<String,Object>> getCurrentUserTenant() { | |
199 | + Result<Map<String,Object>> result = new Result<Map<String,Object>>(); | |
200 | + try { | |
201 | + LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); | |
202 | + String tenantIds = sysUser.getRelTenantIds(); | |
203 | + Map<String,Object> map = new HashMap<String,Object>(); | |
204 | + if (oConvertUtils.isNotEmpty(tenantIds)) { | |
205 | + List<Integer> tenantIdList = new ArrayList<>(); | |
206 | + for(String id: tenantIds.split(",")){ | |
207 | + tenantIdList.add(Integer.valueOf(id)); | |
208 | + } | |
209 | + // 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。 | |
210 | + List<SysTenant> tenantList = sysTenantService.queryEffectiveTenant(tenantIdList); | |
211 | + map.put("list", tenantList); | |
212 | + } | |
213 | + result.setSuccess(true); | |
214 | + result.setResult(map); | |
215 | + }catch(Exception e) { | |
216 | + log.error(e.getMessage(), e); | |
217 | + result.error500("查询失败!"); | |
218 | + } | |
219 | + return result; | |
220 | + } | |
193 | 221 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
... | ... | @@ -108,12 +108,38 @@ public class SysUserController { |
108 | 108 | @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req) { |
109 | 109 | Result<IPage<SysUser>> result = new Result<IPage<SysUser>>(); |
110 | 110 | QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(user, req.getParameterMap()); |
111 | - //TODO 外部模拟登陆临时账号,列表不显示 | |
111 | + | |
112 | + //update-begin-Author:wangshuai--Date:20211119--for:【vue3】通过部门id查询用户,通过code查询id | |
113 | + //部门ID | |
114 | + String departId = req.getParameter("departId"); | |
115 | + if(oConvertUtils.isNotEmpty(departId)){ | |
116 | + LambdaQueryWrapper<SysUserDepart> query = new LambdaQueryWrapper<>(); | |
117 | + query.eq(SysUserDepart::getDepId,departId); | |
118 | + List<SysUserDepart> list = sysUserDepartService.list(query); | |
119 | + List<String> userIds = list.stream().map(SysUserDepart::getUserId).collect(Collectors.toList()); | |
120 | + queryWrapper.in("id",userIds); | |
121 | + } | |
122 | + //用户ID | |
123 | + String code = req.getParameter("code"); | |
124 | + if(oConvertUtils.isNotEmpty(code)){ | |
125 | + queryWrapper.in("id",Arrays.asList(code.split(","))); | |
126 | + pageSize = code.split(",").length; | |
127 | + } | |
128 | + //update-end-Author:wangshuai--Date:20211119--for:【vue3】通过部门id查询用户,通过code查询id | |
129 | + | |
130 | + //update-begin-author:taoyan--date:20220104--for: JTC-372 【用户冻结问题】 online授权、用户组件,选择用户都能看到被冻结的用户 | |
131 | + String status = req.getParameter("status"); | |
132 | + if(oConvertUtils.isNotEmpty(status)){ | |
133 | + queryWrapper.eq("status", Integer.parseInt(status)); | |
134 | + } | |
135 | + //update-end-author:taoyan--date:20220104--for: JTC-372 【用户冻结问题】 online授权、用户组件,选择用户都能看到被冻结的用户 | |
136 | + | |
137 | + //TODO 外部模拟登陆临时账号,列表不显示 | |
112 | 138 | queryWrapper.ne("username","_reserve_user_external"); |
113 | 139 | Page<SysUser> page = new Page<SysUser>(pageNo, pageSize); |
114 | 140 | IPage<SysUser> pageList = sysUserService.page(page, queryWrapper); |
115 | 141 | |
116 | - //批量查询用户的所属部门 | |
142 | + //批量查询用户的所属部门 | |
117 | 143 | //step.1 先拿到全部的 useids |
118 | 144 | //step.2 通过 useids,一次性查询用户的所属部门名字 |
119 | 145 | List<String> userIds = pageList.getRecords().stream().map(SysUser::getId).collect(Collectors.toList()); |
... | ... | @@ -492,6 +518,8 @@ public class SysUserController { |
492 | 518 | errorMessage.add("第 " + lineNumber + " 行:手机号已经存在,忽略导入。"); |
493 | 519 | } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_EMAIL)) { |
494 | 520 | errorMessage.add("第 " + lineNumber + " 行:电子邮件已经存在,忽略导入。"); |
521 | + } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER)) { | |
522 | + errorMessage.add("第 " + lineNumber + " 行:违反表唯一性约束。"); | |
495 | 523 | } else { |
496 | 524 | errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入"); |
497 | 525 | log.error(e.getMessage(), e); |
... | ... | @@ -1187,7 +1215,7 @@ public class SysUserController { |
1187 | 1215 | * @param jsonObject |
1188 | 1216 | * @return |
1189 | 1217 | */ |
1190 | - @RequestMapping(value = "/appEdit", method = RequestMethod.PUT) | |
1218 | + @RequestMapping(value = "/appEdit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
1191 | 1219 | public Result<SysUser> appEdit(HttpServletRequest request,@RequestBody JSONObject jsonObject) { |
1192 | 1220 | Result<SysUser> result = new Result<SysUser>(); |
1193 | 1221 | try { |
... | ... | @@ -1305,7 +1333,9 @@ public class SysUserController { |
1305 | 1333 | * @return |
1306 | 1334 | */ |
1307 | 1335 | @GetMapping("/appQueryUser") |
1308 | - public Result<List<SysUser>> appQueryUser(@RequestParam(name = "keyword", required = false) String keyword) { | |
1336 | + public Result<List<SysUser>> appQueryUser(@RequestParam(name = "keyword", required = false) String keyword, | |
1337 | + @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, | |
1338 | + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) { | |
1309 | 1339 | Result<List<SysUser>> result = new Result<List<SysUser>>(); |
1310 | 1340 | LambdaQueryWrapper<SysUser> queryWrapper =new LambdaQueryWrapper<SysUser>(); |
1311 | 1341 | //TODO 外部模拟登陆临时账号,列表不显示 |
... | ... | @@ -1313,18 +1343,19 @@ public class SysUserController { |
1313 | 1343 | if(StringUtils.isNotBlank(keyword)){ |
1314 | 1344 | queryWrapper.and(i -> i.like(SysUser::getUsername, keyword).or().like(SysUser::getRealname, keyword)); |
1315 | 1345 | } |
1316 | - List<SysUser> list = sysUserService.list(queryWrapper); | |
1346 | + Page<SysUser> page = new Page<>(pageNo, pageSize); | |
1347 | + IPage<SysUser> pageList = this.sysUserService.page(page, queryWrapper); | |
1317 | 1348 | //批量查询用户的所属部门 |
1318 | 1349 | //step.1 先拿到全部的 useids |
1319 | 1350 | //step.2 通过 useids,一次性查询用户的所属部门名字 |
1320 | - List<String> userIds = list.stream().map(SysUser::getId).collect(Collectors.toList()); | |
1351 | + List<String> userIds = pageList.getRecords().stream().map(SysUser::getId).collect(Collectors.toList()); | |
1321 | 1352 | if(userIds!=null && userIds.size()>0){ |
1322 | 1353 | Map<String,String> useDepNames = sysUserService.getDepNamesByUserIds(userIds); |
1323 | - list.forEach(item->{ | |
1354 | + pageList.getRecords().forEach(item->{ | |
1324 | 1355 | item.setOrgCodeTxt(useDepNames.get(item.getId())); |
1325 | 1356 | }); |
1326 | 1357 | } |
1327 | - result.setResult(list); | |
1358 | + result.setResult(pageList.getRecords()); | |
1328 | 1359 | return result; |
1329 | 1360 | } |
1330 | 1361 | |
... | ... | @@ -1374,6 +1405,9 @@ public class SysUserController { |
1374 | 1405 | @GetMapping("/getMultiUser") |
1375 | 1406 | public List<SysUser> getMultiUser(SysUser sysUser){ |
1376 | 1407 | QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(sysUser, null); |
1408 | + //update-begin---author:wangshuai ---date:20220104 for:[JTC-297]已冻结用户仍可设置为代理人------------ | |
1409 | + queryWrapper.eq("status",Integer.parseInt(CommonConstant.STATUS_1)); | |
1410 | + //update-end---author:wangshuai ---date:20220104 for:[JTC-297]已冻结用户仍可设置为代理人------------ | |
1377 | 1411 | List<SysUser> ls = this.sysUserService.list(queryWrapper); |
1378 | 1412 | for(SysUser user: ls){ |
1379 | 1413 | user.setPassword(null); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java
1 | 1 | package org.jeecg.modules.system.controller; |
2 | 2 | |
3 | -import java.util.*; | |
4 | - | |
5 | -import javax.annotation.Resource; | |
3 | +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |
4 | +import lombok.extern.slf4j.Slf4j; | |
6 | 5 | import org.apache.commons.lang.StringUtils; |
7 | 6 | import org.apache.shiro.SecurityUtils; |
8 | 7 | import org.jeecg.common.api.vo.Result; |
... | ... | @@ -21,9 +20,11 @@ import org.springframework.beans.factory.annotation.Autowired; |
21 | 20 | import org.springframework.data.redis.core.RedisTemplate; |
22 | 21 | import org.springframework.web.bind.annotation.*; |
23 | 22 | |
24 | -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |
25 | - | |
26 | -import lombok.extern.slf4j.Slf4j; | |
23 | +import javax.annotation.Resource; | |
24 | +import java.util.ArrayList; | |
25 | +import java.util.Collection; | |
26 | +import java.util.Collections; | |
27 | +import java.util.List; | |
27 | 28 | |
28 | 29 | /** |
29 | 30 | * @Description: 在线用户 |
... | ... | @@ -63,8 +64,20 @@ public class SysUserOnlineController { |
63 | 64 | online.setToken(token); |
64 | 65 | //TODO 改成一次性查询 |
65 | 66 | LoginUser loginUser = sysBaseAPI.getUserByName(JwtUtil.getUsername(token)); |
66 | - BeanUtils.copyProperties(loginUser, online); | |
67 | - onlineList.add(online); | |
67 | + if (loginUser != null) { | |
68 | + //update-begin---author:wangshuai ---date:20220104 for:[JTC-382]在线用户查询无效------------ | |
69 | + //验证用户名是否与传过来的用户名相同 | |
70 | + boolean isMatchUsername=true; | |
71 | + //判断用户名是否为空,并且当前循环的用户不包含传过来的用户名,那么就设成false | |
72 | + if(oConvertUtils.isNotEmpty(username) && !loginUser.getUsername().contains(username)){ | |
73 | + isMatchUsername = false; | |
74 | + } | |
75 | + if(isMatchUsername){ | |
76 | + BeanUtils.copyProperties(loginUser, online); | |
77 | + onlineList.add(online); | |
78 | + } | |
79 | + //update-end---author:wangshuai ---date:20220104 for:[JTC-382]在线用户查询无效------------ | |
80 | + } | |
68 | 81 | } |
69 | 82 | } |
70 | 83 | Collections.reverse(onlineList); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
... | ... | @@ -91,8 +91,12 @@ public class ThirdAppController { |
91 | 91 | @GetMapping("/sync/wechatEnterprise/depart/toApp") |
92 | 92 | public Result syncWechatEnterpriseDepartToApp(@RequestParam(value = "ids", required = false) String ids) { |
93 | 93 | if (thirdAppConfig.isWechatEnterpriseEnabled()) { |
94 | - boolean flag = wechatEnterpriseService.syncLocalDepartmentToThirdApp(ids); | |
95 | - return flag ? Result.OK("同步成功", null) : Result.error("同步失败"); | |
94 | + SyncInfoVo syncInfo = wechatEnterpriseService.syncLocalDepartmentToThirdApp(ids); | |
95 | + if (syncInfo.getFailInfo().size() == 0) { | |
96 | + return Result.OK("同步成功", null); | |
97 | + } else { | |
98 | + return Result.error("同步失败", syncInfo); | |
99 | + } | |
96 | 100 | } |
97 | 101 | return Result.error("企业微信同步功能已禁用"); |
98 | 102 | } |
... | ... | @@ -125,8 +129,12 @@ public class ThirdAppController { |
125 | 129 | @GetMapping("/sync/dingtalk/depart/toApp") |
126 | 130 | public Result syncDingtalkDepartToApp(@RequestParam(value = "ids", required = false) String ids) { |
127 | 131 | if (thirdAppConfig.isDingtalkEnabled()) { |
128 | - boolean flag = dingtalkService.syncLocalDepartmentToThirdApp(ids); | |
129 | - return flag ? Result.OK("同步成功", null) : Result.error("同步失败"); | |
132 | + SyncInfoVo syncInfo = dingtalkService.syncLocalDepartmentToThirdApp(ids); | |
133 | + if (syncInfo.getFailInfo().size() == 0) { | |
134 | + return Result.OK("同步成功", null); | |
135 | + } else { | |
136 | + return Result.error("同步失败", syncInfo); | |
137 | + } | |
130 | 138 | } |
131 | 139 | return Result.error("钉钉同步功能已禁用"); |
132 | 140 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepart.java
... | ... | @@ -45,7 +45,7 @@ public class SysDepart implements Serializable { |
45 | 45 | /**描述*/ |
46 | 46 | @Excel(name="描述",width=15) |
47 | 47 | private String description; |
48 | - /**机构类别 1公司,2组织机构,2岗位*/ | |
48 | + /**机构类别 1=公司,2=组织机构,3=岗位*/ | |
49 | 49 | @Excel(name="机构类别",width=15,dicCode="org_category") |
50 | 50 | private String orgCategory; |
51 | 51 | /**机构类型*/ |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysPosition.java
... | ... | @@ -54,7 +54,6 @@ public class SysPosition { |
54 | 54 | /** |
55 | 55 | * 公司id |
56 | 56 | */ |
57 | - @Excel(name = "公司id", width = 15) | |
58 | 57 | @ApiModelProperty(value = "公司id") |
59 | 58 | private java.lang.String companyId; |
60 | 59 | /** |
... | ... | @@ -84,7 +83,6 @@ public class SysPosition { |
84 | 83 | /** |
85 | 84 | * 组织机构编码 |
86 | 85 | */ |
87 | - @Excel(name = "组织机构编码", width = 15) | |
88 | 86 | @ApiModelProperty(value = "组织机构编码") |
89 | 87 | private java.lang.String sysOrgCode; |
90 | 88 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java
... | ... | @@ -3,12 +3,14 @@ package org.jeecg.modules.system.entity; |
3 | 3 | import com.baomidou.mybatisplus.annotation.IdType; |
4 | 4 | import com.baomidou.mybatisplus.annotation.TableId; |
5 | 5 | import com.baomidou.mybatisplus.annotation.TableName; |
6 | +import com.fasterxml.jackson.annotation.JsonFormat; | |
6 | 7 | import io.swagger.annotations.ApiModel; |
7 | 8 | import io.swagger.annotations.ApiModelProperty; |
8 | 9 | import lombok.Data; |
9 | 10 | import lombok.EqualsAndHashCode; |
10 | 11 | import lombok.experimental.Accessors; |
11 | 12 | import org.jeecgframework.poi.excel.annotation.Excel; |
13 | +import org.springframework.format.annotation.DateTimeFormat; | |
12 | 14 | |
13 | 15 | /** |
14 | 16 | * @Description: 第三方登录账号表 |
... | ... | @@ -25,7 +27,7 @@ public class SysThirdAccount { |
25 | 27 | |
26 | 28 | /**编号*/ |
27 | 29 | @TableId(type = IdType.ASSIGN_ID) |
28 | - @ApiModelProperty(value = "编号") | |
30 | + @ApiModelProperty(value = "编号") | |
29 | 31 | private java.lang.String id; |
30 | 32 | /**第三方登录id*/ |
31 | 33 | @Excel(name = "第三方登录id", width = 15) |
... | ... | @@ -59,4 +61,20 @@ public class SysThirdAccount { |
59 | 61 | @Excel(name = "第三方用户账号", width = 15) |
60 | 62 | @ApiModelProperty(value = "第三方用户账号") |
61 | 63 | private java.lang.String thirdUserId; |
64 | + /**创建人*/ | |
65 | + @Excel(name = "创建人", width = 15) | |
66 | + private java.lang.String createBy; | |
67 | + /**创建日期*/ | |
68 | + @Excel(name = "创建日期", width = 20, format = "yyyy-MM-dd HH:mm:ss") | |
69 | + @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss") | |
70 | + @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") | |
71 | + private java.util.Date createTime; | |
72 | + /**修改人*/ | |
73 | + @Excel(name = "修改人", width = 15) | |
74 | + private java.lang.String updateBy; | |
75 | + /**修改日期*/ | |
76 | + @Excel(name = "修改日期", width = 20, format = "yyyy-MM-dd HH:mm:ss") | |
77 | + @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss") | |
78 | + @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") | |
79 | + private java.util.Date updateTime; | |
62 | 80 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
... | ... | @@ -193,4 +193,15 @@ public interface SysDictMapper extends BaseMapper<SysDict> { |
193 | 193 | */ |
194 | 194 | @Deprecated |
195 | 195 | List<DictModel> queryAllTableDictItems(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql); |
196 | + | |
197 | + /** | |
198 | + * 查询字典表的数据 | |
199 | + * @param table 表名 | |
200 | + * @param text 显示字段名 | |
201 | + * @param code 存储字段名 | |
202 | + * @param filterSql 条件sql | |
203 | + * @param codeValues 存储字段值 作为查询条件in | |
204 | + * @return | |
205 | + */ | |
206 | + List<DictModel> queryTableDictByKeysAndFilterSql(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql, @Param("codeValues") List<String> codeValues); | |
196 | 207 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
... | ... | @@ -134,19 +134,24 @@ |
134 | 134 | ${pidField} as parentId |
135 | 135 | from ${table} |
136 | 136 | where |
137 | - <choose> | |
138 | - <when test="pid != null and pid != ''"> | |
139 | - ${pidField} = #{pid} | |
140 | - </when> | |
141 | - <otherwise> | |
142 | - (${pidField} = '' OR ${pidField} IS NULL) | |
143 | - </otherwise> | |
144 | - </choose> | |
137 | + <!-- udapte-begin-author:sunjianlei date:20220110 for: 【JTC-597】自定义树查询条件查不出数据 --> | |
138 | + <if test="query == null"> | |
139 | + <choose> | |
140 | + <when test="pid != null and pid != ''"> | |
141 | + ${pidField} = #{pid} | |
142 | + </when> | |
143 | + <otherwise> | |
144 | + (${pidField} = '' OR ${pidField} IS NULL) | |
145 | + </otherwise> | |
146 | + </choose> | |
147 | + </if> | |
145 | 148 | <if test="query!= null"> |
149 | + 1 = 1 | |
146 | 150 | <foreach collection="query.entrySet()" item="value" index="key" > |
147 | - and ${key} = #{value} | |
151 | + and ${key} LIKE #{value} | |
148 | 152 | </foreach> |
149 | 153 | </if> |
154 | + <!-- udapte-end-author:sunjianlei date:20220110 for: 【JTC-597】自定义树查询条件查不出数据 --> | |
150 | 155 | </select> |
151 | 156 | |
152 | 157 | |
... | ... | @@ -179,5 +184,18 @@ |
179 | 184 | </select> |
180 | 185 | |
181 | 186 | |
187 | + <!-- 查询字典表的数据 支持设置过滤条件、设置存储值作为in查询条件 --> | |
188 | + <select id="queryTableDictByKeysAndFilterSql" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel"> | |
189 | + select ${text} as "text", ${code} as "value" from ${table} where ${code} IN ( | |
190 | + <foreach item="key" collection="codeValues" separator=","> | |
191 | + #{key} | |
192 | + </foreach> | |
193 | + ) | |
194 | + <if test="filterSql != null and filterSql != ''"> | |
195 | + and ${filterSql} | |
196 | + </if> | |
197 | + </select> | |
198 | + | |
199 | + | |
182 | 200 | |
183 | 201 | </mapper> |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserDepartMapper.xml
... | ... | @@ -14,7 +14,9 @@ |
14 | 14 | join sys_depart c on b.dep_id = c.id |
15 | 15 | where a.del_flag = 0 and c.org_code like '${orgCode}%' |
16 | 16 | <if test="realname!=null and realname!=''"> |
17 | - and a.realname like '%${realname}%' | |
17 | + <!-- update by sunjianlei 20220119【#3348】SQL injection exists in /sys/user/queryUserByDepId; --> | |
18 | + <bind name="bindRealname" value="'%'+realname+'%'"/> | |
19 | + and a.realname like #{bindRealname} | |
18 | 20 | </if> |
19 | 21 | </select> |
20 | 22 | |
... | ... | @@ -23,12 +25,14 @@ |
23 | 25 | select a.*, c.depart_name as org_code_txt from sys_user a |
24 | 26 | join sys_user_depart b on b.user_id = a.id |
25 | 27 | join sys_depart c on b.dep_id = c.id |
26 | - where a.del_flag = 0 and c.org_code like '${orgCode}%' | |
28 | + where a.del_flag = 0 and a.status = 1 and c.org_code like '${orgCode}%' | |
27 | 29 | <if test="username!=null and username!=''"> |
28 | - and a.username like '%${username}%' | |
30 | + <bind name="bindUsername" value="'%'+username+'%'"/> | |
31 | + and a.username like #{bindUsername} | |
29 | 32 | </if> |
30 | 33 | <if test="realname!=null and realname!=''"> |
31 | - and a.realname like '%${realname}%' | |
34 | + <bind name="bindRealname" value="'%'+realname+'%'"/> | |
35 | + and a.realname like #{bindRealname} | |
32 | 36 | </if> |
33 | 37 | </select> |
34 | 38 | </mapper> |
35 | 39 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/AnnouncementSendModel.java
1 | 1 | package org.jeecg.modules.system.model; |
2 | 2 | |
3 | -import java.io.Serializable; | |
4 | - | |
5 | -import org.springframework.format.annotation.DateTimeFormat; | |
6 | - | |
7 | 3 | import com.baomidou.mybatisplus.annotation.IdType; |
8 | 4 | import com.baomidou.mybatisplus.annotation.TableId; |
9 | -import com.baomidou.mybatisplus.annotation.TableName; | |
10 | 5 | import com.fasterxml.jackson.annotation.JsonFormat; |
11 | - | |
12 | 6 | import lombok.Data; |
7 | +import org.springframework.format.annotation.DateTimeFormat; | |
8 | + | |
9 | +import java.io.Serializable; | |
13 | 10 | |
14 | 11 | /** |
15 | 12 | * @Description: 用户通告阅读标记表 |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/rule/CategoryCodeRule.java
... | ... | @@ -2,6 +2,7 @@ package org.jeecg.modules.system.rule; |
2 | 2 | |
3 | 3 | import com.alibaba.fastjson.JSONObject; |
4 | 4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
5 | +import lombok.extern.slf4j.Slf4j; | |
5 | 6 | import org.jeecg.common.handler.IFillRuleHandler; |
6 | 7 | import org.jeecg.common.util.SpringContextUtils; |
7 | 8 | import org.jeecg.common.util.YouBianCodeUtil; |
... | ... | @@ -16,12 +17,14 @@ import java.util.List; |
16 | 17 | * @Date 2019/12/9 11:32 |
17 | 18 | * @Description: 分类字典编码生成规则 |
18 | 19 | */ |
20 | +@Slf4j | |
19 | 21 | public class CategoryCodeRule implements IFillRuleHandler { |
20 | 22 | |
21 | 23 | public static final String ROOT_PID_VALUE = "0"; |
22 | 24 | |
23 | 25 | @Override |
24 | 26 | public Object execute(JSONObject params, JSONObject formData) { |
27 | + log.info("系统自定义编码规则[category_code_rule],params:{} ,formData: {}", params, formData); | |
25 | 28 | |
26 | 29 | String categoryPid = ROOT_PID_VALUE; |
27 | 30 | String categoryCode = null; |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
... | ... | @@ -67,7 +67,7 @@ public interface ISysDepartService extends IService<SysDepart>{ |
67 | 67 | * @param keyWord |
68 | 68 | * @return |
69 | 69 | */ |
70 | - List<SysDepartTreeModel> searhBy(String keyWord,String myDeptSearch,String departIds); | |
70 | + List<SysDepartTreeModel> searchByKeyWord(String keyWord,String myDeptSearch,String departIds); | |
71 | 71 | |
72 | 72 | /** |
73 | 73 | * 根据部门id删除并删除其可能存在的子级部门 |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java
... | ... | @@ -14,7 +14,7 @@ public interface ISysTenantService extends IService<SysTenant> { |
14 | 14 | * @param idList |
15 | 15 | * @return |
16 | 16 | */ |
17 | - List<SysTenant> queryEffectiveTenant(Collection<String> idList); | |
17 | + List<SysTenant> queryEffectiveTenant(Collection<Integer> idList); | |
18 | 18 | |
19 | 19 | /** |
20 | 20 | * 返回某个租户被多少个用户引用了 |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/IThirdAppService.java
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
... | ... | @@ -146,7 +146,9 @@ public class SysBaseApiImpl implements ISysBaseAPI { |
146 | 146 | //通过自定义URL匹配规则 获取菜单(实现通过菜单配置数据权限规则,实际上针对获取数据接口进行数据规则控制) |
147 | 147 | String userMatchUrl = UrlMatchEnum.getMatchResultByUrl(requestPath); |
148 | 148 | LambdaQueryWrapper<SysPermission> queryQserMatch = new LambdaQueryWrapper<SysPermission>(); |
149 | - queryQserMatch.eq(SysPermission::getMenuType, 1); | |
149 | + // update-begin-author:taoyan date:20211027 for: online菜单如果配置成一级菜单 权限查询不到 取消menuType = 1 | |
150 | + //queryQserMatch.eq(SysPermission::getMenuType, 1); | |
151 | + // update-end-author:taoyan date:20211027 for: online菜单如果配置成一级菜单 权限查询不到 取消menuType = 1 | |
150 | 152 | queryQserMatch.eq(SysPermission::getDelFlag, 0); |
151 | 153 | queryQserMatch.eq(SysPermission::getUrl, userMatchUrl); |
152 | 154 | if(oConvertUtils.isNotEmpty(userMatchUrl)){ |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartPermissionServiceImpl.java
... | ... | @@ -69,7 +69,7 @@ public class SysDepartPermissionServiceImpl extends ServiceImpl<SysDepartPermiss |
69 | 69 | @Override |
70 | 70 | public List<SysPermissionDataRule> getPermRuleListByDeptIdAndPermId(String departId, String permissionId) { |
71 | 71 | SysDepartPermission departPermission = this.getOne(new QueryWrapper<SysDepartPermission>().lambda().eq(SysDepartPermission::getDepartId, departId).eq(SysDepartPermission::getPermissionId, permissionId)); |
72 | - if(departPermission != null){ | |
72 | + if(departPermission != null && oConvertUtils.isNotEmpty(departPermission.getDataRuleIds())){ | |
73 | 73 | LambdaQueryWrapper<SysPermissionDataRule> query = new LambdaQueryWrapper<SysPermissionDataRule>(); |
74 | 74 | query.in(SysPermissionDataRule::getId, Arrays.asList(departPermission.getDataRuleIds().split(","))); |
75 | 75 | query.orderByDesc(SysPermissionDataRule::getCreateTime); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
... | ... | @@ -300,7 +300,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart |
300 | 300 | * </p> |
301 | 301 | */ |
302 | 302 | @Override |
303 | - public List<SysDepartTreeModel> searhBy(String keyWord,String myDeptSearch,String departIds) { | |
303 | + public List<SysDepartTreeModel> searchByKeyWord(String keyWord,String myDeptSearch,String departIds) { | |
304 | 304 | LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>(); |
305 | 305 | List<SysDepartTreeModel> newList = new ArrayList<>(); |
306 | 306 | //myDeptSearch不为空时为我的部门搜索,只搜索所负责部门 |
... | ... | @@ -311,9 +311,15 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart |
311 | 311 | } |
312 | 312 | //根据部门id获取所负责部门 |
313 | 313 | String[] codeArr = this.getMyDeptParentOrgCode(departIds); |
314 | - for(int i=0;i<codeArr.length;i++){ | |
315 | - query.or().likeRight(SysDepart::getOrgCode,codeArr[i]); | |
314 | + //update-begin-author:taoyan date:20220104 for:/issues/3311 当用户属于两个部门的时候,且这两个部门没有上下级关系,我的部门-部门名称查询条件模糊搜索失效! | |
315 | + if (codeArr != null && codeArr.length > 0) { | |
316 | + query.nested(i -> { | |
317 | + for (String s : codeArr) { | |
318 | + i.or().likeRight(SysDepart::getOrgCode, s); | |
319 | + } | |
320 | + }); | |
316 | 321 | } |
322 | + //update-end-author:taoyan date:20220104 for:/issues/3311 当用户属于两个部门的时候,且这两个部门没有上下级关系,我的部门-部门名称查询条件模糊搜索失效! | |
317 | 323 | query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString()); |
318 | 324 | } |
319 | 325 | query.like(SysDepart::getDepartName, keyWord); |
... | ... | @@ -499,7 +505,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart |
499 | 505 | } |
500 | 506 | }; |
501 | 507 | LambdaQueryWrapper<SysDepart> lqw=new LambdaQueryWrapper(); |
502 | - lqw.eq(true,SysDepart::getDelFlag,CommonConstant.DEL_FLAG_0); | |
508 | + lqw.eq(true,SysDepart::getDelFlag,CommonConstant.DEL_FLAG_0.toString()); | |
503 | 509 | lqw.func(square); |
504 | 510 | lqw.orderByDesc(SysDepart::getDepartOrder); |
505 | 511 | List<SysDepart> list = list(lqw); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
... | ... | @@ -163,7 +163,15 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl |
163 | 163 | |
164 | 164 | @Override |
165 | 165 | public List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> keys) { |
166 | - return sysDictMapper.queryTableDictTextByKeys(table, text, code, keys); | |
166 | + //update-begin-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件 | |
167 | + String filterSql = null; | |
168 | + if(table.toLowerCase().indexOf("where")>0){ | |
169 | + String[] arr = table.split(" (?i)where "); | |
170 | + table = arr[0]; | |
171 | + filterSql = arr[1]; | |
172 | + } | |
173 | + return sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, keys); | |
174 | + //update-end-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件 | |
167 | 175 | } |
168 | 176 | |
169 | 177 | @Override |
... | ... | @@ -225,6 +233,11 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl |
225 | 233 | insert = sysDictMapper.insert(sysDict); |
226 | 234 | if (sysDictItemList != null) { |
227 | 235 | for (SysDictItem entity : sysDictItemList) { |
236 | + //update-begin---author:wangshuai ---date:20220211 for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------ | |
237 | + if(oConvertUtils.isEmpty(entity.getItemValue())){ | |
238 | + return -1; | |
239 | + } | |
240 | + //update-end---author:wangshuai ---date:20220211 for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------ | |
228 | 241 | entity.setDictId(sysDict.getId()); |
229 | 242 | entity.setStatus(1); |
230 | 243 | sysDictItemMapper.insert(entity); |
... | ... | @@ -255,7 +268,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl |
255 | 268 | public List<DictModel> queryLittleTableDictItems(String table, String text, String code, String condition, String keyword, int pageSize) { |
256 | 269 | Page<DictModel> page = new Page<DictModel>(1, pageSize); |
257 | 270 | page.setSearchCount(false); |
258 | - String filterSql = getFilterSql(text, code, condition, keyword); | |
271 | + String filterSql = getFilterSql(table, text, code, condition, keyword); | |
259 | 272 | IPage<DictModel> pageList = baseMapper.queryTableDictWithFilter(page, table, text, code, filterSql); |
260 | 273 | return pageList.getRecords(); |
261 | 274 | } |
... | ... | @@ -268,12 +281,19 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl |
268 | 281 | * @param keyword |
269 | 282 | * @return |
270 | 283 | */ |
271 | - private String getFilterSql(String text, String code, String condition, String keyword){ | |
284 | + private String getFilterSql(String table, String text, String code, String condition, String keyword){ | |
272 | 285 | String keywordSql = null, filterSql = "", sql_where = " where "; |
286 | + // update-begin-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错 | |
287 | + if (table.toLowerCase().contains(" where ")) { | |
288 | + sql_where = " and "; | |
289 | + } | |
290 | + // update-end-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错 | |
273 | 291 | if(oConvertUtils.isNotEmpty(keyword)){ |
274 | 292 | // 判断是否是多选 |
275 | 293 | if (keyword.contains(",")) { |
276 | - String inKeywords = "\"" + keyword.replaceAll(",", "\",\"") + "\""; | |
294 | + //update-begin--author:scott--date:20220105--for:JTC-529【表单设计器】 编辑页面报错,in参数采用双引号导致 ---- | |
295 | + String inKeywords = "'" + String.join("','", keyword.split(",")) + "'"; | |
296 | + //update-end--author:scott--date:20220105--for:JTC-529【表单设计器】 编辑页面报错,in参数采用双引号导致---- | |
277 | 297 | keywordSql = "(" + text + " in (" + inKeywords + ") or " + code + " in (" + inKeywords + "))"; |
278 | 298 | } else { |
279 | 299 | keywordSql = "("+text + " like '%"+keyword+"%' or "+ code + " like '%"+keyword+"%')"; |
... | ... | @@ -290,14 +310,20 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl |
290 | 310 | } |
291 | 311 | @Override |
292 | 312 | public List<DictModel> queryAllTableDictItems(String table, String text, String code, String condition, String keyword) { |
293 | - String filterSql = getFilterSql(text, code, condition, keyword); | |
313 | + String filterSql = getFilterSql(table, text, code, condition, keyword); | |
294 | 314 | List<DictModel> ls = baseMapper.queryAllTableDictItems(table, text, code, filterSql); |
295 | 315 | return ls; |
296 | 316 | } |
297 | 317 | |
298 | 318 | @Override |
299 | 319 | public List<TreeSelectModel> queryTreeList(Map<String, String> query,String table, String text, String code, String pidField,String pid,String hasChildField) { |
300 | - return baseMapper.queryTreeList(query,table, text, code, pidField, pid,hasChildField); | |
320 | + List<TreeSelectModel> result = baseMapper.queryTreeList(query, table, text, code, pidField, pid, hasChildField); | |
321 | + // udapte-begin-author:sunjianlei date:20220110 for: 【JTC-597】如果 query 有值,就不允许展开子节点 | |
322 | + if (query != null) { | |
323 | + result.forEach(r -> r.setLeaf(true)); | |
324 | + } | |
325 | + return result; | |
326 | + // udapte-end-author:sunjianlei date:20220110 for: 【JTC-597】如果 query 有值,就不允许展开子节点 | |
301 | 327 | } |
302 | 328 | |
303 | 329 | @Override |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java
... | ... | @@ -24,10 +24,10 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant |
24 | 24 | ISysUserService userService; |
25 | 25 | |
26 | 26 | @Override |
27 | - public List<SysTenant> queryEffectiveTenant(Collection<String> idList) { | |
27 | + public List<SysTenant> queryEffectiveTenant(Collection<Integer> idList) { | |
28 | 28 | LambdaQueryWrapper<SysTenant> queryWrapper = new LambdaQueryWrapper<>(); |
29 | 29 | queryWrapper.in(SysTenant::getId, idList); |
30 | - queryWrapper.eq(SysTenant::getStatus, CommonConstant.STATUS_1); | |
30 | + queryWrapper.eq(SysTenant::getStatus, Integer.valueOf(CommonConstant.STATUS_1)); | |
31 | 31 | //此处查询忽略时间条件 |
32 | 32 | return super.list(queryWrapper); |
33 | 33 | } |
... | ... | @@ -50,7 +50,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant |
50 | 50 | if (userCount > 0) { |
51 | 51 | throw new JeecgBootException("该租户已被引用,无法删除!"); |
52 | 52 | } |
53 | - return super.removeById(id); | |
53 | + return super.removeById(Integer.parseInt(id)); | |
54 | 54 | } |
55 | 55 | |
56 | 56 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java
... | ... | @@ -2,6 +2,7 @@ package org.jeecg.modules.system.service.impl; |
2 | 2 | |
3 | 3 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
4 | 4 | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
5 | +import lombok.extern.slf4j.Slf4j; | |
5 | 6 | import org.jeecg.common.constant.CommonConstant; |
6 | 7 | import org.jeecg.common.util.DateUtils; |
7 | 8 | import org.jeecg.common.util.PasswordUtil; |
... | ... | @@ -30,6 +31,7 @@ import java.util.List; |
30 | 31 | * @Version: V1.0 |
31 | 32 | */ |
32 | 33 | @Service |
34 | +@Slf4j | |
33 | 35 | public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMapper, SysThirdAccount> implements ISysThirdAccountService { |
34 | 36 | |
35 | 37 | @Autowired |
... | ... | @@ -116,6 +118,7 @@ public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMappe |
116 | 118 | @Override |
117 | 119 | public SysThirdAccount getOneBySysUserId(String sysUserId, String thirdType) { |
118 | 120 | LambdaQueryWrapper<SysThirdAccount> queryWrapper = new LambdaQueryWrapper<>(); |
121 | + log.info("getSysUserId: {} ,getThirdType: {}",sysUserId,thirdType); | |
119 | 122 | queryWrapper.eq(SysThirdAccount::getSysUserId, sysUserId); |
120 | 123 | queryWrapper.eq(SysThirdAccount::getThirdType, thirdType); |
121 | 124 | return super.getOne(queryWrapper); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
1 | 1 | package org.jeecg.modules.system.service.impl; |
2 | 2 | |
3 | -import java.util.ArrayList; | |
4 | -import java.util.HashMap; | |
5 | -import java.util.List; | |
6 | -import java.util.Map; | |
7 | -import java.util.stream.Collectors; | |
8 | -import java.util.stream.Collectors; | |
9 | - | |
10 | -import com.baomidou.mybatisplus.core.conditions.Wrapper; | |
3 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |
11 | 4 | import com.baomidou.mybatisplus.core.metadata.IPage; |
12 | 5 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
6 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |
7 | +import org.jeecg.common.constant.CommonConstant; | |
13 | 8 | import org.jeecg.common.util.oConvertUtils; |
14 | 9 | import org.jeecg.modules.system.entity.SysDepart; |
15 | 10 | import org.jeecg.modules.system.entity.SysUser; |
... | ... | @@ -22,8 +17,11 @@ import org.jeecg.modules.system.service.ISysUserService; |
22 | 17 | import org.springframework.beans.factory.annotation.Autowired; |
23 | 18 | import org.springframework.stereotype.Service; |
24 | 19 | |
25 | -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |
26 | -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |
20 | +import java.util.ArrayList; | |
21 | +import java.util.HashMap; | |
22 | +import java.util.List; | |
23 | +import java.util.Map; | |
24 | +import java.util.stream.Collectors; | |
27 | 25 | |
28 | 26 | /** |
29 | 27 | * <P> |
... | ... | @@ -128,6 +126,9 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S |
128 | 126 | Page<SysUser> page = new Page<SysUser>(pageNo, pageSize); |
129 | 127 | if(oConvertUtils.isEmpty(departId)){ |
130 | 128 | LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>(); |
129 | + //update-begin---author:wangshuai ---date:20220104 for:[JTC-297]已冻结用户仍可设置为代理人------------ | |
130 | + query.eq(SysUser::getStatus,Integer.parseInt(CommonConstant.STATUS_1)); | |
131 | + //update-end---author:wangshuai ---date:20220104 for:[JTC-297]已冻结用户仍可设置为代理人------------ | |
131 | 132 | if(oConvertUtils.isNotEmpty(username)){ |
132 | 133 | query.like(SysUser::getUsername, username); |
133 | 134 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
... | ... | @@ -399,6 +399,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl |
399 | 399 | } |
400 | 400 | |
401 | 401 | @Override |
402 | + @CacheEvict(value={CacheConstant.SYS_USERS_CACHE}, allEntries=true) | |
402 | 403 | public boolean revertLogicDeleted(List<String> userIds, SysUser updateEntity) { |
403 | 404 | String ids = String.format("'%s'", String.join("','", userIds)); |
404 | 405 | return userMapper.revertLogicDeleted(ids, updateEntity) > 0; |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java
... | ... | @@ -85,18 +85,31 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { |
85 | 85 | return null; |
86 | 86 | } |
87 | 87 | |
88 | + // update:2022-1-21,updateBy:sunjianlei; for 【JTC-704】【钉钉】部门同步成功,实际没成,后台提示ip白名单 | |
88 | 89 | @Override |
89 | - public boolean syncLocalDepartmentToThirdApp(String ids) { | |
90 | + public SyncInfoVo syncLocalDepartmentToThirdApp(String ids) { | |
91 | + SyncInfoVo syncInfo = new SyncInfoVo(); | |
90 | 92 | String accessToken = this.getAccessToken(); |
91 | 93 | if (accessToken == null) { |
92 | - return false; | |
94 | + syncInfo.addFailInfo("accessToken获取失败!"); | |
95 | + return syncInfo; | |
93 | 96 | } |
94 | 97 | // 获取【钉钉】所有的部门 |
95 | - List<Department> departments = JdtDepartmentAPI.listAll(accessToken); | |
98 | + List<Response<Department>> departments = JdtDepartmentAPI.listAllResponse(accessToken); | |
96 | 99 | // 删除钉钉有但本地没有的部门(以本地部门数据为主)(钉钉不能创建同名部门,只能先删除) |
97 | 100 | List<SysDepart> sysDepartList = sysDepartService.list(); |
98 | 101 | for1: |
99 | - for (Department department : departments) { | |
102 | + for (Response<Department> departmentRes : departments) { | |
103 | + // 判断部门是否查询成功 | |
104 | + if (!departmentRes.isSuccess()) { | |
105 | + syncInfo.addFailInfo(departmentRes.getErrmsg()); | |
106 | + // 88 是 ip 不在白名单的错误码,如果遇到此错误码,后面的操作都可以不用进行了,因为肯定都是失败的 | |
107 | + if (new Integer(88).equals(departmentRes.getErrcode())) { | |
108 | + return syncInfo; | |
109 | + } | |
110 | + continue; | |
111 | + } | |
112 | + Department department = departmentRes.getResult(); | |
100 | 113 | for (SysDepart depart : sysDepartList) { |
101 | 114 | // id相同,代表已存在,不删除 |
102 | 115 | String sourceIdentifier = department.getSource_identifier(); |
... | ... | @@ -124,24 +137,34 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { |
124 | 137 | Department parent = new Department(); |
125 | 138 | parent.setDept_id(1); |
126 | 139 | // 递归同步部门 |
127 | - departments = JdtDepartmentAPI.listAll(accessToken); | |
128 | - this.syncDepartmentRecursion(sysDepartsTree, departments, parent, accessToken); | |
129 | - return true; | |
140 | + departments = JdtDepartmentAPI.listAllResponse(accessToken); | |
141 | + this.syncDepartmentRecursion(sysDepartsTree, departments, parent, accessToken, syncInfo); | |
142 | + return syncInfo; | |
130 | 143 | } |
131 | 144 | |
132 | 145 | // 递归同步部门到本地 |
133 | - public void syncDepartmentRecursion(List<SysDepartTreeModel> sysDepartsTree, List<Department> departments, Department parent, String accessToken) { | |
146 | + public void syncDepartmentRecursion(List<SysDepartTreeModel> sysDepartsTree, List<Response<Department>> departments, Department parent, String accessToken, SyncInfoVo syncInfo) { | |
134 | 147 | if (sysDepartsTree != null && sysDepartsTree.size() != 0) { |
135 | 148 | for1: |
136 | 149 | for (SysDepartTreeModel depart : sysDepartsTree) { |
137 | - for (Department department : departments) { | |
150 | + for (Response<Department> departmentRes : departments) { | |
151 | + // 判断部门是否查询成功 | |
152 | + if (!departmentRes.isSuccess()) { | |
153 | + syncInfo.addFailInfo(departmentRes.getErrmsg()); | |
154 | + continue; | |
155 | + } | |
156 | + Department department = departmentRes.getResult(); | |
138 | 157 | // id相同,代表已存在,执行修改操作 |
139 | 158 | String sourceIdentifier = department.getSource_identifier(); |
140 | 159 | if (sourceIdentifier != null && sourceIdentifier.equals(depart.getId())) { |
141 | 160 | this.sysDepartToDtDepartment(depart, department, parent.getDept_id()); |
142 | - JdtDepartmentAPI.update(department, accessToken); | |
143 | - // 紧接着同步子级 | |
144 | - this.syncDepartmentRecursion(depart.getChildren(), departments, department, accessToken); | |
161 | + Response<JSONObject> response = JdtDepartmentAPI.update(department, accessToken); | |
162 | + if (response.isSuccess()) { | |
163 | + // 紧接着同步子级 | |
164 | + this.syncDepartmentRecursion(depart.getChildren(), departments, department, accessToken, syncInfo); | |
165 | + } | |
166 | + // 收集错误信息 | |
167 | + this.syncDepartCollectErrInfo(response, depart, syncInfo); | |
145 | 168 | // 跳出外部循环 |
146 | 169 | continue for1; |
147 | 170 | } |
... | ... | @@ -154,10 +177,10 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { |
154 | 177 | Department newParent = new Department(); |
155 | 178 | newParent.setDept_id(response.getResult()); |
156 | 179 | // 紧接着同步子级 |
157 | - this.syncDepartmentRecursion(depart.getChildren(), departments, newParent, accessToken); | |
180 | + this.syncDepartmentRecursion(depart.getChildren(), departments, newParent, accessToken, syncInfo); | |
158 | 181 | } |
159 | 182 | // 收集错误信息 |
160 | -// this.syncUserCollectErrInfo(errCode, sysUser, errInfo); | |
183 | + this.syncDepartCollectErrInfo(response, depart, syncInfo); | |
161 | 184 | } |
162 | 185 | } |
163 | 186 | } |
... | ... | @@ -209,6 +232,11 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { |
209 | 232 | SysDepart newSysDepart = this.dtDepartmentToSysDepart(departmentTree, null); |
210 | 233 | if (sysParentId != null) { |
211 | 234 | newSysDepart.setParentId(sysParentId); |
235 | + // 2 = 组织机构 | |
236 | + newSysDepart.setOrgCategory("2"); | |
237 | + } else { | |
238 | + // 1 = 公司 | |
239 | + newSysDepart.setOrgCategory("1"); | |
212 | 240 | } |
213 | 241 | try { |
214 | 242 | sysDepartService.saveDepartData(newSysDepart, username); |
... | ... | @@ -246,6 +274,20 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { |
246 | 274 | return false; |
247 | 275 | } |
248 | 276 | |
277 | + /** | |
278 | + * 【同步部门】收集同步过程中的错误信息 | |
279 | + */ | |
280 | + private boolean syncDepartCollectErrInfo(Response<?> response, SysDepartTreeModel depart, SyncInfoVo syncInfo) { | |
281 | + if (!response.isSuccess()) { | |
282 | + String str = String.format("部门 %s(%s) 同步失败!错误码:%s——%s", depart.getDepartName(), depart.getOrgCode(), response.getErrcode(), response.getErrmsg()); | |
283 | + syncInfo.addFailInfo(str); | |
284 | + return false; | |
285 | + } else { | |
286 | + String str = String.format("部门户 %s(%s) 同步成功!", depart.getDepartName(), depart.getOrgCode()); | |
287 | + syncInfo.addSuccessInfo(str); | |
288 | + return true; | |
289 | + } | |
290 | + } | |
249 | 291 | |
250 | 292 | @Override |
251 | 293 | public SyncInfoVo syncLocalUserToThirdApp(String ids) { |
... | ... | @@ -279,7 +321,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { |
279 | 321 | /* |
280 | 322 | * 判断是否同步过的逻辑: |
281 | 323 | * 1. 查询 sys_third_account(第三方账号表)是否有数据,如果有代表已同步 |
282 | - * 2. 本地表里没有,就先用手机号判断,不通过再用username判断。 | |
324 | + * 2. 本地表里没有,就先用手机号判断,不通过再用username(用户账号)判断。 | |
283 | 325 | */ |
284 | 326 | SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneBySysUserId(sysUser.getId(), THIRD_TYPE); |
285 | 327 | if (sysThirdAccount != null && oConvertUtils.isNotEmpty(sysThirdAccount.getThirdUserId())) { |
... | ... | @@ -528,6 +570,12 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService { |
528 | 570 | // update-begin--Author:liusq Date:20210713 for:钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L |
529 | 571 | sysUser.setStatus(1); |
530 | 572 | // update-end--Author:liusq Date:20210713 for:钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L |
573 | + // 设置工号,如果工号为空,则使用username | |
574 | + if (oConvertUtils.isEmpty(dtUser.getJob_number())) { | |
575 | + sysUser.setWorkNo(dtUser.getUserid()); | |
576 | + } else { | |
577 | + sysUser.setWorkNo(dtUser.getJob_number()); | |
578 | + } | |
531 | 579 | return this.dtUserToSysUser(dtUser, sysUser); |
532 | 580 | } |
533 | 581 | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java
... | ... | @@ -96,15 +96,18 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { |
96 | 96 | } |
97 | 97 | |
98 | 98 | @Override |
99 | - public boolean syncLocalDepartmentToThirdApp(String ids) { | |
99 | + public SyncInfoVo syncLocalDepartmentToThirdApp(String ids) { | |
100 | + SyncInfoVo syncInfo = new SyncInfoVo(); | |
100 | 101 | String accessToken = this.getAccessToken(); |
101 | 102 | if (accessToken == null) { |
102 | - return false; | |
103 | + syncInfo.addFailInfo("accessToken获取失败!"); | |
104 | + return syncInfo; | |
103 | 105 | } |
104 | 106 | // 获取企业微信所有的部门 |
105 | 107 | List<Department> departments = JwDepartmentAPI.getAllDepartment(accessToken); |
106 | 108 | if (departments == null) { |
107 | - return false; | |
109 | + syncInfo.addFailInfo("获取企业微信所有部门失败!"); | |
110 | + return syncInfo; | |
108 | 111 | } |
109 | 112 | // 删除企业微信有但本地没有的部门(以本地部门数据为主)(以为企业微信不能创建同名部门,所以只能先删除) |
110 | 113 | List<JwDepartmentTreeVo> departmentTreeList = JwDepartmentTreeVo.listToTree(departments); |
... | ... | @@ -117,7 +120,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { |
117 | 120 | // 递归同步部门 |
118 | 121 | departments = JwDepartmentAPI.getAllDepartment(accessToken); |
119 | 122 | this.syncDepartmentRecursion(sysDepartsTree, departments, parent, accessToken); |
120 | - return true; | |
123 | + return syncInfo; | |
121 | 124 | } |
122 | 125 | |
123 | 126 | // 递归删除部门以及子部门,由于企业微信不允许删除带有成员和子部门的部门,所以需要递归删除下子部门,然后把部门成员移动端根部门下 |
... | ... | @@ -250,6 +253,11 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { |
250 | 253 | SysDepart newSysDepart = this.qwDepartmentToSysDepart(departmentTree, null); |
251 | 254 | if (sysParentId != null) { |
252 | 255 | newSysDepart.setParentId(sysParentId); |
256 | + // 2 = 组织机构 | |
257 | + newSysDepart.setOrgCategory("2"); | |
258 | + } else { | |
259 | + // 1 = 公司 | |
260 | + newSysDepart.setOrgCategory("1"); | |
253 | 261 | } |
254 | 262 | try { |
255 | 263 | sysDepartService.saveDepartData(newSysDepart, username); |
... | ... | @@ -604,6 +612,10 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService { |
604 | 612 | BeanUtils.copyProperties(oldSysUser, sysUser); |
605 | 613 | sysUser.setRealname(qwUser.getName()); |
606 | 614 | sysUser.setPost(qwUser.getPosition()); |
615 | + // 设置工号,由于企业微信没有工号的概念,所以只能用 userId 代替 | |
616 | + if (oConvertUtils.isEmpty(sysUser.getWorkNo())) { | |
617 | + sysUser.setWorkNo(qwUser.getUserid()); | |
618 | + } | |
607 | 619 | try { |
608 | 620 | sysUser.setSex(Integer.parseInt(qwUser.getGender())); |
609 | 621 | } catch (NumberFormatException ignored) { |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml
jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/utils.ftl
... | ... | @@ -115,9 +115,9 @@ |
115 | 115 | <#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}'}"> |
116 | 116 | <#else> |
117 | 117 | <#if po.classType=="sel_search" || po.classType=="list_multi"> |
118 | - <#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}',dictTable:'${superQuery_dictTable}', dictText:'${superQuery_dictText}', dictCode:'${po.dictField}'}"> | |
118 | + <#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}',dictTable:\"${superQuery_dictTable}\", dictText:'${superQuery_dictText}', dictCode:'${po.dictField}'}"> | |
119 | 119 | <#elseif po.dictTable?? && po.dictTable!="" && po.classType!="sel_tree" && po.classType!="cat_tree" && po.classType!="link_down"> |
120 | - <#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:'${po.dictTable},${po.dictText},${po.dictField}'}"> | |
120 | + <#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:\"${po.dictTable},${po.dictText},${po.dictField}\"}"> | |
121 | 121 | <#elseif po.dictField?? && po.classType!="sel_tree" && po.classType!="cat_tree" && po.classType!="link_down"> |
122 | 122 | <#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:'${po.dictField}'}"> |
123 | 123 | <#elseif po.fieldDbType=="Text"> |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -65,10 +65,10 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
65 | 65 | * @param req |
66 | 66 | * @return |
67 | 67 | */ |
68 | - @AutoLog(value = "${tableVo.ftlDescription}-分页列表查询") | |
68 | + //@AutoLog(value = "${tableVo.ftlDescription}-分页列表查询") | |
69 | 69 | @ApiOperation(value="${tableVo.ftlDescription}-分页列表查询", notes="${tableVo.ftlDescription}-分页列表查询") |
70 | 70 | @GetMapping(value = "/list") |
71 | - public Result<?> queryPageList(${entityName} ${entityName?uncap_first}, | |
71 | + public Result<IPage<${entityName}>> queryPageList(${entityName} ${entityName?uncap_first}, | |
72 | 72 | @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, |
73 | 73 | @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, |
74 | 74 | HttpServletRequest req) { |
... | ... | @@ -87,7 +87,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
87 | 87 | @AutoLog(value = "${tableVo.ftlDescription}-添加") |
88 | 88 | @ApiOperation(value="${tableVo.ftlDescription}-添加", notes="${tableVo.ftlDescription}-添加") |
89 | 89 | @PostMapping(value = "/add") |
90 | - public Result<?> add(@RequestBody ${entityName} ${entityName?uncap_first}) { | |
90 | + public Result<String> add(@RequestBody ${entityName} ${entityName?uncap_first}) { | |
91 | 91 | <#if bpm_flag> |
92 | 92 | ${entityName?uncap_first}.setBpmStatus("1"); |
93 | 93 | </#if> |
... | ... | @@ -103,8 +103,8 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
103 | 103 | */ |
104 | 104 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
105 | 105 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
106 | - @PutMapping(value = "/edit") | |
107 | - public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) { | |
106 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
107 | + public Result<String> edit(@RequestBody ${entityName} ${entityName?uncap_first}) { | |
108 | 108 | ${entityName?uncap_first}Service.updateById(${entityName?uncap_first}); |
109 | 109 | return Result.OK("编辑成功!"); |
110 | 110 | } |
... | ... | @@ -118,7 +118,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
118 | 118 | @AutoLog(value = "${tableVo.ftlDescription}-通过id删除") |
119 | 119 | @ApiOperation(value="${tableVo.ftlDescription}-通过id删除", notes="${tableVo.ftlDescription}-通过id删除") |
120 | 120 | @DeleteMapping(value = "/delete") |
121 | - public Result<?> delete(@RequestParam(name="id",required=true) String id) { | |
121 | + public Result<String> delete(@RequestParam(name="id",required=true) String id) { | |
122 | 122 | ${entityName?uncap_first}Service.removeById(id); |
123 | 123 | return Result.OK("删除成功!"); |
124 | 124 | } |
... | ... | @@ -132,7 +132,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
132 | 132 | @AutoLog(value = "${tableVo.ftlDescription}-批量删除") |
133 | 133 | @ApiOperation(value="${tableVo.ftlDescription}-批量删除", notes="${tableVo.ftlDescription}-批量删除") |
134 | 134 | @DeleteMapping(value = "/deleteBatch") |
135 | - public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) { | |
135 | + public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) { | |
136 | 136 | this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(","))); |
137 | 137 | return Result.OK("批量删除成功!"); |
138 | 138 | } |
... | ... | @@ -143,13 +143,13 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
143 | 143 | * @param id |
144 | 144 | * @return |
145 | 145 | */ |
146 | - @AutoLog(value = "${tableVo.ftlDescription}-通过id查询") | |
146 | + //@AutoLog(value = "${tableVo.ftlDescription}-通过id查询") | |
147 | 147 | @ApiOperation(value="${tableVo.ftlDescription}-通过id查询", notes="${tableVo.ftlDescription}-通过id查询") |
148 | 148 | @GetMapping(value = "/queryById") |
149 | - public Result<?> queryById(@RequestParam(name="id",required=true) String id) { | |
149 | + public Result<${entityName}> queryById(@RequestParam(name="id",required=true) String id) { | |
150 | 150 | ${entityName} ${entityName?uncap_first} = ${entityName?uncap_first}Service.getById(id); |
151 | 151 | if(${entityName?uncap_first}==null) { |
152 | - return Result.error("未找到对应数据"); | |
152 | + return Result.error("未找到对应数据",null); | |
153 | 153 | } |
154 | 154 | return Result.OK(${entityName?uncap_first}); |
155 | 155 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
... | ... | @@ -108,8 +108,8 @@ |
108 | 108 | </#if> |
109 | 109 | </#list> |
110 | 110 | <#if bpm_flag> |
111 | - <a-col v-if="showFlowSubmitButton" :span="24" style="text-align: center"> | |
112 | - <a-button @click="submitForm">提 交</a-button> | |
111 | + <a-col v-if="showFlowSubmitButton" :span="24" style="width: 100%;text-align: center;"> | |
112 | + <a-button icon="check" style="width: 126px" type="primary" @click="submitForm">提 交</a-button> | |
113 | 113 | </a-col> |
114 | 114 | </#if> |
115 | 115 | </a-row> |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | +<#assign list_need_category=false> | |
4 | +<#assign list_need_pca=false> | |
5 | +<#assign bpm_flag=false> | |
6 | + | |
7 | +<#-- 开始循环 --> | |
8 | +<#list columns as po> | |
9 | +<#if po.fieldDbName=='bpm_status'> | |
10 | + <#assign bpm_flag=true> | |
11 | +</#if> | |
12 | +<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0> | |
13 | +<#assign list_need_category=true> | |
14 | +</#if> | |
15 | +<#if po.classType=='pca'> | |
16 | +<#assign list_need_pca=true> | |
17 | +</#if> | |
18 | +</#list> | |
19 | +<#-- 结束循环 --> | |
20 | + <!--引用表格--> | |
21 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
22 | + <!--插槽:table标题--> | |
23 | + <template #tableTitle> | |
24 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
25 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
26 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
27 | + <a-dropdown v-if="checkedKeys.length > 0"> | |
28 | + <template #overlay> | |
29 | + <a-menu> | |
30 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
31 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
32 | + 删除 | |
33 | + </a-menu-item> | |
34 | + </a-menu> | |
35 | + </template> | |
36 | + <a-button>批量操作 | |
37 | + <Icon icon="mdi:chevron-down"></Icon> | |
38 | + </a-button> | |
39 | + </a-dropdown> | |
40 | + </template> | |
41 | + <!--操作栏--> | |
42 | + <template #action="{ record }"> | |
43 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
44 | + </template> | |
45 | + <!--字段回显插槽--> | |
46 | + <template #htmlSlot="{text}"> | |
47 | + <div v-html="text"></div> | |
48 | + </template> | |
49 | + <template #fileSlot="{text}"> | |
50 | + <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |
51 | + <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |
52 | + </template> | |
53 | + </BasicTable> | |
54 | + <!-- 表单区域 --> | |
55 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
56 | + </div> | |
57 | +</template> | |
58 | + | |
59 | +<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup> | |
60 | + import {ref, computed, unref} from 'vue'; | |
61 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
62 | + import {useModal} from '/@/components/Modal'; | |
63 | + import { useListPage } from '/@/hooks/system/useListPage' | |
64 | + import ${entityName}Modal from './components/${entityName}Modal.vue' | |
65 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
66 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
67 | + <#if list_need_category> | |
68 | + import { loadCategoryData } from '/@/api/common/api' | |
69 | + import { getAuthCache, setAuthCache } from '/@/utils/auth'; | |
70 | + import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum'; | |
71 | + </#if> | |
72 | + const checkedKeys = ref<Array<string | number>>([]); | |
73 | + //注册model | |
74 | + const [registerModal, {openModal}] = useModal(); | |
75 | + //注册table数据 | |
76 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
77 | + tableProps:{ | |
78 | + title: '${tableVo.ftlDescription}', | |
79 | + api: list, | |
80 | + columns, | |
81 | + canResize:false, | |
82 | + formConfig: { | |
83 | + labelWidth: 120, | |
84 | + schemas: searchFormSchema, | |
85 | + autoSubmitOnEnter:true, | |
86 | + showAdvancedButton:true, | |
87 | + fieldMapToTime: [ | |
88 | + <#list columns as po> | |
89 | + <#if po.isQuery=='Y'> | |
90 | + <#if po.queryMode!='single'> | |
91 | + <#if po.classType=='date'> | |
92 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'], | |
93 | + <#elseif po.classType=='datetime'> | |
94 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'], | |
95 | + </#if> | |
96 | + </#if> | |
97 | + </#if> | |
98 | + </#list> | |
99 | + ], | |
100 | + }, | |
101 | + actionColumn: { | |
102 | + width: 120, | |
103 | + }, | |
104 | + }, | |
105 | + exportConfig: { | |
106 | + name:"${tableVo.ftlDescription}", | |
107 | + url: getExportUrl, | |
108 | + }, | |
109 | + importConfig: { | |
110 | + url: getImportUrl | |
111 | + }, | |
112 | + }) | |
113 | + | |
114 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
115 | + | |
116 | + /** | |
117 | + * 新增事件 | |
118 | + */ | |
119 | + function handleAdd() { | |
120 | + openModal(true, { | |
121 | + isUpdate: false, | |
122 | + showFooter: true, | |
123 | + }); | |
124 | + } | |
125 | + /** | |
126 | + * 编辑事件 | |
127 | + */ | |
128 | + function handleEdit(record: Recordable) { | |
129 | + openModal(true, { | |
130 | + record, | |
131 | + isUpdate: true, | |
132 | + showFooter: true, | |
133 | + }); | |
134 | + } | |
135 | + /** | |
136 | + * 详情 | |
137 | + */ | |
138 | + function handleDetail(record: Recordable) { | |
139 | + openModal(true, { | |
140 | + record, | |
141 | + isUpdate: true, | |
142 | + showFooter: false, | |
143 | + }); | |
144 | + } | |
145 | + /** | |
146 | + * 删除事件 | |
147 | + */ | |
148 | + async function handleDelete(record) { | |
149 | + await deleteOne({id: record.id}, reload); | |
150 | + } | |
151 | + /** | |
152 | + * 批量删除事件 | |
153 | + */ | |
154 | + async function batchHandleDelete() { | |
155 | + await batchDelete({ids: checkedKeys.value}, reload); | |
156 | + } | |
157 | + /** | |
158 | + * 成功回调 | |
159 | + */ | |
160 | + function handleSuccess() { | |
161 | + reload(); | |
162 | + } | |
163 | + /** | |
164 | + * 操作栏 | |
165 | + */ | |
166 | + function getTableAction(record){ | |
167 | + return [ | |
168 | + { | |
169 | + label: '编辑', | |
170 | + onClick: handleEdit.bind(null, record), | |
171 | + } | |
172 | + ] | |
173 | + } | |
174 | + /** | |
175 | + * 下拉操作栏 | |
176 | + */ | |
177 | + function getDropDownAction(record){ | |
178 | + return [ | |
179 | + { | |
180 | + label: '详情', | |
181 | + onClick: handleDetail.bind(null, record), | |
182 | + }, { | |
183 | + label: '删除', | |
184 | + popConfirm: { | |
185 | + title: '是否确认删除', | |
186 | + confirm: handleDelete.bind(null, record), | |
187 | + } | |
188 | + } | |
189 | + ] | |
190 | + } | |
191 | + <#if list_need_category> | |
192 | + /** | |
193 | + * 初始化字典配置 | |
194 | + */ | |
195 | + function initDictConfig(){ | |
196 | + <#list columns as po> | |
197 | + <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'> | |
198 | + <#if po.classType=='cat_tree' && list_need_category==true> | |
199 | + loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => { | |
200 | + if (res) { | |
201 | + let allDictDate = getAuthCache(DB_DICT_DATA_KEY); | |
202 | + if(!allDictDate['${po.dictField?default("")}']){ | |
203 | + Object.assign(allDictDate,{'${po.dictField?default("")}':res}) | |
204 | + } | |
205 | + setAuthCache(DB_DICT_DATA_KEY,allDictDate) | |
206 | + } | |
207 | + }) | |
208 | + </#if> | |
209 | + </#if> | |
210 | + </#list> | |
211 | + } | |
212 | + initDictConfig(); | |
213 | + </#if> | |
214 | +</script> | |
215 | + | |
216 | +<style scoped> | |
217 | + | |
218 | +</style> | |
0 | 219 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +} | |
13 | +/** | |
14 | + * 导出api | |
15 | + * @param params | |
16 | + */ | |
17 | +export const getExportUrl = Api.exportXls; | |
18 | +/** | |
19 | + * 导入api | |
20 | + */ | |
21 | +export const getImportUrl = Api.importExcel; | |
22 | +/** | |
23 | + * 列表接口 | |
24 | + * @param params | |
25 | + */ | |
26 | +export const list = (params) => | |
27 | + defHttp.get({url: Api.list, params}); | |
28 | + | |
29 | +/** | |
30 | + * 删除单个 | |
31 | + */ | |
32 | +export const deleteOne = (params,handleSuccess) => { | |
33 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
34 | + handleSuccess(); | |
35 | + }); | |
36 | +} | |
37 | +/** | |
38 | + * 批量删除 | |
39 | + * @param params | |
40 | + */ | |
41 | +export const batchDelete = (params, handleSuccess) => { | |
42 | + Modal.confirm({ | |
43 | + title: '确认删除', | |
44 | + content: '是否删除选中数据', | |
45 | + okText: '确认', | |
46 | + cancelText: '取消', | |
47 | + onOk: () => { | |
48 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
49 | + handleSuccess(); | |
50 | + }); | |
51 | + } | |
52 | + }); | |
53 | +} | |
54 | +/** | |
55 | + * 保存或者更新 | |
56 | + * @param params | |
57 | + */ | |
58 | +export const saveOrUpdate = (params, isUpdate) => { | |
59 | + let url = isUpdate ? Api.edit : Api.save; | |
60 | + return defHttp.post({url: url, params}); | |
61 | +} | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +//列表数据 | |
6 | +export const columns: BasicColumn[] = [ | |
7 | + <#list columns as po> | |
8 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
9 | + { | |
10 | + title: '${po.filedComment}', | |
11 | + align:"center", | |
12 | + <#if po.sort=='Y'> | |
13 | + sorter: true, | |
14 | + </#if> | |
15 | + <#if po.classType=='date'> | |
16 | + dataIndex: '${po.fieldName}', | |
17 | + customRender:({text}) =>{ | |
18 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
19 | + }, | |
20 | + <#elseif po.fieldDbType=='Blob'> | |
21 | + dataIndex: '${po.fieldName}String' | |
22 | + <#elseif po.classType=='umeditor'> | |
23 | + dataIndex: '${po.fieldName}', | |
24 | + slots: { customRender: 'htmlSlot' }, | |
25 | + <#elseif po.classType=='pca'> | |
26 | + dataIndex: '${po.fieldName}', | |
27 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
28 | + <#elseif po.classType=='file'> | |
29 | + dataIndex: '${po.fieldName}', | |
30 | + slots: { customRender: 'fileSlot' }, | |
31 | + <#elseif po.classType=='image'> | |
32 | + dataIndex: '${po.fieldName}', | |
33 | + customRender:render.renderAvatar, | |
34 | + <#elseif po.classType=='switch'> | |
35 | + dataIndex: '${po.fieldName}', | |
36 | +<#assign switch_extend_arr=['Y','N']> | |
37 | +<#if po.dictField?default("")?contains("[")> | |
38 | +<#assign switch_extend_arr=po.dictField?eval> | |
39 | +</#if> | |
40 | +<#list switch_extend_arr as a> | |
41 | +<#if a_index == 0> | |
42 | +<#assign switch_extend_arr1=a> | |
43 | +<#else> | |
44 | +<#assign switch_extend_arr2=a> | |
45 | +</#if> | |
46 | +</#list> | |
47 | + customRender:({text}) => { | |
48 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
49 | + }, | |
50 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
51 | + dataIndex: '${po.fieldName}_dictText' | |
52 | + <#elseif po.classType=='cat_tree'> | |
53 | + dataIndex: '${po.fieldName}', | |
54 | + <#if po.dictText?default("")?trim?length == 0> | |
55 | + customRender:({text}) => { | |
56 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
57 | + }, | |
58 | + <#else> | |
59 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
60 | + </#if> | |
61 | + <#else> | |
62 | + dataIndex: '${po.fieldName}' | |
63 | + </#if> | |
64 | + }, | |
65 | + </#if> | |
66 | + </#list> | |
67 | +]; | |
68 | +//查询数据 | |
69 | +export const searchFormSchema: FormSchema[] = [ | |
70 | +<#-- 开始循环 --> | |
71 | +<#list columns as po> | |
72 | +<#if po.fieldDbName=='bpm_status'> | |
73 | + <#assign bpm_flag=true> | |
74 | +</#if> | |
75 | +<#if po.isQuery=='Y'> | |
76 | +<#assign query_flag=true> | |
77 | + <#assign query_field_dictCode=""> | |
78 | + <#if po.dictTable?default("")?trim?length gt 1> | |
79 | + <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
80 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
81 | + <#assign query_field_dictCode="${po.dictField}"> | |
82 | + </#if> | |
83 | +<#if po.queryMode=='single'> | |
84 | + { | |
85 | + label: "${po.filedComment}", | |
86 | + field: "${po.fieldName}", | |
87 | +<#if po.classType=='sel_search'> | |
88 | + component: 'JSearchSelect', | |
89 | + componentProps:{ | |
90 | + dict:"${po.dictTable},${po.dictText},${po.dictField}" | |
91 | + }, | |
92 | +<#elseif po.classType=='sel_user'> | |
93 | + component: 'JSelectUserByDept', | |
94 | +<#elseif po.classType=='switch'> | |
95 | + component: 'JSwitch', | |
96 | + componentProps:{ | |
97 | + <#if po.dictField != 'is_open'> | |
98 | + options:"${po.dictField}" | |
99 | + </#if> | |
100 | + }, | |
101 | + <#elseif po.classType=='sel_depart'> | |
102 | + component: 'JSelectDept', | |
103 | + <#elseif po.classType=='list_multi'> | |
104 | + component: 'JMultiSelectTag',//暂无该组件 | |
105 | + componentProps:{ | |
106 | + dictCode:"query_field_dictCode?default("")" | |
107 | + }, | |
108 | + <#elseif po.classType=='cat_tree'> | |
109 | + component: 'JCategorySelect', | |
110 | + componentProps:{ | |
111 | + pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题 | |
112 | + }, | |
113 | +<#elseif po.classType=='date'> | |
114 | + component: 'DatePicker', | |
115 | +<#elseif po.classType=='datetime'> | |
116 | + component: 'DatePicker', | |
117 | + componentProps: { | |
118 | + showTime:true | |
119 | + }, | |
120 | +<#elseif po.classType=='pca'> | |
121 | + component: 'JAreaLinkage', | |
122 | +<#elseif po.classType=='popup'> | |
123 | + component: 'JPopup', | |
124 | + componentProps: ({ formActionType }) => { | |
125 | + const {setFieldsValue} = formActionType; | |
126 | + return{ | |
127 | + setFieldsValue:setFieldsValue, | |
128 | + code:"${po.dictTable}", | |
129 | + fieldConfig:"${po.dictField}", | |
130 | + multi:${po.extendParams.popupMulti?c}, | |
131 | + } | |
132 | + }, | |
133 | +<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'> | |
134 | +<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- --> | |
135 | + component: 'JDictSelectTag', | |
136 | + componentProps:{ | |
137 | + <#if po.dictTable?default("")?trim?length gt 1> | |
138 | + dictCode:"${po.dictTable},${po.dictText},${po.dictField}" | |
139 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
140 | + dictCode:"${po.dictField}" | |
141 | + </#if> | |
142 | + }, | |
143 | +<#else> | |
144 | + component: 'Input', | |
145 | +</#if> | |
146 | + colProps: {span: 6}, | |
147 | + }, | |
148 | +<#else> | |
149 | + { | |
150 | + label: "${po.filedComment}", | |
151 | + field: "${po.fieldName}", | |
152 | +<#if po.classType=='date'> | |
153 | + component: 'RangePicker', | |
154 | +<#elseif po.classType=='datetime'> | |
155 | + component: 'RangePicker', | |
156 | + componentProps: { | |
157 | + showTime:true | |
158 | + }, | |
159 | +<#else> | |
160 | + component: 'Input', //TODO 范围查询 | |
161 | +</#if> | |
162 | + colProps: {span: 6}, | |
163 | + }, | |
164 | +</#if> | |
165 | +</#if> | |
166 | +</#list> | |
167 | +<#-- 结束循环 --> | |
168 | +]; | |
169 | +//表单数据 | |
170 | +export const formSchema: FormSchema[] = [ | |
171 | +<#assign form_cat_tree = false> | |
172 | +<#assign form_cat_back = ""> | |
173 | +<#assign bpm_flag=false> | |
174 | +<#list columns as po><#rt/> | |
175 | +<#if po.fieldDbName=='bpm_status'> | |
176 | + <#assign bpm_flag=true> | |
177 | +</#if> | |
178 | +<#if po.isShow =='Y'> | |
179 | +<#assign form_field_dictCode=""> | |
180 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
181 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
182 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
183 | + <#assign form_field_dictCode="${po.dictField}"> | |
184 | + </#if> | |
185 | + { | |
186 | + label: '${po.filedComment}', | |
187 | + field: '${po.fieldName}', | |
188 | + <#if po.classType =='date'> | |
189 | + component: 'DatePicker', | |
190 | + <#elseif po.fieldType =='datetime'> | |
191 | + component: 'DatePicker', | |
192 | + componentProps: { | |
193 | + showTime:true | |
194 | + }, | |
195 | + <#elseif po.fieldType =='time'> | |
196 | + component: 'TimePicker', | |
197 | + <#elseif po.classType =='popup'> | |
198 | + component: 'JPopup', | |
199 | + componentProps: ({ formActionType }) => { | |
200 | + const {setFieldsValue} = formActionType; | |
201 | + return{ | |
202 | + setFieldsValue:setFieldsValue, | |
203 | + code:"${po.dictTable}", | |
204 | + fieldConfig:${po.dictField}, | |
205 | + multi:${po.extendParams.popupMulti?c}, | |
206 | + } | |
207 | + } | |
208 | + <#elseif po.classType =='sel_depart'> | |
209 | + component: 'JSelectDept', | |
210 | + <#elseif po.classType =='switch'> | |
211 | + component: 'JSwitch', | |
212 | + componentProps:{ | |
213 | + <#if po.dictField != 'is_open'> | |
214 | + options:${po.dictField} | |
215 | + </#if> | |
216 | + } | |
217 | + <#elseif po.classType =='pca'> | |
218 | + component: 'JAreaLinkage', | |
219 | + <#elseif po.classType =='markdown'> | |
220 | + component: 'JMarkdownEditor',//注意string转换问题 | |
221 | + <#elseif po.classType =='password'> | |
222 | + component: 'InputPassword', | |
223 | + <#elseif po.classType =='sel_user'> | |
224 | + component: 'JSelectUserByDept', | |
225 | + componentProps:{ | |
226 | + labelKey:'realname', | |
227 | + } | |
228 | + <#elseif po.classType =='textarea'> | |
229 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
230 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
231 | + component: 'JDictSelectTag', | |
232 | + componentProps:{ | |
233 | + dictCode:"${form_field_dictCode}" | |
234 | + } | |
235 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
236 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
237 | + componentProps:{ | |
238 | + dictCode:"${form_field_dictCode}" | |
239 | + } | |
240 | + <#elseif po.classType=='sel_search'> | |
241 | + component: 'JSearchSelect', | |
242 | + componentProps:{ | |
243 | + dict:"${form_field_dictCode}" | |
244 | + } | |
245 | +<#elseif po.classType=='cat_tree'> | |
246 | + <#assign form_cat_tree = true> | |
247 | + component: 'JCategorySelect', | |
248 | + componentProps:{ | |
249 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
250 | + } | |
251 | + <#if po.dictText?default("")?trim?length gt 1> | |
252 | + <#assign form_cat_back = "${po.dictText}"> | |
253 | + </#if> | |
254 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
255 | + component: 'InputNumber', | |
256 | + <#elseif po.classType=='file'> | |
257 | + component: 'JUpload', | |
258 | + componentProps:{ | |
259 | + <#if po.uploadnum??> | |
260 | + maxCount:${po.uploadnum} | |
261 | + </#if> | |
262 | + } | |
263 | + <#elseif po.classType=='image'> | |
264 | + component: 'JImageUpload', | |
265 | + componentProps:{ | |
266 | + <#if po.uploadnum??> | |
267 | + fileMax:${po.uploadnum} | |
268 | + </#if> | |
269 | + } | |
270 | + <#elseif po.classType=='umeditor'> | |
271 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
272 | + <#elseif po.classType == 'sel_tree'> | |
273 | + component: 'JTreeSelect', | |
274 | + componentProps:{ | |
275 | + <#if po.dictText??> | |
276 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
277 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
278 | + <#elseif po.dictText?split(',')[1]??> | |
279 | + pidField:"${po.dictText?split(',')[1]}", | |
280 | + <#elseif po.dictText?split(',')[3]??> | |
281 | + hasChildField:"${po.dictText?split(',')[3]}", | |
282 | + </#if> | |
283 | + </#if> | |
284 | + pidValue:"${po.dictField}", | |
285 | + } | |
286 | + <#else> | |
287 | + component: 'Input', | |
288 | + </#if> | |
289 | + <#include "/common/utils.ftl"> | |
290 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
291 | + dynamicRules: ({model,schema}) => { | |
292 | + <#if po.fieldName != 'id'> | |
293 | + <#assign fieldValidType = po.fieldValidType!''> | |
294 | + return [ | |
295 | + <#-- 非空校验 --> | |
296 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
297 | + { required: true, message: '请输入${po.filedComment}!'}, | |
298 | + <#elseif fieldValidType!=''> | |
299 | + { required: false}, | |
300 | + </#if> | |
301 | + <#-- 唯一校验 --> | |
302 | + <#if fieldValidType == 'only'> | |
303 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
304 | + <#-- 6到16位数字 --> | |
305 | + <#elseif fieldValidType == 'n6-16'> | |
306 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
307 | + <#-- 6到16位任意字符 --> | |
308 | + <#elseif fieldValidType == '*6-16'> | |
309 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
310 | + <#-- 6到18位字符串 --> | |
311 | + <#elseif fieldValidType == 's6-18'> | |
312 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
313 | + <#-- 网址 --> | |
314 | + <#elseif fieldValidType == 'url'> | |
315 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
316 | + <#-- 电子邮件 --> | |
317 | + <#elseif fieldValidType == 'e'> | |
318 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
319 | + <#-- 手机号码 --> | |
320 | + <#elseif fieldValidType == 'm'> | |
321 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
322 | + <#-- 邮政编码 --> | |
323 | + <#elseif fieldValidType == 'p'> | |
324 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
325 | + <#-- 字母 --> | |
326 | + <#elseif fieldValidType == 's'> | |
327 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
328 | + <#-- 数字 --> | |
329 | + <#elseif fieldValidType == 'n'> | |
330 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
331 | + <#-- 整数 --> | |
332 | + <#elseif fieldValidType == 'z'> | |
333 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
334 | + <#-- 金额 --> | |
335 | + <#elseif fieldValidType == 'money'> | |
336 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
337 | + <#-- 正则校验 --> | |
338 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
339 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
340 | + <#-- 无校验 --> | |
341 | + <#else> | |
342 | + <#t> | |
343 | + </#if> | |
344 | + ]; | |
345 | + </#if> | |
346 | + }, | |
347 | + </#if> | |
348 | + <#if po.readonly=='Y'> | |
349 | + dynamicDisabled:true | |
350 | + </#if> | |
351 | + }, | |
352 | +</#if> | |
353 | +</#list> | |
354 | +]; | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |
3 | + <BasicForm @register="registerForm"/> | |
4 | + </BasicModal> | |
5 | +</template> | |
6 | + | |
7 | +<script lang="ts" setup> | |
8 | + import {ref, computed, unref} from 'vue'; | |
9 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
10 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
11 | + import {formSchema} from '../${entityName?uncap_first}.data'; | |
12 | + import {saveOrUpdate} from '../${entityName?uncap_first}.api'; | |
13 | + // Emits声明 | |
14 | + const emit = defineEmits(['register','success']); | |
15 | + const isUpdate = ref(true); | |
16 | + //表单配置 | |
17 | + const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |
18 | + labelWidth: 150, | |
19 | + schemas: formSchema, | |
20 | + showActionButtonGroup: false, | |
21 | + }); | |
22 | + //表单赋值 | |
23 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
24 | + //重置表单 | |
25 | + await resetFields(); | |
26 | + setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter}); | |
27 | + isUpdate.value = !!data?.isUpdate; | |
28 | + if (unref(isUpdate)) { | |
29 | + //表单赋值 | |
30 | + await setFieldsValue({ | |
31 | + ...data.record, | |
32 | + }); | |
33 | + } | |
34 | + // 隐藏底部时禁用整个表单 | |
35 | + setProps({ disabled: !data?.showFooter }) | |
36 | + }); | |
37 | + //设置标题 | |
38 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
39 | + //表单提交事件 | |
40 | + async function handleSubmit(v) { | |
41 | + try { | |
42 | + let values = await validate(); | |
43 | + setModalProps({confirmLoading: true}); | |
44 | + //提交表单 | |
45 | + await saveOrUpdate(values, isUpdate.value); | |
46 | + //关闭弹窗 | |
47 | + closeModal(); | |
48 | + //刷新列表 | |
49 | + emit('success'); | |
50 | + } finally { | |
51 | + setModalProps({confirmLoading: false}); | |
52 | + } | |
53 | + } | |
54 | +</script> | |
55 | + | |
56 | +<style lang="less" scoped> | |
57 | + | |
58 | +</style> | |
0 | 59 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -119,7 +119,7 @@ public class ${entityName}Controller { |
119 | 119 | */ |
120 | 120 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
121 | 121 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
122 | - @PutMapping(value = "/edit") | |
122 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
123 | 123 | public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) { |
124 | 124 | ${entityName} ${entityName?uncap_first} = new ${entityName}(); |
125 | 125 | BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first}); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
... | ... | @@ -28,13 +28,8 @@ |
28 | 28 | <#elseif po.dictField?default("")?trim?length gt 1> |
29 | 29 | <#assign form_field_dictCode="${po.dictField}"> |
30 | 30 | </#if> |
31 | - <#if po.classType =='textarea'> | |
32 | - <a-col :span="24"> | |
33 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
34 | - <#else> | |
35 | 31 | <a-col :span="${form_span}" > |
36 | 32 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
37 | - </#if> | |
38 | 33 | <#if po.classType =='date'> |
39 | 34 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/> |
40 | 35 | <#elseif po.classType =='datetime'> |
... | ... | @@ -140,7 +135,7 @@ |
140 | 135 | </#list> |
141 | 136 | </a-tabs> |
142 | 137 | <#if bpm_flag> |
143 | - <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button @click="handleOk">提 交</a-button></a-row> | |
138 | + <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button icon="check" style="width: 126px" type="primary" @click="handleOk">提 交</a-button></a-row> | |
144 | 139 | </#if> |
145 | 140 | </a-spin> |
146 | 141 | </template> |
... | ... | @@ -171,20 +166,12 @@ |
171 | 166 | return { |
172 | 167 | labelCol: { |
173 | 168 | xs: { span: 24 }, |
174 | - sm: { span: 6 }, | |
169 | + sm: { span: 5 }, | |
175 | 170 | }, |
176 | 171 | wrapperCol: { |
177 | 172 | xs: { span: 24 }, |
178 | 173 | sm: { span: 16 }, |
179 | 174 | }, |
180 | - labelCol2: { | |
181 | - xs: { span: 24 }, | |
182 | - sm: { span: 3 }, | |
183 | - }, | |
184 | - wrapperCol2: { | |
185 | - xs: { span: 24 }, | |
186 | - sm: { span: 20 }, | |
187 | - }, | |
188 | 175 | model:{ |
189 | 176 | <#include "/common/init/initValue.ftl"> |
190 | 177 | }, |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
... | ... | @@ -25,13 +25,8 @@ |
25 | 25 | <#elseif po.dictField?default("")?trim?length gt 1> |
26 | 26 | <#assign form_field_dictCode="${po.dictField}"> |
27 | 27 | </#if> |
28 | - <#if po.classType =='textarea'> | |
29 | - <a-col :span="24"> | |
30 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
31 | - <#else> | |
32 | 28 | <a-col :span="${form_span}"> |
33 | 29 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
34 | - </#if> | |
35 | 30 | <#if po.classType =='date'> |
36 | 31 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%"/> |
37 | 32 | <#elseif po.classType =='datetime'> |
... | ... | @@ -117,20 +112,12 @@ |
117 | 112 | }, |
118 | 113 | labelCol: { |
119 | 114 | xs: { span: 24 }, |
120 | - sm: { span: 6 }, | |
115 | + sm: { span: 5 }, | |
121 | 116 | }, |
122 | 117 | wrapperCol: { |
123 | 118 | xs: { span: 24 }, |
124 | 119 | sm: { span: 16 }, |
125 | 120 | }, |
126 | - labelCol2: { | |
127 | - xs: { span: 24 }, | |
128 | - sm: { span: 3 }, | |
129 | - }, | |
130 | - wrapperCol2: { | |
131 | - xs: { span: 24 }, | |
132 | - sm: { span: 20 }, | |
133 | - }, | |
134 | 121 | <#include "/common/validatorRulesTemplate/sub.ftl"> |
135 | 122 | confirmLoading: false, |
136 | 123 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -158,7 +158,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
158 | 158 | */ |
159 | 159 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
160 | 160 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
161 | - @PutMapping(value = "/edit") | |
161 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
162 | 162 | public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) { |
163 | 163 | ${entityName?uncap_first}Service.update${entityName}(${entityName?uncap_first}); |
164 | 164 | return Result.OK("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div class="p-4"> | |
3 | + <!--引用表格--> | |
4 | + <BasicTable @register="registerTable" :rowSelection="rowSelection" :expandedRowKeys="expandedRowKeys" @expand="handleExpand" @fetch-success="onFetchSuccess"> | |
5 | + <!--插槽:table标题--> | |
6 | + <template #tableTitle> | |
7 | + <a-button type="primary" @click="handleCreate" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
8 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
9 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
10 | + | |
11 | + <a-dropdown v-if="selectedRowKeys.length > 0"> | |
12 | + <template #overlay> | |
13 | + <a-menu> | |
14 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
15 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
16 | + 删除 | |
17 | + </a-menu-item> | |
18 | + </a-menu> | |
19 | + </template> | |
20 | + <a-button>批量操作 | |
21 | + <Icon icon="ant-design:down-outlined"></Icon> | |
22 | + </a-button> | |
23 | + </a-dropdown> | |
24 | + </template> | |
25 | + <!--操作栏--> | |
26 | + <template #action="{ record }"> | |
27 | + <TableAction :actions="getTableAction(record)"/> | |
28 | + </template> | |
29 | + </BasicTable> | |
30 | + <!--字典弹窗--> | |
31 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"/> | |
32 | + </div> | |
33 | +</template> | |
34 | + | |
35 | +<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup> | |
36 | + //ts语法 | |
37 | + import {ref, computed, unref, toRaw, nextTick} from 'vue'; | |
38 | + import {BasicTable, useTable, TableAction} from '/src/components/Table'; | |
39 | + import {useModal} from '/src/components/Modal'; | |
40 | + import { useListPage } from '/@/hooks/system/useListPage' | |
41 | + import ${entityName}Modal from './components/${entityName}Modal.vue'; | |
42 | + import {columns} from './${entityName}.data'; | |
43 | + import {list, delete${entityName}, batchDelete${entityName}, getExportUrl,getImportUrl, getChildList,getChildListBatch} from './${entityName}.api'; | |
44 | + | |
45 | + const expandedRowKeys = ref([]); | |
46 | + //字典model | |
47 | + const [registerModal, {openModal}] = useModal(); | |
48 | + //注册table数据 | |
49 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
50 | + tableProps:{ | |
51 | + title: '${tableVo.ftlDescription}', | |
52 | + columns, | |
53 | + canResize:false, | |
54 | + actionColumn: { | |
55 | + width: 120, | |
56 | + }, | |
57 | + }, | |
58 | + exportConfig: { | |
59 | + name:"${tableVo.ftlDescription}", | |
60 | + url: getExportUrl, | |
61 | + }, | |
62 | + importConfig: { | |
63 | + url: getImportUrl, | |
64 | + success:importSuccess | |
65 | + }, | |
66 | + }) | |
67 | + | |
68 | + const [registerTable, {reload, collapseAll, updateTableDataRecord, findTableDataRecord,getDataSource},{ rowSelection, selectedRowKeys }] = tableContext | |
69 | + | |
70 | + /** | |
71 | + * 新增事件 | |
72 | + */ | |
73 | + function handleCreate() { | |
74 | + openModal(true, { | |
75 | + isUpdate: false, | |
76 | + }); | |
77 | + } | |
78 | + | |
79 | + /** | |
80 | + * 编辑事件 | |
81 | + */ | |
82 | + async function handleEdit(record) { | |
83 | + openModal(true, { | |
84 | + record, | |
85 | + isUpdate: true, | |
86 | + }); | |
87 | + } | |
88 | + | |
89 | + /** | |
90 | + * 详情 | |
91 | + */ | |
92 | + async function handleDetail(record) { | |
93 | + openModal(true, { | |
94 | + record, | |
95 | + isUpdate: true, | |
96 | + hideFooter: true, | |
97 | + }); | |
98 | + } | |
99 | + | |
100 | + /** | |
101 | + * 删除事件 | |
102 | + */ | |
103 | + async function handleDelete(record) { | |
104 | + await delete${entityName}({id: record.id}, importSuccess); | |
105 | + } | |
106 | + | |
107 | + /** | |
108 | + * 批量删除事件 | |
109 | + */ | |
110 | + async function batchHandleDelete() { | |
111 | + const ids = selectedRowKeys.value.filter(item => !item.includes('loading')) | |
112 | + await batchDelete${entityName}({ids: ids}, importSuccess); | |
113 | + } | |
114 | + /** | |
115 | + * 导入 | |
116 | + */ | |
117 | + function importSuccess() { | |
118 | + reload() && (expandedRowKeys.value = []); | |
119 | + } | |
120 | + /** | |
121 | + * 添加下级 | |
122 | + */ | |
123 | + function handleAddSub(record) { | |
124 | + openModal(true, { | |
125 | + record, | |
126 | + isUpdate: false, | |
127 | + }); | |
128 | + } | |
129 | + /** | |
130 | + * 成功回调 | |
131 | + */ | |
132 | + async function handleSuccess({isUpdate, values, expandedArr}) { | |
133 | + if (isUpdate) { | |
134 | + //编辑回调 | |
135 | + updateTableDataRecord(values.id, values); | |
136 | + } else { | |
137 | + if(!values['pid']){ | |
138 | + //新增根节点 | |
139 | + reload(); | |
140 | + }else{ | |
141 | + //新增子集 | |
142 | + expandedRowKeys.value = []; | |
143 | + for (let key of unref(expandedArr)) { | |
144 | + await expandTreeNode(key) | |
145 | + } | |
146 | + } | |
147 | + } | |
148 | + } | |
149 | + | |
150 | + /** | |
151 | + * 接口请求成功后回调 | |
152 | + */ | |
153 | + function onFetchSuccess(result) { | |
154 | + getDataByResult(result.items)&&loadDataByExpandedRows(); | |
155 | + } | |
156 | + /** | |
157 | + * 根据已展开的行查询数据(用于保存后刷新时异步加载子级的数据) | |
158 | + */ | |
159 | + async function loadDataByExpandedRows() { | |
160 | + if (unref(expandedRowKeys).length > 0) { | |
161 | + const res = await getChildListBatch({ parentIds: unref(expandedRowKeys).join(',')}); | |
162 | + if (res.success && res.result.records.length>0) { | |
163 | + //已展开的数据批量子节点 | |
164 | + let records = res.result.records | |
165 | + const listMap = new Map(); | |
166 | + for (let item of records) { | |
167 | + let pid = item['pid']; | |
168 | + if (unref(expandedRowKeys).includes(pid)) { | |
169 | + let mapList = listMap.get(pid); | |
170 | + if (mapList == null) { | |
171 | + mapList = []; | |
172 | + } | |
173 | + mapList.push(item); | |
174 | + listMap.set(pid, mapList); | |
175 | + } | |
176 | + } | |
177 | + let childrenMap = listMap; | |
178 | + let fn = (list) => { | |
179 | + if(list) { | |
180 | + list.forEach(data => { | |
181 | + if (unref(expandedRowKeys).includes(data.id)) { | |
182 | + data.children = getDataByResult(childrenMap.get(data.id)) | |
183 | + fn(data.children) | |
184 | + } | |
185 | + }) | |
186 | + } | |
187 | + }; | |
188 | + fn(getDataSource()) | |
189 | + } | |
190 | + } | |
191 | + } | |
192 | + /** | |
193 | + * 处理数据集 | |
194 | + */ | |
195 | + function getDataByResult(result){ | |
196 | + if(result && result.length>0){ | |
197 | + return result.map(item=>{ | |
198 | + //判断是否标记了带有子节点 | |
199 | + if(item["hasChild"]=='1'){ | |
200 | + let loadChild = { id: item.id+'_loadChild', name: 'loading...', isLoading: true } | |
201 | + item.children = [loadChild] | |
202 | + } | |
203 | + return item | |
204 | + }) | |
205 | + } | |
206 | + } | |
207 | + /** | |
208 | + *树节点展开合并 | |
209 | + * */ | |
210 | + async function handleExpand(expanded, record) { | |
211 | + // 判断是否是展开状态,展开状态(expanded)并且存在子集(children)并且未加载过(isLoading)的就去查询子节点数据 | |
212 | + if (expanded) { | |
213 | + expandedRowKeys.value.push(record.id) | |
214 | + if (record.children.length > 0 && !!record.children[0].isLoading) { | |
215 | + let result = await getChildList({pid: record.id}); | |
216 | + result=result.records?result.records:result; | |
217 | + if (result && result.length > 0) { | |
218 | + record.children = getDataByResult(result); | |
219 | + } else { | |
220 | + record.children = null | |
221 | + record.hasChild = '0' | |
222 | + } | |
223 | + } | |
224 | + } else { | |
225 | + let keyIndex = expandedRowKeys.value.indexOf(record.id) | |
226 | + if (keyIndex >= 0) { | |
227 | + expandedRowKeys.value.splice(keyIndex, 1); | |
228 | + } | |
229 | + } | |
230 | + } | |
231 | + /** | |
232 | + *操作表格后处理树节点展开合并 | |
233 | + * */ | |
234 | + async function expandTreeNode(key) { | |
235 | + let record = findTableDataRecord(key) | |
236 | + expandedRowKeys.value.push(key); | |
237 | + let result = await getChildList({pid: key}); | |
238 | + if (result && result.length > 0) { | |
239 | + record.children = getDataByResult(result); | |
240 | + } else { | |
241 | + record.children = null | |
242 | + record.hasChild = '0' | |
243 | + } | |
244 | + updateTableDataRecord(key, record); | |
245 | + } | |
246 | + /** | |
247 | + * 操作栏 | |
248 | + */ | |
249 | + function getTableAction(record) { | |
250 | + return [ | |
251 | + { | |
252 | + label: '编辑', | |
253 | + onClick: handleEdit.bind(null, record), | |
254 | + }, | |
255 | + { | |
256 | + label: '删除', | |
257 | + popConfirm: { | |
258 | + title: '确定删除吗?', | |
259 | + confirm: handleDelete.bind(null, record), | |
260 | + }, | |
261 | + }, | |
262 | + { | |
263 | + label: '添加下级', | |
264 | + onClick: handleAddSub.bind(null, {pid: record.id}), | |
265 | + } | |
266 | + ] | |
267 | + } | |
268 | +</script> | |
269 | + | |
270 | +<style scoped> | |
271 | + | |
272 | +</style> | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from "/@/utils/http/axios"; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/rootList', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + delete${entityName} = '/sys/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | + loadTreeData = '/${entityPackage}/${entityName?uncap_first}/loadTreeRoot', | |
13 | + getChildList = '/${entityPackage}/${entityName?uncap_first}/childList', | |
14 | + getChildListBatch = '/${entityPackage}/${entityName?uncap_first}/getChildListBatch', | |
15 | +} | |
16 | +/** | |
17 | + * 导出api | |
18 | + * @param params | |
19 | + */ | |
20 | +export const getExportUrl = Api.exportXls; | |
21 | +/** | |
22 | + * 导入api | |
23 | + * @param params | |
24 | + */ | |
25 | +export const getImportUrl = Api.importExcel; | |
26 | +/** | |
27 | + * 列表接口 | |
28 | + * @param params | |
29 | + */ | |
30 | +export const list = (params) => | |
31 | + defHttp.get({url: Api.list, params}); | |
32 | +/** | |
33 | + * 删除 | |
34 | + */ | |
35 | +export const delete${entityName} = (params,handleSuccess) => { | |
36 | + return defHttp.delete({url: Api.delete${entityName}, params}, {joinParamsToUrl: true}).then(() => { | |
37 | + handleSuccess(); | |
38 | + }); | |
39 | +} | |
40 | +/** | |
41 | + * 批量删除 | |
42 | + * @param params | |
43 | + */ | |
44 | +export const batchDelete${entityName} = (params, handleSuccess) => { | |
45 | + Modal.confirm({ | |
46 | + title: '确认删除', | |
47 | + content: '是否删除选中数据', | |
48 | + okText: '确认', | |
49 | + cancelText: '取消', | |
50 | + onOk: () => { | |
51 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
52 | + handleSuccess(); | |
53 | + }); | |
54 | + } | |
55 | + }); | |
56 | +} | |
57 | +/** | |
58 | + * 保存或者更新 | |
59 | + * @param params | |
60 | + */ | |
61 | +export const saveOrUpdateDict = (params, isUpdate) => { | |
62 | + let url = isUpdate ? Api.edit : Api.save; | |
63 | + return defHttp.post({url: url, params}); | |
64 | +} | |
65 | +/** | |
66 | + * 查询全部树形节点数据 | |
67 | + * @param params | |
68 | + */ | |
69 | +export const loadTreeData = (params) => | |
70 | + defHttp.get({url: Api.loadTreeData,params}); | |
71 | +/** | |
72 | + * 查询子节点数据 | |
73 | + * @param params | |
74 | + */ | |
75 | +export const getChildList = (params) => | |
76 | + defHttp.get({url: Api.getChildList, params}); | |
77 | +/** | |
78 | + * 批量查询子节点数据 | |
79 | + * @param params | |
80 | + */ | |
81 | +export const getChildListBatch = (params) => | |
82 | + defHttp.get({url: Api.getChildListBatch, params},{isTransformResponse:false}); | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +//列表数据 | |
6 | +export const columns: BasicColumn[] = [ | |
7 | + <#list columns as po> | |
8 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
9 | + { | |
10 | + title: '${po.filedComment}', | |
11 | + align:"center", | |
12 | + <#if po.sort=='Y'> | |
13 | + sorter: true, | |
14 | + </#if> | |
15 | + <#if po.classType=='date'> | |
16 | + dataIndex: '${po.fieldName}', | |
17 | + customRender:({text}) =>{ | |
18 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
19 | + }, | |
20 | + <#elseif po.fieldDbType=='Blob'> | |
21 | + dataIndex: '${po.fieldName}String' | |
22 | + <#elseif po.classType=='umeditor'> | |
23 | + dataIndex: '${po.fieldName}', | |
24 | + slots: { customRender: 'htmlSlot' }, | |
25 | + <#elseif po.classType=='pca'> | |
26 | + dataIndex: '${po.fieldName}', | |
27 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
28 | + <#elseif po.classType=='file'> | |
29 | + dataIndex: '${po.fieldName}', | |
30 | + slots: { customRender: 'fileSlot' }, | |
31 | + <#elseif po.classType=='image'> | |
32 | + dataIndex: '${po.fieldName}', | |
33 | + customRender:render.renderAvatar, | |
34 | + <#elseif po.classType=='switch'> | |
35 | + dataIndex: '${po.fieldName}', | |
36 | +<#assign switch_extend_arr=['Y','N']> | |
37 | +<#if po.dictField?default("")?contains("[")> | |
38 | +<#assign switch_extend_arr=po.dictField?eval> | |
39 | +</#if> | |
40 | +<#list switch_extend_arr as a> | |
41 | +<#if a_index == 0> | |
42 | +<#assign switch_extend_arr1=a> | |
43 | +<#else> | |
44 | +<#assign switch_extend_arr2=a> | |
45 | +</#if> | |
46 | +</#list> | |
47 | + customRender:({text}) => { | |
48 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
49 | + }, | |
50 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
51 | + dataIndex: '${po.fieldName}_dictText' | |
52 | + <#elseif po.classType=='cat_tree'> | |
53 | + dataIndex: '${po.fieldName}', | |
54 | + <#if po.dictText?default("")?trim?length == 0> | |
55 | + customRender:({text}) => { | |
56 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
57 | + }, | |
58 | + <#else> | |
59 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
60 | + </#if> | |
61 | + <#else> | |
62 | + dataIndex: '${po.fieldName}' | |
63 | + </#if> | |
64 | + }, | |
65 | + </#if> | |
66 | + </#list> | |
67 | +]; | |
68 | +//查询数据 | |
69 | +export const searchFormSchema: FormSchema[] = [ | |
70 | +<#-- 开始循环 --> | |
71 | +<#list columns as po> | |
72 | +<#if po.fieldDbName=='bpm_status'> | |
73 | + <#assign bpm_flag=true> | |
74 | +</#if> | |
75 | +<#if po.isQuery=='Y'> | |
76 | +<#assign query_flag=true> | |
77 | + <#assign query_field_dictCode=""> | |
78 | + <#if po.dictTable?default("")?trim?length gt 1> | |
79 | + <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
80 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
81 | + <#assign query_field_dictCode="${po.dictField}"> | |
82 | + </#if> | |
83 | +<#if po.queryMode=='single'> | |
84 | + { | |
85 | + label: "${po.filedComment}", | |
86 | + field: "${po.fieldName}", | |
87 | +<#if po.classType=='sel_search'> | |
88 | + component: 'JSearchSelect', | |
89 | + componentProps:{ | |
90 | + dict:"${po.dictTable},${po.dictText},${po.dictField}" | |
91 | + }, | |
92 | +<#elseif po.classType=='sel_user'> | |
93 | + component: 'JSelectUserByDept', | |
94 | +<#elseif po.classType=='switch'> | |
95 | + component: 'JSwitch', | |
96 | + componentProps:{ | |
97 | + <#if po.dictField != 'is_open'> | |
98 | + options:"${po.dictField}" | |
99 | + </#if> | |
100 | + }, | |
101 | + <#elseif po.classType=='sel_depart'> | |
102 | + component: 'JSelectDept', | |
103 | + <#elseif po.classType=='list_multi'> | |
104 | + component: 'JMultiSelectTag',//暂无该组件 | |
105 | + componentProps:{ | |
106 | + dictCode:"query_field_dictCode?default("")" | |
107 | + }, | |
108 | + <#elseif po.classType=='cat_tree'> | |
109 | + component: 'JCategorySelect', | |
110 | + componentProps:{ | |
111 | + pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题 | |
112 | + }, | |
113 | +<#elseif po.classType=='date'> | |
114 | + component: 'DatePicker', | |
115 | +<#elseif po.classType=='datetime'> | |
116 | + component: 'DatePicker', | |
117 | + componentProps: { | |
118 | + showTime:true | |
119 | + }, | |
120 | +<#elseif po.classType=='pca'> | |
121 | + component: 'JAreaLinkage', | |
122 | +<#elseif po.classType=='popup'> | |
123 | + component: 'JPopup', | |
124 | + componentProps: ({ formActionType }) => { | |
125 | + const {setFieldsValue} = formActionType; | |
126 | + return{ | |
127 | + setFieldsValue:setFieldsValue, | |
128 | + code:"${po.dictTable}", | |
129 | + fieldConfig:"${po.dictField}", | |
130 | + multi:${po.extendParams.popupMulti?c}, | |
131 | + } | |
132 | + }, | |
133 | +<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'> | |
134 | +<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- --> | |
135 | + component: 'JDictSelectTag', | |
136 | + componentProps:{ | |
137 | + <#if po.dictTable?default("")?trim?length gt 1> | |
138 | + dictCode:"${po.dictTable},${po.dictText},${po.dictField}" | |
139 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
140 | + dictCode:"${po.dictField}" | |
141 | + </#if> | |
142 | + }, | |
143 | +<#else> | |
144 | + component: 'Input', | |
145 | +</#if> | |
146 | + colProps: {span: 6}, | |
147 | + }, | |
148 | +<#else> | |
149 | + { | |
150 | + label: "${po.filedComment}", | |
151 | + field: "${po.fieldName}", | |
152 | +<#if po.classType=='date'> | |
153 | + component: 'RangePicker', | |
154 | +<#elseif po.classType=='datetime'> | |
155 | + component: 'RangePicker', | |
156 | + componentProps: { | |
157 | + showTime:true | |
158 | + }, | |
159 | +<#else> | |
160 | + component: 'Input', //TODO 范围查询 | |
161 | +</#if> | |
162 | + colProps: {span: 6}, | |
163 | + }, | |
164 | +</#if> | |
165 | +</#if> | |
166 | +</#list> | |
167 | +<#-- 结束循环 --> | |
168 | +]; | |
169 | +//表单数据 | |
170 | +export const formSchema: FormSchema[] = [ | |
171 | +<#assign form_cat_tree = false> | |
172 | +<#assign form_cat_back = ""> | |
173 | +<#assign bpm_flag=false> | |
174 | +<#list columns as po><#rt/> | |
175 | +<#if po.fieldDbName=='bpm_status'> | |
176 | + <#assign bpm_flag=true> | |
177 | +</#if> | |
178 | +<#if po.isShow =='Y'> | |
179 | +<#assign form_field_dictCode=""> | |
180 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
181 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
182 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
183 | + <#assign form_field_dictCode="${po.dictField}"> | |
184 | + </#if> | |
185 | + { | |
186 | + label: '${po.filedComment}', | |
187 | + field: '${po.fieldName}', | |
188 | + <#if po.classType =='date'> | |
189 | + component: 'DatePicker', | |
190 | + <#elseif po.fieldType =='datetime'> | |
191 | + component: 'DatePicker', | |
192 | + componentProps: { | |
193 | + showTime:true | |
194 | + }, | |
195 | + <#elseif po.fieldType =='time'> | |
196 | + component: 'TimePicker', | |
197 | + <#elseif po.classType =='popup'> | |
198 | + component: 'JPopup', | |
199 | + componentProps: ({ formActionType }) => { | |
200 | + const {setFieldsValue} = formActionType; | |
201 | + return{ | |
202 | + setFieldsValue:setFieldsValue, | |
203 | + code:"${po.dictTable}", | |
204 | + fieldConfig:${po.dictField}, | |
205 | + multi:${po.extendParams.popupMulti?c}, | |
206 | + } | |
207 | + } | |
208 | + <#elseif po.classType =='sel_depart'> | |
209 | + component: 'JSelectDept', | |
210 | + <#elseif po.classType =='switch'> | |
211 | + component: 'JSwitch', | |
212 | + componentProps:{ | |
213 | + <#if po.dictField != 'is_open'> | |
214 | + options:${po.dictField} | |
215 | + </#if> | |
216 | + } | |
217 | + <#elseif po.classType =='pca'> | |
218 | + component: 'JAreaLinkage', | |
219 | + <#elseif po.classType =='markdown'> | |
220 | + component: 'JMarkdownEditor',//注意string转换问题 | |
221 | + <#elseif po.classType =='password'> | |
222 | + component: 'InputPassword', | |
223 | + <#elseif po.classType =='sel_user'> | |
224 | + component: 'JSelectUserByDept', | |
225 | + componentProps:{ | |
226 | + labelKey:'realname', | |
227 | + } | |
228 | + <#elseif po.classType =='textarea'> | |
229 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
230 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
231 | + component: 'JDictSelectTag', | |
232 | + componentProps:{ | |
233 | + dictCode:"${form_field_dictCode}" | |
234 | + } | |
235 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
236 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
237 | + componentProps:{ | |
238 | + dictCode:"${form_field_dictCode}" | |
239 | + } | |
240 | + <#elseif po.classType=='sel_search'> | |
241 | + component: 'JSearchSelect', | |
242 | + componentProps:{ | |
243 | + dict:"${form_field_dictCode}" | |
244 | + } | |
245 | +<#elseif po.classType=='cat_tree'> | |
246 | + <#assign form_cat_tree = true> | |
247 | + component: 'JCategorySelect', | |
248 | + componentProps:{ | |
249 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
250 | + } | |
251 | + <#if po.dictText?default("")?trim?length gt 1> | |
252 | + <#assign form_cat_back = "${po.dictText}"> | |
253 | + </#if> | |
254 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
255 | + component: 'InputNumber', | |
256 | + <#elseif po.classType=='file'> | |
257 | + component: 'JUpload', | |
258 | + componentProps:{ | |
259 | + <#if po.uploadnum??> | |
260 | + maxCount:${po.uploadnum} | |
261 | + </#if> | |
262 | + } | |
263 | + <#elseif po.classType=='image'> | |
264 | + component: 'JImageUpload', | |
265 | + componentProps:{ | |
266 | + <#if po.uploadnum??> | |
267 | + fileMax:${po.uploadnum} | |
268 | + </#if> | |
269 | + } | |
270 | + <#elseif po.classType=='umeditor'> | |
271 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
272 | + <#elseif po.classType == 'sel_tree'> | |
273 | + component: 'JTreeSelect', | |
274 | + componentProps:{ | |
275 | + <#if po.dictText??> | |
276 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
277 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
278 | + <#elseif po.dictText?split(',')[1]??> | |
279 | + pidField:"${po.dictText?split(',')[1]}", | |
280 | + <#elseif po.dictText?split(',')[3]??> | |
281 | + hasChildField:"${po.dictText?split(',')[3]}", | |
282 | + </#if> | |
283 | + </#if> | |
284 | + pidValue:"${po.dictField}", | |
285 | + } | |
286 | + <#else> | |
287 | + component: 'Input', | |
288 | + </#if> | |
289 | + <#include "/common/utils.ftl"> | |
290 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
291 | + dynamicRules: ({model,schema}) => { | |
292 | + <#if po.fieldName != 'id'> | |
293 | + <#assign fieldValidType = po.fieldValidType!''> | |
294 | + return [ | |
295 | + <#-- 非空校验 --> | |
296 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
297 | + { required: true, message: '请输入${po.filedComment}!'}, | |
298 | + <#elseif fieldValidType!=''> | |
299 | + { required: false}, | |
300 | + </#if> | |
301 | + <#-- 唯一校验 --> | |
302 | + <#if fieldValidType == 'only'> | |
303 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
304 | + <#-- 6到16位数字 --> | |
305 | + <#elseif fieldValidType == 'n6-16'> | |
306 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
307 | + <#-- 6到16位任意字符 --> | |
308 | + <#elseif fieldValidType == '*6-16'> | |
309 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
310 | + <#-- 6到18位字符串 --> | |
311 | + <#elseif fieldValidType == 's6-18'> | |
312 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
313 | + <#-- 网址 --> | |
314 | + <#elseif fieldValidType == 'url'> | |
315 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
316 | + <#-- 电子邮件 --> | |
317 | + <#elseif fieldValidType == 'e'> | |
318 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
319 | + <#-- 手机号码 --> | |
320 | + <#elseif fieldValidType == 'm'> | |
321 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
322 | + <#-- 邮政编码 --> | |
323 | + <#elseif fieldValidType == 'p'> | |
324 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
325 | + <#-- 字母 --> | |
326 | + <#elseif fieldValidType == 's'> | |
327 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
328 | + <#-- 数字 --> | |
329 | + <#elseif fieldValidType == 'n'> | |
330 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
331 | + <#-- 整数 --> | |
332 | + <#elseif fieldValidType == 'z'> | |
333 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
334 | + <#-- 金额 --> | |
335 | + <#elseif fieldValidType == 'money'> | |
336 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
337 | + <#-- 正则校验 --> | |
338 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
339 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
340 | + <#-- 无校验 --> | |
341 | + <#else> | |
342 | + <#t> | |
343 | + </#if> | |
344 | + ]; | |
345 | + </#if> | |
346 | + }, | |
347 | + </#if> | |
348 | + <#if po.readonly=='Y'> | |
349 | + dynamicDisabled:true | |
350 | + </#if> | |
351 | + }, | |
352 | +</#if> | |
353 | +</#list> | |
354 | +]; | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit"> | |
3 | + <BasicForm @register="registerForm"/> | |
4 | + </BasicModal> | |
5 | +</template> | |
6 | +<script lang="ts" setup> | |
7 | + import {ref, computed, unref} from 'vue'; | |
8 | + import {BasicModal, useModalInner} from '/src/components/Modal'; | |
9 | + import {BasicForm, useForm} from '/src/components/Form'; | |
10 | + import {formSchema} from '../${entityName?uncap_first}.data'; | |
11 | + import {loadTreeData, saveOrUpdateDict} from '../${entityName?uncap_first}.api'; | |
12 | + // 获取emit | |
13 | + const emit = defineEmits(['register', 'success']); | |
14 | + const isUpdate = ref(true); | |
15 | + const expandedRowKeys = ref([]); | |
16 | + const treeData = ref([]); | |
17 | + //表单配置 | |
18 | + const [registerForm, {resetFields, setFieldsValue, validate, updateSchema}] = useForm({ | |
19 | + schemas: formSchema, | |
20 | + showActionButtonGroup: false, | |
21 | + labelCol: { | |
22 | + xs: { span: 24 }, | |
23 | + sm: { span: 4 }, | |
24 | + }, | |
25 | + wrapperCol: { | |
26 | + xs: { span: 24 }, | |
27 | + sm: { span: 18 }, | |
28 | + }, | |
29 | + }); | |
30 | + //表单赋值 | |
31 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
32 | + //重置表单 | |
33 | + await resetFields(); | |
34 | + expandedRowKeys.value = []; | |
35 | + setModalProps({confirmLoading: false, minHeight: 80}); | |
36 | + isUpdate.value = !!data?.isUpdate; | |
37 | + if (data?.record) { | |
38 | + //表单赋值 | |
39 | + await setFieldsValue({ | |
40 | + ...data.record, | |
41 | + }); | |
42 | + } | |
43 | + //父级节点树信息 | |
44 | + treeData.value = await loadTreeData({'async': false,'pcode':''}); | |
45 | + updateSchema({ | |
46 | + field: 'pid', | |
47 | + componentProps: {treeData}, | |
48 | + }); | |
49 | + }); | |
50 | + //设置标题 | |
51 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增字典' : '编辑字典')); | |
52 | + | |
53 | + /** | |
54 | + * 根据pid获取展开的节点 | |
55 | + * @param pid | |
56 | + * @param arr | |
57 | + */ | |
58 | + function getExpandKeysByPid(pid,arr){ | |
59 | + if(pid && arr && arr.length>0){ | |
60 | + for(let i=0;i<arr.length;i++){ | |
61 | + if(arr[i].key==pid && unref(expandedRowKeys).indexOf(pid)<0){ | |
62 | + expandedRowKeys.value.push(arr[i].key); | |
63 | + getExpandKeysByPid(arr[i]['parentId'],unref(treeData)) | |
64 | + }else{ | |
65 | + getExpandKeysByPid(pid,arr[i].children) | |
66 | + } | |
67 | + } | |
68 | + } | |
69 | + } | |
70 | + //表单提交事件 | |
71 | + async function handleSubmit() { | |
72 | + try { | |
73 | + let values = await validate(); | |
74 | + setModalProps({confirmLoading: true}); | |
75 | + //提交表单 | |
76 | + await saveOrUpdateDict(values, isUpdate.value); | |
77 | + //关闭弹窗 | |
78 | + closeModal(); | |
79 | + //展开的节点信息 | |
80 | + await getExpandKeysByPid(values['pid'],unref(treeData)) | |
81 | + //刷新列表(isUpdate:是否编辑;values:表单信息;expandedArr:展开的节点信息) | |
82 | + emit('success', {isUpdate: unref(isUpdate), values:{...values},expandedArr: unref(expandedRowKeys).reverse()}); | |
83 | + } finally { | |
84 | + setModalProps({confirmLoading: false}); | |
85 | + } | |
86 | + } | |
87 | +</script> | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -103,7 +103,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
103 | 103 | */ |
104 | 104 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
105 | 105 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
106 | - @PutMapping(value = "/edit") | |
106 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
107 | 107 | public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) { |
108 | 108 | ${entityName?uncap_first}Service.updateById(${entityName?uncap_first}); |
109 | 109 | return Result.OK("编辑成功!"); |
... | ... | @@ -194,7 +194,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
194 | 194 | */ |
195 | 195 | @AutoLog(value = "${sub.ftlDescription}-编辑") |
196 | 196 | @ApiOperation(value="${sub.ftlDescription}-编辑", notes="${sub.ftlDescription}-编辑") |
197 | - @PutMapping(value = "/edit${sub.entityName}") | |
197 | + @RequestMapping(value = "/edit${sub.entityName}", method = {RequestMethod.PUT,RequestMethod.POST}) | |
198 | 198 | public Result<?> edit${sub.entityName}(@RequestBody ${sub.entityName} ${sub.entityName?uncap_first}) { |
199 | 199 | ${sub.entityName?uncap_first}Service.updateById(${sub.entityName?uncap_first}); |
200 | 200 | return Result.OK("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
... | ... | @@ -371,7 +371,7 @@ |
371 | 371 | this.$set(this.dictOptions, '${po.fieldName}', res.result) |
372 | 372 | } |
373 | 373 | }) |
374 | - <#elseif po.classType=='sel_search' || po.classType=='list_multi' || po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'> | |
374 | + <#elseif po.classType=='radio' || po.classType=='checkbox'> | |
375 | 375 | <#assign list_field_dictCode=""> |
376 | 376 | <#if po.dictTable?default("")?trim?length gt 1> |
377 | 377 | <#assign list_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/[1-n]List.vuei
... | ... | @@ -15,8 +15,6 @@ |
15 | 15 | @change="handleImportExcel"> |
16 | 16 | <a-button type="primary" icon="import">导入</a-button> |
17 | 17 | </a-upload> |
18 | - <!-- 高级查询区域 --> | |
19 | - <j-super-query :fieldList="superFieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query> | |
20 | 18 | <a-dropdown v-if="selectedRowKeys.length > 0"> |
21 | 19 | <a-menu slot="overlay"> |
22 | 20 | <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item> |
... | ... | @@ -192,12 +190,10 @@ |
192 | 190 | </#if> |
193 | 191 | </#if> |
194 | 192 | </#list> |
195 | - }, | |
196 | - superFieldList:[], | |
193 | + } | |
197 | 194 | } |
198 | 195 | }, |
199 | 196 | created() { |
200 | - this.getSuperFieldList(); | |
201 | 197 | }, |
202 | 198 | computed: { |
203 | 199 | importExcelUrl(){ |
... | ... | @@ -209,15 +205,8 @@ |
209 | 205 | this.dataSource=[] |
210 | 206 | this.selectedRowKeys=[] |
211 | 207 | this.ipagination.current = 1 |
212 | - }, | |
213 | - getSuperFieldList(){ | |
214 | - <#include "/common/utils.ftl"> | |
215 | - let fieldList=[]; | |
216 | - <#list columns as po> | |
217 | - fieldList.push(${superQueryFieldList(po)}) | |
218 | - </#list> | |
219 | - this.superFieldList = fieldList | |
220 | 208 | } |
209 | + | |
221 | 210 | } |
222 | 211 | } |
223 | 212 | </script> |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | +<#assign list_need_category=false> | |
4 | +<#assign list_need_pca=false> | |
5 | +<#assign bpm_flag=false> | |
6 | + | |
7 | +<#-- 开始循环 --> | |
8 | +<#list columns as po> | |
9 | +<#if po.fieldDbName=='bpm_status'> | |
10 | + <#assign bpm_flag=true> | |
11 | +</#if> | |
12 | +<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0> | |
13 | +<#assign list_need_category=true> | |
14 | +</#if> | |
15 | +<#if po.classType=='pca'> | |
16 | +<#assign list_need_pca=true> | |
17 | +</#if> | |
18 | +</#list> | |
19 | +<#-- 结束循环 --> | |
20 | + <!--引用表格--> | |
21 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
22 | + <!--插槽:table标题--> | |
23 | + <template #tableTitle> | |
24 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
25 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
26 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
27 | + <a-dropdown v-if="selectedRowKeys.length > 0"> | |
28 | + <template #overlay> | |
29 | + <a-menu> | |
30 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
31 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
32 | + 删除 | |
33 | + </a-menu-item> | |
34 | + </a-menu> | |
35 | + </template> | |
36 | + <a-button>批量操作 | |
37 | + <Icon icon="mdi:chevron-down"></Icon> | |
38 | + </a-button> | |
39 | + </a-dropdown> | |
40 | + </template> | |
41 | + <!--操作栏--> | |
42 | + <template #action="{ record }"> | |
43 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
44 | + </template> | |
45 | + <!--字段回显插槽--> | |
46 | + <template #htmlSlot="{text}"> | |
47 | + <div v-html="text"></div> | |
48 | + </template> | |
49 | + <template #fileSlot="{text}"> | |
50 | + <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |
51 | + <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |
52 | + </template> | |
53 | + </BasicTable> | |
54 | + <!--子表表格tab--> | |
55 | + <a-tabs defaultActiveKey="1"> | |
56 | + <#assign sub_seq=1> | |
57 | + <#list subTables as sub> | |
58 | + <a-tab-pane tab="${sub.ftlDescription}" key="${sub_seq}" <#if sub_seq gt 1>forceRender</#if>> | |
59 | + <${sub.entityName}List/> | |
60 | + </a-tab-pane> | |
61 | + <#assign sub_seq=sub_seq+1> | |
62 | + </#list> | |
63 | + </a-tabs> | |
64 | + <!-- 表单区域 --> | |
65 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
66 | + </div> | |
67 | +</template> | |
68 | + | |
69 | +<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup> | |
70 | + import {ref, computed, unref,provide} from 'vue'; | |
71 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
72 | + import { useListPage } from '/@/hooks/system/useListPage' | |
73 | + import {useModal} from '/@/components/Modal'; | |
74 | + import ${entityName}Modal from './components/${entityName}Modal.vue' | |
75 | +<#list subTables as sub> | |
76 | + import ${sub.entityName}List from './${sub.entityName}List.vue' | |
77 | +</#list> | |
78 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
79 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
80 | + <#if list_need_category> | |
81 | + import { loadCategoryData } from '/@/api/common/api' | |
82 | + import { getAuthCache, setAuthCache } from '/@/utils/auth'; | |
83 | + import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum'; | |
84 | + </#if> | |
85 | + //注册model | |
86 | + const [registerModal, {openModal}] = useModal(); | |
87 | + //注册table数据 | |
88 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
89 | + tableProps:{ | |
90 | + title: '${tableVo.ftlDescription}', | |
91 | + api: list, | |
92 | + columns, | |
93 | + canResize:false, | |
94 | + rowSelection: {type: 'radio'}, | |
95 | + formConfig: { | |
96 | + schemas: searchFormSchema, | |
97 | + fieldMapToTime: [ | |
98 | + <#list columns as po> | |
99 | + <#if po.isQuery=='Y'> | |
100 | + <#if po.queryMode!='single'> | |
101 | + <#if po.classType=='date'> | |
102 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'], | |
103 | + <#elseif po.classType=='datetime'> | |
104 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'], | |
105 | + </#if> | |
106 | + </#if> | |
107 | + </#if> | |
108 | + </#list> | |
109 | + ], | |
110 | + }, | |
111 | + actionColumn: { | |
112 | + width: 120, | |
113 | + }, | |
114 | + pagination:{ | |
115 | + current: 1, | |
116 | + pageSize: 5, | |
117 | + pageSizeOptions: ['5', '10', '20'], | |
118 | + } | |
119 | + }, | |
120 | + exportConfig: { | |
121 | + name:"${tableVo.ftlDescription}", | |
122 | + url: getExportUrl, | |
123 | + }, | |
124 | + importConfig: { | |
125 | + url: getImportUrl | |
126 | + }, | |
127 | + }) | |
128 | + | |
129 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
130 | + | |
131 | + const mainId = computed(() => (unref(selectedRowKeys).length > 0 ? unref(selectedRowKeys)[0] : '')); | |
132 | + //下发 mainId,子组件接收 | |
133 | + provide('mainId', mainId); | |
134 | + /** | |
135 | + * 新增事件 | |
136 | + */ | |
137 | + function handleAdd() { | |
138 | + openModal(true, { | |
139 | + isUpdate: false, | |
140 | + showFooter: true, | |
141 | + }); | |
142 | + } | |
143 | + /** | |
144 | + * 编辑事件 | |
145 | + */ | |
146 | + function handleEdit(record: Recordable) { | |
147 | + openModal(true, { | |
148 | + record, | |
149 | + isUpdate: true, | |
150 | + showFooter: true, | |
151 | + }); | |
152 | + } | |
153 | + /** | |
154 | + * 详情 | |
155 | + */ | |
156 | + function handleDetail(record: Recordable) { | |
157 | + openModal(true, { | |
158 | + record, | |
159 | + isUpdate: true, | |
160 | + showFooter: false, | |
161 | + }); | |
162 | + } | |
163 | + /** | |
164 | + * 删除事件 | |
165 | + */ | |
166 | + async function handleDelete(record) { | |
167 | + await deleteOne({id: record.id}, reload); | |
168 | + } | |
169 | + /** | |
170 | + * 批量删除事件 | |
171 | + */ | |
172 | + async function batchHandleDelete() { | |
173 | + await batchDelete({ids: selectedRowKeys.value}, reload); | |
174 | + } | |
175 | + /** | |
176 | + * 成功回调 | |
177 | + */ | |
178 | + function handleSuccess() { | |
179 | + reload(); | |
180 | + } | |
181 | + /** | |
182 | + * 操作栏 | |
183 | + */ | |
184 | + function getTableAction(record){ | |
185 | + return [ | |
186 | + { | |
187 | + label: '编辑', | |
188 | + onClick: handleEdit.bind(null, record), | |
189 | + } | |
190 | + ] | |
191 | + } | |
192 | + /** | |
193 | + * 下拉操作栏 | |
194 | + */ | |
195 | + function getDropDownAction(record){ | |
196 | + return [ | |
197 | + { | |
198 | + label: '详情', | |
199 | + onClick: handleDetail.bind(null, record), | |
200 | + }, { | |
201 | + label: '删除', | |
202 | + popConfirm: { | |
203 | + title: '是否确认删除', | |
204 | + confirm: handleDelete.bind(null, record), | |
205 | + } | |
206 | + } | |
207 | + ] | |
208 | + } | |
209 | + <#if list_need_category> | |
210 | + /** | |
211 | + * 初始化字典配置 | |
212 | + */ | |
213 | + function initDictConfig(){ | |
214 | + <#list columns as po> | |
215 | + <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'> | |
216 | + <#if po.classType=='cat_tree' && list_need_category==true> | |
217 | + loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => { | |
218 | + if (res) { | |
219 | + let allDictDate = getAuthCache(DB_DICT_DATA_KEY); | |
220 | + if(!allDictDate['${po.dictField?default("")}']){ | |
221 | + Object.assign(allDictDate,{'${po.dictField?default("")}':res}) | |
222 | + } | |
223 | + setAuthCache(DB_DICT_DATA_KEY,allDictDate) | |
224 | + } | |
225 | + }) | |
226 | + </#if> | |
227 | + </#if> | |
228 | + </#list> | |
229 | + } | |
230 | + initDictConfig(); | |
231 | + </#if> | |
232 | +</script> | |
233 | + | |
234 | +<style scoped> | |
235 | + | |
236 | +</style> | |
0 | 237 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +<#list subTables as sub><#rt/> | |
13 | + ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/list${sub.entityName}ByMainId', | |
14 | + ${sub.entityName?uncap_first}Save='/${entityPackage}/${entityName?uncap_first}/add${sub.entityName}', | |
15 | + ${sub.entityName?uncap_first}Edit='/${entityPackage}/${entityName?uncap_first}/edit${sub.entityName}', | |
16 | + ${sub.entityName?uncap_first}Delete = '/${entityPackage}/${entityName?uncap_first}/delete${sub.entityName}', | |
17 | + ${sub.entityName?uncap_first}DeleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch${sub.entityName}', | |
18 | + ${sub.entityName?uncap_first}ExportXlsUrl = '/${entityPackage}/${entityName?uncap_first}/export${sub.entityName}', | |
19 | + ${sub.entityName?uncap_first}ImportUrl = '/${entityPackage}/${entityName?uncap_first}/import${sub.entityName}', | |
20 | +</#list> | |
21 | +} | |
22 | +/** | |
23 | + * 导出api | |
24 | + * @param params | |
25 | + */ | |
26 | +export const getExportUrl = Api.exportXls; | |
27 | + | |
28 | +/** | |
29 | + * 导入api | |
30 | + */ | |
31 | +export const getImportUrl = Api.importExcel; | |
32 | +/** | |
33 | + * 列表接口 | |
34 | + * @param params | |
35 | + */ | |
36 | +export const list = (params) => | |
37 | + defHttp.get({url: Api.list, params}); | |
38 | + | |
39 | +/** | |
40 | + * 删除单个 | |
41 | + */ | |
42 | +export const deleteOne = (params,handleSuccess) => { | |
43 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
44 | + handleSuccess(); | |
45 | + }); | |
46 | +} | |
47 | +/** | |
48 | + * 批量删除 | |
49 | + * @param params | |
50 | + */ | |
51 | +export const batchDelete = (params, handleSuccess) => { | |
52 | + Modal.confirm({ | |
53 | + title: '确认删除', | |
54 | + content: '是否删除选中数据', | |
55 | + okText: '确认', | |
56 | + cancelText: '取消', | |
57 | + onOk: () => { | |
58 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
59 | + handleSuccess(); | |
60 | + }); | |
61 | + } | |
62 | + }); | |
63 | +} | |
64 | +/** | |
65 | + * 保存或者更新 | |
66 | + * @param params | |
67 | + */ | |
68 | +export const saveOrUpdate = (params, isUpdate) => { | |
69 | + let url = isUpdate ? Api.edit : Api.save; | |
70 | + return defHttp.post({url: url, params}); | |
71 | +} | |
72 | +<#list subTables as sub><#rt/> | |
73 | +/** | |
74 | + * 列表接口 | |
75 | + * @param params | |
76 | + */ | |
77 | +export const ${sub.entityName?uncap_first}List = (params) => | |
78 | + defHttp.get({url: Api.${sub.entityName?uncap_first}List, params}); | |
79 | + | |
80 | +/** | |
81 | + * 删除单个 | |
82 | + */ | |
83 | +export const ${sub.entityName?uncap_first}Delete = (params,handleSuccess) => { | |
84 | + return defHttp.delete({url: Api.${sub.entityName?uncap_first}Delete, params}, {joinParamsToUrl: true}).then(() => { | |
85 | + handleSuccess(); | |
86 | + }); | |
87 | +} | |
88 | +/** | |
89 | + * 批量删除 | |
90 | + * @param params | |
91 | + */ | |
92 | +export const ${sub.entityName?uncap_first}DeleteBatch = (params, handleSuccess) => { | |
93 | + Modal.confirm({ | |
94 | + title: '确认删除', | |
95 | + content: '是否删除选中数据', | |
96 | + okText: '确认', | |
97 | + cancelText: '取消', | |
98 | + onOk: () => { | |
99 | + return defHttp.delete({url: Api.${sub.entityName?uncap_first}DeleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
100 | + handleSuccess(); | |
101 | + }); | |
102 | + } | |
103 | + }); | |
104 | +} | |
105 | +/** | |
106 | + * 保存或者更新 | |
107 | + * @param params | |
108 | + */ | |
109 | +export const ${sub.entityName?uncap_first}SaveOrUpdate = (params, isUpdate) => { | |
110 | + let url = isUpdate ? Api.${sub.entityName?uncap_first}Edit : Api.${sub.entityName?uncap_first}Save; | |
111 | + return defHttp.post({url: url, params}); | |
112 | +} | |
113 | +</#list> | |
0 | 114 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +//列表数据 | |
6 | +export const columns: BasicColumn[] = [ | |
7 | + <#list columns as po> | |
8 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
9 | + { | |
10 | + title: '${po.filedComment}', | |
11 | + align:"center", | |
12 | + <#if po.sort=='Y'> | |
13 | + sorter: true, | |
14 | + </#if> | |
15 | + <#if po.classType=='date'> | |
16 | + dataIndex: '${po.fieldName}', | |
17 | + customRender:({text}) =>{ | |
18 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
19 | + }, | |
20 | + <#elseif po.fieldDbType=='Blob'> | |
21 | + dataIndex: '${po.fieldName}String' | |
22 | + <#elseif po.classType=='umeditor'> | |
23 | + dataIndex: '${po.fieldName}', | |
24 | + slots: { customRender: 'htmlSlot' }, | |
25 | + <#elseif po.classType=='pca'> | |
26 | + dataIndex: '${po.fieldName}', | |
27 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
28 | + <#elseif po.classType=='file'> | |
29 | + dataIndex: '${po.fieldName}', | |
30 | + slots: { customRender: 'fileSlot' }, | |
31 | + <#elseif po.classType=='image'> | |
32 | + dataIndex: '${po.fieldName}', | |
33 | + customRender:render.renderAvatar, | |
34 | + <#elseif po.classType=='switch'> | |
35 | + dataIndex: '${po.fieldName}', | |
36 | +<#assign switch_extend_arr=['Y','N']> | |
37 | +<#if po.dictField?default("")?contains("[")> | |
38 | +<#assign switch_extend_arr=po.dictField?eval> | |
39 | +</#if> | |
40 | +<#list switch_extend_arr as a> | |
41 | +<#if a_index == 0> | |
42 | +<#assign switch_extend_arr1=a> | |
43 | +<#else> | |
44 | +<#assign switch_extend_arr2=a> | |
45 | +</#if> | |
46 | +</#list> | |
47 | + customRender:({text}) => { | |
48 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
49 | + }, | |
50 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
51 | + dataIndex: '${po.fieldName}_dictText' | |
52 | + <#elseif po.classType=='cat_tree'> | |
53 | + dataIndex: '${po.fieldName}', | |
54 | + <#if po.dictText?default("")?trim?length == 0> | |
55 | + customRender:({text}) => { | |
56 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
57 | + }, | |
58 | + <#else> | |
59 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
60 | + </#if> | |
61 | + <#else> | |
62 | + dataIndex: '${po.fieldName}' | |
63 | + </#if> | |
64 | + }, | |
65 | + </#if> | |
66 | + </#list> | |
67 | +]; | |
68 | +//查询数据 | |
69 | +export const searchFormSchema: FormSchema[] = [ | |
70 | +<#-- 开始循环 --> | |
71 | +<#list columns as po> | |
72 | +<#if po.isQuery=='Y'> | |
73 | +<#assign query_flag=true> | |
74 | + <#assign query_field_dictCode=""> | |
75 | + <#if po.dictTable?default("")?trim?length gt 1> | |
76 | + <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
77 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
78 | + <#assign query_field_dictCode="${po.dictField}"> | |
79 | + </#if> | |
80 | +<#if po.queryMode=='single'> | |
81 | + { | |
82 | + label: "${po.filedComment}", | |
83 | + field: "${po.fieldName}", | |
84 | +<#if po.classType=='sel_search'> | |
85 | + component: 'JSearchSelect', | |
86 | + componentProps:{ | |
87 | + dict:"${po.dictTable},${po.dictText},${po.dictField}" | |
88 | + }, | |
89 | +<#elseif po.classType=='sel_user'> | |
90 | + component: 'JSelectUserByDept', | |
91 | +<#elseif po.classType=='switch'> | |
92 | + component: 'JSwitch', | |
93 | + componentProps:{ | |
94 | + <#if po.dictField != 'is_open'> | |
95 | + options:"${po.dictField}" | |
96 | + </#if> | |
97 | + }, | |
98 | + <#elseif po.classType=='sel_depart'> | |
99 | + component: 'JSelectDept', | |
100 | + <#elseif po.classType=='list_multi'> | |
101 | + component: 'JMultiSelectTag',//暂无该组件 | |
102 | + componentProps:{ | |
103 | + dictCode:"query_field_dictCode?default("")" | |
104 | + }, | |
105 | + <#elseif po.classType=='cat_tree'> | |
106 | + component: 'JCategorySelect', | |
107 | + componentProps:{ | |
108 | + pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题 | |
109 | + }, | |
110 | +<#elseif po.classType=='date'> | |
111 | + component: 'DatePicker', | |
112 | +<#elseif po.classType=='datetime'> | |
113 | + component: 'DatePicker', | |
114 | + componentProps: { | |
115 | + showTime:true | |
116 | + }, | |
117 | +<#elseif po.classType=='pca'> | |
118 | + component: 'JAreaLinkage', | |
119 | +<#elseif po.classType=='popup'> | |
120 | + component: 'JPopup', | |
121 | + componentProps: ({ formActionType }) => { | |
122 | + const {setFieldsValue} = formActionType; | |
123 | + return{ | |
124 | + setFieldsValue:setFieldsValue, | |
125 | + code:"${po.dictTable}", | |
126 | + fieldConfig:"${po.dictField}", | |
127 | + multi:${po.extendParams.popupMulti?c}, | |
128 | + } | |
129 | + }, | |
130 | +<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'> | |
131 | +<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- --> | |
132 | + component: 'JDictSelectTag', | |
133 | + componentProps:{ | |
134 | + <#if po.dictTable?default("")?trim?length gt 1> | |
135 | + dictCode:"${po.dictTable},${po.dictText},${po.dictField}" | |
136 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
137 | + dictCode:"${po.dictField}" | |
138 | + </#if> | |
139 | + }, | |
140 | +<#else> | |
141 | + component: 'Input', | |
142 | +</#if> | |
143 | + colProps: {span: 6}, | |
144 | + }, | |
145 | +<#else> | |
146 | + { | |
147 | + label: "${po.filedComment}", | |
148 | + field: "${po.fieldName}", | |
149 | +<#if po.classType=='date'> | |
150 | + component: 'RangePicker', | |
151 | +<#elseif po.classType=='datetime'> | |
152 | + component: 'RangePicker', | |
153 | + componentProps: { | |
154 | + showTime:true | |
155 | + }, | |
156 | +<#else> | |
157 | + component: 'Input', //TODO 范围查询 | |
158 | +</#if> | |
159 | + colProps: {span: 6}, | |
160 | + }, | |
161 | +</#if> | |
162 | +</#if> | |
163 | +</#list> | |
164 | +<#-- 结束循环 --> | |
165 | +]; | |
166 | + | |
167 | +//表单数据 | |
168 | +export const formSchema: FormSchema[] = [ | |
169 | +<#assign form_cat_tree = false> | |
170 | +<#assign form_cat_back = ""> | |
171 | +<#assign bpm_flag=false> | |
172 | +<#list columns as po><#rt/> | |
173 | +<#if po.fieldDbName=='bpm_status'> | |
174 | + <#assign bpm_flag=true> | |
175 | +</#if> | |
176 | +<#if po.isShow =='Y'> | |
177 | +<#assign form_field_dictCode=""> | |
178 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
179 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
180 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
181 | + <#assign form_field_dictCode="${po.dictField}"> | |
182 | + </#if> | |
183 | + { | |
184 | + label: '${po.filedComment}', | |
185 | + field: '${po.fieldName}', | |
186 | + <#if po.classType =='date'> | |
187 | + component: 'DatePicker', | |
188 | + <#elseif po.fieldType =='datetime'> | |
189 | + component: 'DatePicker', | |
190 | + componentProps: { | |
191 | + showTime:true | |
192 | + }, | |
193 | + <#elseif po.fieldType =='time'> | |
194 | + component: 'TimePicker', | |
195 | + <#elseif po.classType =='popup'> | |
196 | + component: 'JPopup', | |
197 | + componentProps: ({ formActionType }) => { | |
198 | + const {setFieldsValue} = formActionType; | |
199 | + return{ | |
200 | + setFieldsValue:setFieldsValue, | |
201 | + code:"${po.dictTable}", | |
202 | + fieldConfig:${po.dictField}, | |
203 | + multi:${po.extendParams.popupMulti?c}, | |
204 | + } | |
205 | + } | |
206 | + <#elseif po.classType =='sel_depart'> | |
207 | + component: 'JSelectDept', | |
208 | + <#elseif po.classType =='switch'> | |
209 | + component: 'JSwitch', | |
210 | + componentProps:{ | |
211 | + <#if po.dictField != 'is_open'> | |
212 | + options:${po.dictField} | |
213 | + </#if> | |
214 | + } | |
215 | + <#elseif po.classType =='pca'> | |
216 | + component: 'JAreaLinkage', | |
217 | + <#elseif po.classType =='markdown'> | |
218 | + component: 'JMarkdownEditor',//注意string转换问题 | |
219 | + <#elseif po.classType =='password'> | |
220 | + component: 'InputPassword', | |
221 | + <#elseif po.classType =='sel_user'> | |
222 | + component: 'JSelectUserByDept', | |
223 | + componentProps:{ | |
224 | + labelKey:'realname', | |
225 | + } | |
226 | + <#elseif po.classType =='textarea'> | |
227 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
228 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
229 | + component: 'JDictSelectTag', | |
230 | + componentProps:{ | |
231 | + dictCode:"${form_field_dictCode}" | |
232 | + } | |
233 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
234 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
235 | + componentProps:{ | |
236 | + dictCode:"${form_field_dictCode}" | |
237 | + } | |
238 | + <#elseif po.classType=='sel_search'> | |
239 | + component: 'JSearchSelect', | |
240 | + componentProps:{ | |
241 | + dict:"${form_field_dictCode}" | |
242 | + } | |
243 | +<#elseif po.classType=='cat_tree'> | |
244 | + <#assign form_cat_tree = true> | |
245 | + component: 'JCategorySelect', | |
246 | + componentProps:{ | |
247 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
248 | + } | |
249 | + <#if po.dictText?default("")?trim?length gt 1> | |
250 | + <#assign form_cat_back = "${po.dictText}"> | |
251 | + </#if> | |
252 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
253 | + component: 'InputNumber', | |
254 | + <#elseif po.classType=='file'> | |
255 | + component: 'JUpload', | |
256 | + componentProps:{ | |
257 | + <#if po.uploadnum??> | |
258 | + maxCount:${po.uploadnum} | |
259 | + </#if> | |
260 | + } | |
261 | + <#elseif po.classType=='image'> | |
262 | + component: 'JImageUpload', | |
263 | + componentProps:{ | |
264 | + <#if po.uploadnum??> | |
265 | + fileMax:${po.uploadnum} | |
266 | + </#if> | |
267 | + } | |
268 | + <#elseif po.classType=='umeditor'> | |
269 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
270 | + <#elseif po.classType == 'sel_tree'> | |
271 | + component: 'JTreeSelect', | |
272 | + componentProps:{ | |
273 | + <#if po.dictText??> | |
274 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
275 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
276 | + <#elseif po.dictText?split(',')[1]??> | |
277 | + pidField:"${po.dictText?split(',')[1]}", | |
278 | + <#elseif po.dictText?split(',')[3]??> | |
279 | + hasChildField:"${po.dictText?split(',')[3]}", | |
280 | + </#if> | |
281 | + </#if> | |
282 | + pidValue:"${po.dictField}", | |
283 | + } | |
284 | + <#else> | |
285 | + component: 'Input', | |
286 | + </#if> | |
287 | + <#include "/common/utils.ftl"> | |
288 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
289 | + dynamicRules: ({model,schema}) => { | |
290 | + <#if po.fieldName != 'id'> | |
291 | + <#assign fieldValidType = po.fieldValidType!''> | |
292 | + return [ | |
293 | + <#-- 非空校验 --> | |
294 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
295 | + { required: true, message: '请输入${po.filedComment}!'}, | |
296 | + <#elseif fieldValidType!=''> | |
297 | + { required: false}, | |
298 | + </#if> | |
299 | + <#-- 唯一校验 --> | |
300 | + <#if fieldValidType == 'only'> | |
301 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
302 | + <#-- 6到16位数字 --> | |
303 | + <#elseif fieldValidType == 'n6-16'> | |
304 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
305 | + <#-- 6到16位任意字符 --> | |
306 | + <#elseif fieldValidType == '*6-16'> | |
307 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
308 | + <#-- 6到18位字符串 --> | |
309 | + <#elseif fieldValidType == 's6-18'> | |
310 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
311 | + <#-- 网址 --> | |
312 | + <#elseif fieldValidType == 'url'> | |
313 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
314 | + <#-- 电子邮件 --> | |
315 | + <#elseif fieldValidType == 'e'> | |
316 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
317 | + <#-- 手机号码 --> | |
318 | + <#elseif fieldValidType == 'm'> | |
319 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
320 | + <#-- 邮政编码 --> | |
321 | + <#elseif fieldValidType == 'p'> | |
322 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
323 | + <#-- 字母 --> | |
324 | + <#elseif fieldValidType == 's'> | |
325 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
326 | + <#-- 数字 --> | |
327 | + <#elseif fieldValidType == 'n'> | |
328 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
329 | + <#-- 整数 --> | |
330 | + <#elseif fieldValidType == 'z'> | |
331 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
332 | + <#-- 金额 --> | |
333 | + <#elseif fieldValidType == 'money'> | |
334 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
335 | + <#-- 正则校验 --> | |
336 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
337 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
338 | + <#-- 无校验 --> | |
339 | + <#else> | |
340 | + <#t> | |
341 | + </#if> | |
342 | + ]; | |
343 | + </#if> | |
344 | + }, | |
345 | + </#if> | |
346 | + <#if po.readonly=='Y'> | |
347 | + dynamicDisabled:true | |
348 | + </#if> | |
349 | + }, | |
350 | +</#if> | |
351 | +</#list> | |
352 | +]; | |
353 | + | |
354 | +<#list subTables as sub> | |
355 | +//子表列表数据 | |
356 | +export const ${sub.entityName?uncap_first}Columns: BasicColumn[] = [ | |
357 | + <#list sub.originalColumns as po> | |
358 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
359 | + { | |
360 | + title: '${po.filedComment}', | |
361 | + align:"center", | |
362 | + <#if po.sort=='Y'> | |
363 | + sorter: true, | |
364 | + </#if> | |
365 | + <#if po.classType=='date'> | |
366 | + dataIndex: '${po.fieldName}', | |
367 | + customRender:({text}) =>{ | |
368 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
369 | + }, | |
370 | + <#elseif po.fieldDbType=='Blob'> | |
371 | + dataIndex: '${po.fieldName}String' | |
372 | + <#elseif po.classType=='umeditor'> | |
373 | + dataIndex: '${po.fieldName}', | |
374 | + slots: { customRender: 'htmlSlot' }, | |
375 | + <#elseif po.classType=='pca'> | |
376 | + dataIndex: '${po.fieldName}', | |
377 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
378 | + <#elseif po.classType=='file'> | |
379 | + dataIndex: '${po.fieldName}', | |
380 | + slots: { customRender: 'fileSlot' }, | |
381 | + <#elseif po.classType=='image'> | |
382 | + dataIndex: '${po.fieldName}', | |
383 | + customRender:render.renderAvatar, | |
384 | + <#elseif po.classType=='switch'> | |
385 | + dataIndex: '${po.fieldName}', | |
386 | +<#assign switch_extend_arr=['Y','N']> | |
387 | +<#if po.dictField?default("")?contains("[")> | |
388 | +<#assign switch_extend_arr=po.dictField?eval> | |
389 | +</#if> | |
390 | +<#list switch_extend_arr as a> | |
391 | +<#if a_index == 0> | |
392 | +<#assign switch_extend_arr1=a> | |
393 | +<#else> | |
394 | +<#assign switch_extend_arr2=a> | |
395 | +</#if> | |
396 | +</#list> | |
397 | + customRender:({text}) => { | |
398 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
399 | + }, | |
400 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
401 | + dataIndex: '${po.fieldName}_dictText' | |
402 | + <#elseif po.classType=='cat_tree'> | |
403 | + dataIndex: '${po.fieldName}', | |
404 | + <#if po.dictText?default("")?trim?length == 0> | |
405 | + customRender:({text}) => { | |
406 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
407 | + }, | |
408 | + <#else> | |
409 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
410 | + </#if> | |
411 | + <#else> | |
412 | + dataIndex: '${po.fieldName}' | |
413 | + </#if> | |
414 | + }, | |
415 | + </#if> | |
416 | + </#list> | |
417 | +]; | |
418 | +//子表表单数据 | |
419 | +export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [ | |
420 | +<#assign form_cat_tree = false> | |
421 | +<#assign form_cat_back = ""> | |
422 | +<#assign bpm_flag=false> | |
423 | +<#list sub.originalColumns as po><#rt/> | |
424 | +<#if po.isShow =='Y'> | |
425 | +<#assign form_field_dictCode=""> | |
426 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
427 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
428 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
429 | + <#assign form_field_dictCode="${po.dictField}"> | |
430 | + </#if> | |
431 | + { | |
432 | + label: '${po.filedComment}', | |
433 | + field: '${po.fieldName}', | |
434 | + <#if po.classType =='date'> | |
435 | + component: 'DatePicker', | |
436 | + <#elseif po.fieldType =='datetime'> | |
437 | + component: 'DatePicker', | |
438 | + componentProps: { | |
439 | + showTime:true | |
440 | + }, | |
441 | + <#elseif po.fieldType =='time'> | |
442 | + component: 'TimePicker', | |
443 | + <#elseif po.classType =='popup'> | |
444 | + component: 'JPopup', | |
445 | + componentProps: ({ formActionType }) => { | |
446 | + const {setFieldsValue} = formActionType; | |
447 | + return{ | |
448 | + setFieldsValue:setFieldsValue, | |
449 | + code:"${po.dictTable}", | |
450 | + fieldConfig:${po.dictField}, | |
451 | + multi:${po.extendParams.popupMulti?c}, | |
452 | + } | |
453 | + } | |
454 | + <#elseif po.classType =='sel_depart'> | |
455 | + component: 'JSelectDept', | |
456 | + <#elseif po.classType =='switch'> | |
457 | + component: 'JSwitch', | |
458 | + componentProps:{ | |
459 | + <#if po.dictField != 'is_open'> | |
460 | + options:${po.dictField} | |
461 | + </#if> | |
462 | + } | |
463 | + <#elseif po.classType =='pca'> | |
464 | + component: 'JAreaLinkage', | |
465 | + <#elseif po.classType =='markdown'> | |
466 | + component: 'JMarkdownEditor',//注意string转换问题 | |
467 | + <#elseif po.classType =='password'> | |
468 | + component: 'InputPassword', | |
469 | + <#elseif po.classType =='sel_user'> | |
470 | + component: 'JSelectUserByDept', | |
471 | + componentProps:{ | |
472 | + labelKey:'realname', | |
473 | + } | |
474 | + <#elseif po.classType =='textarea'> | |
475 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
476 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
477 | + component: 'JDictSelectTag', | |
478 | + componentProps:{ | |
479 | + dictCode:"${form_field_dictCode}" | |
480 | + } | |
481 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
482 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
483 | + componentProps:{ | |
484 | + dictCode:"${form_field_dictCode}" | |
485 | + } | |
486 | + <#elseif po.classType=='sel_search'> | |
487 | + component: 'JSearchSelect', | |
488 | + componentProps:{ | |
489 | + dict:"${form_field_dictCode}" | |
490 | + } | |
491 | +<#elseif po.classType=='cat_tree'> | |
492 | + <#assign form_cat_tree = true> | |
493 | + component: 'JCategorySelect', | |
494 | + componentProps:{ | |
495 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
496 | + } | |
497 | + <#if po.dictText?default("")?trim?length gt 1> | |
498 | + <#assign form_cat_back = "${po.dictText}"> | |
499 | + </#if> | |
500 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
501 | + component: 'InputNumber', | |
502 | + <#elseif po.classType=='file'> | |
503 | + component: 'JUpload', | |
504 | + componentProps:{ | |
505 | + <#if po.uploadnum??> | |
506 | + maxCount:${po.uploadnum} | |
507 | + </#if> | |
508 | + } | |
509 | + <#elseif po.classType=='image'> | |
510 | + component: 'JImageUpload', | |
511 | + componentProps:{ | |
512 | + <#if po.uploadnum??> | |
513 | + fileMax:${po.uploadnum} | |
514 | + </#if> | |
515 | + } | |
516 | + <#elseif po.classType=='umeditor'> | |
517 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
518 | + <#elseif po.classType == 'sel_tree'> | |
519 | + component: 'JTreeSelect', | |
520 | + componentProps:{ | |
521 | + <#if po.dictText??> | |
522 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
523 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
524 | + <#elseif po.dictText?split(',')[1]??> | |
525 | + pidField:"${po.dictText?split(',')[1]}", | |
526 | + <#elseif po.dictText?split(',')[3]??> | |
527 | + hasChildField:"${po.dictText?split(',')[3]}", | |
528 | + </#if> | |
529 | + </#if> | |
530 | + pidValue:"${po.dictField}", | |
531 | + } | |
532 | + <#else> | |
533 | + component: 'Input', | |
534 | + </#if> | |
535 | + <#include "/common/utils.ftl"> | |
536 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
537 | + dynamicRules: ({model,schema}) => { | |
538 | + <#if po.fieldName != 'id'> | |
539 | + <#assign fieldValidType = po.fieldValidType!''> | |
540 | + return [ | |
541 | + <#-- 非空校验 --> | |
542 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
543 | + { required: true, message: '请输入${po.filedComment}!'}, | |
544 | + <#elseif fieldValidType!=''> | |
545 | + { required: false}, | |
546 | + </#if> | |
547 | + <#-- 唯一校验 --> | |
548 | + <#if fieldValidType == 'only'> | |
549 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
550 | + <#-- 6到16位数字 --> | |
551 | + <#elseif fieldValidType == 'n6-16'> | |
552 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
553 | + <#-- 6到16位任意字符 --> | |
554 | + <#elseif fieldValidType == '*6-16'> | |
555 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
556 | + <#-- 6到18位字符串 --> | |
557 | + <#elseif fieldValidType == 's6-18'> | |
558 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
559 | + <#-- 网址 --> | |
560 | + <#elseif fieldValidType == 'url'> | |
561 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
562 | + <#-- 电子邮件 --> | |
563 | + <#elseif fieldValidType == 'e'> | |
564 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
565 | + <#-- 手机号码 --> | |
566 | + <#elseif fieldValidType == 'm'> | |
567 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
568 | + <#-- 邮政编码 --> | |
569 | + <#elseif fieldValidType == 'p'> | |
570 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
571 | + <#-- 字母 --> | |
572 | + <#elseif fieldValidType == 's'> | |
573 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
574 | + <#-- 数字 --> | |
575 | + <#elseif fieldValidType == 'n'> | |
576 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
577 | + <#-- 整数 --> | |
578 | + <#elseif fieldValidType == 'z'> | |
579 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
580 | + <#-- 金额 --> | |
581 | + <#elseif fieldValidType == 'money'> | |
582 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
583 | + <#-- 正则校验 --> | |
584 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
585 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
586 | + <#-- 无校验 --> | |
587 | + <#else> | |
588 | + <#t> | |
589 | + </#if> | |
590 | + ]; | |
591 | + </#if> | |
592 | + }, | |
593 | + </#if> | |
594 | + <#if po.readonly=='Y'> | |
595 | + dynamicDisabled:true | |
596 | + </#if> | |
597 | + }, | |
598 | +</#if> | |
599 | +</#list> | |
600 | +]; | |
601 | +</#list> | |
0 | 602 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
0 → 100644
1 | +<#list subTables as sub> | |
2 | +#segment#${sub.entityName}List.vue | |
3 | +<template> | |
4 | + <div> | |
5 | + <!--引用表格--> | |
6 | + <BasicTable @register="registerTable" :rowSelection="rowSelection" :searchInfo="searchInfo"> | |
7 | + <!--插槽:table标题--> | |
8 | + <template #tableTitle> | |
9 | + <a-button type="primary" @click="handleCreate" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
10 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
11 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
12 | + <a-dropdown v-if="selectedRowKeys.length > 0"> | |
13 | + <template #overlay> | |
14 | + <a-menu> | |
15 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
16 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
17 | + 删除 | |
18 | + </a-menu-item> | |
19 | + </a-menu> | |
20 | + </template> | |
21 | + <a-button>批量操作 | |
22 | + <Icon icon="mdi:chevron-down"></Icon> | |
23 | + </a-button> | |
24 | + </a-dropdown> | |
25 | + </template> | |
26 | + <!--操作栏--> | |
27 | + <template #action="{ record }"> | |
28 | + <TableAction :actions="getTableAction(record)"/> | |
29 | + </template> | |
30 | + <!--字段回显插槽--> | |
31 | + <template #htmlSlot="{text}"> | |
32 | + <div v-html="text"></div> | |
33 | + </template> | |
34 | + <template #fileSlot="{text}"> | |
35 | + <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |
36 | + <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |
37 | + </template> | |
38 | + </BasicTable> | |
39 | + | |
40 | + <${sub.entityName}Modal @register="registerModal" @success="handleSuccess"/> | |
41 | + </div> | |
42 | +</template> | |
43 | + | |
44 | +<script lang="ts" setup> | |
45 | + import {ref, computed, unref,inject,watch} from 'vue'; | |
46 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
47 | + import { useListPage } from '/@/hooks/system/useListPage' | |
48 | + import {useModal} from '/@/components/Modal'; | |
49 | + import ${sub.entityName}Modal from './components/${sub.entityName}Modal.vue' | |
50 | + import {${sub.entityName?uncap_first}Columns} from './${entityName}.data'; | |
51 | + import {${sub.entityName?uncap_first}List, ${sub.entityName?uncap_first}Delete, ${sub.entityName?uncap_first}DeleteBatch} from './${entityName}.api'; | |
52 | + import {isEmpty} from "/@/utils/is"; | |
53 | + import {useMessage} from '/@/hooks/web/useMessage'; | |
54 | + | |
55 | + //接收主表id | |
56 | + const mainId = inject('mainId') || ''; | |
57 | + //提示弹窗 | |
58 | + const $message = useMessage() | |
59 | + //弹窗model | |
60 | + const [registerModal, {openModal}] = useModal(); | |
61 | + const searchInfo = {}; | |
62 | + // 列表页面公共参数、方法 | |
63 | + const {prefixCls, tableContext} = useListPage({ | |
64 | + tableProps: { | |
65 | + api: ${sub.entityName?uncap_first}List, | |
66 | + columns: ${sub.entityName?uncap_first}Columns, | |
67 | + canResize: false, | |
68 | + useSearchForm: false, | |
69 | + actionColumn: { | |
70 | + width: 180, | |
71 | + }, | |
72 | + pagination:{ | |
73 | + current: 1, | |
74 | + pageSize: 5, | |
75 | + pageSizeOptions: ['5', '10', '20'], | |
76 | + } | |
77 | + }, | |
78 | + }); | |
79 | + | |
80 | + //注册table数据 | |
81 | + const [registerTable, {reload}, {rowSelection, selectedRowKeys}] = tableContext; | |
82 | + | |
83 | + watch(mainId, () => { | |
84 | + <#list sub.foreignKeys as key> | |
85 | + searchInfo['${key?uncap_first}'] = unref(mainId); | |
86 | + </#list> | |
87 | + reload(); | |
88 | + } | |
89 | + ); | |
90 | + | |
91 | + /** | |
92 | + * 新增事件 | |
93 | + */ | |
94 | + function handleCreate() { | |
95 | + if (isEmpty(unref(mainId))) { | |
96 | + $message.createMessage.warning('请选择一个主表信息') | |
97 | + return; | |
98 | + } | |
99 | + openModal(true, { | |
100 | + isUpdate: false, | |
101 | + showFooter: true, | |
102 | + }); | |
103 | + } | |
104 | + | |
105 | + /** | |
106 | + * 编辑事件 | |
107 | + */ | |
108 | + async function handleEdit(record: Recordable) { | |
109 | + openModal(true, { | |
110 | + record, | |
111 | + isUpdate: true, | |
112 | + showFooter: true, | |
113 | + }); | |
114 | + } | |
115 | + | |
116 | + /** | |
117 | + * 删除事件 | |
118 | + */ | |
119 | + async function handleDelete(record) { | |
120 | + await ${sub.entityName?uncap_first}Delete({id: record.id}, reload); | |
121 | + } | |
122 | + | |
123 | + /** | |
124 | + * 批量删除事件 | |
125 | + */ | |
126 | + async function batchHandleDelete() { | |
127 | + await ${sub.entityName?uncap_first}DeleteBatch({ids: selectedRowKeys.value}, () => { | |
128 | + reload() | |
129 | + }) | |
130 | + } | |
131 | + | |
132 | + /** | |
133 | + * 成功回调 | |
134 | + */ | |
135 | + function handleSuccess() { | |
136 | + reload(); | |
137 | + } | |
138 | + | |
139 | + /** | |
140 | + * 操作栏 | |
141 | + */ | |
142 | + function getTableAction(record) { | |
143 | + return [ | |
144 | + { | |
145 | + label: '编辑', | |
146 | + onClick: handleEdit.bind(null, record), | |
147 | + }, { | |
148 | + label: '删除', | |
149 | + popConfirm: { | |
150 | + title: '是否确认删除', | |
151 | + confirm: handleDelete.bind(null, record), | |
152 | + }, | |
153 | + } | |
154 | + ] | |
155 | + } | |
156 | +</script> | |
157 | +</#list> | |
0 | 158 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |
3 | + <BasicForm @register="registerForm"/> | |
4 | + </BasicModal> | |
5 | +</template> | |
6 | + | |
7 | +<script lang="ts" setup> | |
8 | + import {ref, computed, unref} from 'vue'; | |
9 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
10 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
11 | + import {formSchema} from '../${entityName?uncap_first}.data'; | |
12 | + import {saveOrUpdate} from '../${entityName?uncap_first}.api'; | |
13 | + // Emits声明 | |
14 | + const emit = defineEmits(['register','success']); | |
15 | + const isUpdate = ref(true); | |
16 | + //表单配置 | |
17 | + const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |
18 | + labelWidth: 150, | |
19 | + schemas: formSchema, | |
20 | + showActionButtonGroup: false, | |
21 | + }); | |
22 | + //表单赋值 | |
23 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
24 | + //重置表单 | |
25 | + await resetFields(); | |
26 | + setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter}); | |
27 | + isUpdate.value = !!data?.isUpdate; | |
28 | + if (unref(isUpdate)) { | |
29 | + //表单赋值 | |
30 | + await setFieldsValue({ | |
31 | + ...data.record, | |
32 | + }); | |
33 | + } | |
34 | + // 隐藏底部时禁用整个表单 | |
35 | + setProps({ disabled: !data?.showFooter }) | |
36 | + }); | |
37 | + //设置标题 | |
38 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
39 | + //表单提交事件 | |
40 | + async function handleSubmit(v) { | |
41 | + try { | |
42 | + let values = await validate(); | |
43 | + setModalProps({confirmLoading: true}); | |
44 | + //提交表单 | |
45 | + await saveOrUpdate(values, isUpdate.value); | |
46 | + //关闭弹窗 | |
47 | + closeModal(); | |
48 | + //刷新列表 | |
49 | + emit('success'); | |
50 | + } finally { | |
51 | + setModalProps({confirmLoading: false}); | |
52 | + } | |
53 | + } | |
54 | +</script> | |
55 | + | |
56 | +<style lang="less" scoped> | |
57 | + | |
58 | +</style> | |
0 | 59 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Modal.vuei
0 → 100644
1 | +<#include "/common/utils.ftl"> | |
2 | +<#list subTables as sub> | |
3 | +#segment#${sub.entityName}Modal.vue | |
4 | +<template> | |
5 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |
6 | + <BasicForm @register="registerForm"/> | |
7 | + </BasicModal> | |
8 | +</template> | |
9 | + | |
10 | +<script lang="ts" setup> | |
11 | + import {ref, computed, unref,inject} from 'vue'; | |
12 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
13 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
14 | + import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data'; | |
15 | + import {${sub.entityName?uncap_first}SaveOrUpdate} from '../${entityName?uncap_first}.api'; | |
16 | + | |
17 | + //接收主表id | |
18 | + const mainId = inject('mainId'); | |
19 | + // Emits声明 | |
20 | + const emit = defineEmits(['register','success']); | |
21 | + const isUpdate = ref(true); | |
22 | + //表单配置 | |
23 | + const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |
24 | + labelWidth: 150, | |
25 | + schemas: ${sub.entityName?uncap_first}FormSchema, | |
26 | + showActionButtonGroup: false, | |
27 | + }); | |
28 | + //表单赋值 | |
29 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
30 | + //重置表单 | |
31 | + await resetFields(); | |
32 | + setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter}); | |
33 | + isUpdate.value = !!data?.isUpdate; | |
34 | + if (unref(isUpdate)) { | |
35 | + //表单赋值 | |
36 | + await setFieldsValue({ | |
37 | + ...data.record, | |
38 | + }); | |
39 | + } | |
40 | + // 隐藏底部时禁用整个表单 | |
41 | + setProps({ disabled: !data?.showFooter }) | |
42 | + }); | |
43 | + //设置标题 | |
44 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
45 | + //表单提交事件 | |
46 | + async function handleSubmit(v) { | |
47 | + try { | |
48 | + let values = await validate(); | |
49 | + setModalProps({confirmLoading: true}); | |
50 | + if (unref(mainId)) { | |
51 | + <#list sub.foreignKeys as key> | |
52 | + values['${key?uncap_first}'] = unref(mainId); | |
53 | + </#list> | |
54 | + } | |
55 | + //提交表单 | |
56 | + await ${sub.entityName?uncap_first}SaveOrUpdate(values, isUpdate.value); | |
57 | + //关闭弹窗 | |
58 | + closeModal(); | |
59 | + //刷新列表 | |
60 | + emit('success'); | |
61 | + } finally { | |
62 | + setModalProps({confirmLoading: false}); | |
63 | + } | |
64 | + } | |
65 | +</script> | |
66 | +</#list> | |
0 | 67 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -110,7 +110,7 @@ public class ${entityName}Controller { |
110 | 110 | */ |
111 | 111 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
112 | 112 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
113 | - @PutMapping(value = "/edit") | |
113 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
114 | 114 | public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) { |
115 | 115 | ${entityName} ${entityName?uncap_first} = new ${entityName}(); |
116 | 116 | BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first}); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
... | ... | @@ -266,9 +266,7 @@ |
266 | 266 | <a @click="handleEdit(record)">编辑</a> |
267 | 267 | <a-divider type="vertical"/> |
268 | 268 | <a-dropdown> |
269 | - <a class="ant-dropdown-link"> | |
270 | - <span>更多 <a-icon type="down"/></span> | |
271 | - </a> | |
269 | + <a class="ant-dropdown-link">更多 <a-icon type="down" /></a> | |
272 | 270 | <a-menu slot="overlay"> |
273 | 271 | <a-menu-item> |
274 | 272 | <a-popconfirm title="确定删除吗?" @confirm="handleDelete(record.id)"> |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
... | ... | @@ -21,13 +21,8 @@ |
21 | 21 | <#elseif po.dictField?default("")?trim?length gt 1> |
22 | 22 | <#assign form_field_dictCode="${po.dictField}"> |
23 | 23 | </#if> |
24 | - <#if po.classType =='textarea'> | |
25 | - <a-col :span="24"> | |
26 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
27 | - <#else> | |
28 | 24 | <a-col :xs="24" :sm="12"> |
29 | 25 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
30 | - </#if> | |
31 | 26 | <#if po.classType =='date'> |
32 | 27 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/> |
33 | 28 | <#elseif po.classType =='datetime'> |
... | ... | @@ -131,7 +126,7 @@ |
131 | 126 | </#list> |
132 | 127 | </a-tabs> |
133 | 128 | <#if bpm_flag> |
134 | - <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button @click="handleOk">提 交</a-button></a-row> | |
129 | + <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button icon="check" style="width: 126px" type="primary" @click="handleOk">提 交</a-button></a-row> | |
135 | 130 | </#if> |
136 | 131 | </a-spin> |
137 | 132 | </template> |
... | ... | @@ -161,20 +156,12 @@ |
161 | 156 | return { |
162 | 157 | labelCol: { |
163 | 158 | xs: { span: 24 }, |
164 | - sm: { span: 6 }, | |
159 | + sm: { span: 5 }, | |
165 | 160 | }, |
166 | 161 | wrapperCol: { |
167 | 162 | xs: { span: 24 }, |
168 | 163 | sm: { span: 16 }, |
169 | 164 | }, |
170 | - labelCol2: { | |
171 | - xs: { span: 24 }, | |
172 | - sm: { span: 3 }, | |
173 | - }, | |
174 | - wrapperCol2: { | |
175 | - xs: { span: 24 }, | |
176 | - sm: { span: 20 }, | |
177 | - }, | |
178 | 165 | model:{ |
179 | 166 | <#include "/common/init/initValue.ftl"> |
180 | 167 | }, |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
... | ... | @@ -15,13 +15,8 @@ |
15 | 15 | <#elseif po.dictField?default("")?trim?length gt 1> |
16 | 16 | <#assign form_field_dictCode="${po.dictField}"> |
17 | 17 | </#if> |
18 | - <#if po.classType =='textarea'> | |
19 | - <a-col :span="24"> | |
20 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
21 | - <#else> | |
22 | 18 | <a-col :xs="24" :sm="12"> |
23 | 19 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
24 | - </#if> | |
25 | 20 | <#if po.classType =='date'> |
26 | 21 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%"/> |
27 | 22 | <#elseif po.classType =='datetime'> |
... | ... | @@ -90,20 +85,12 @@ |
90 | 85 | }, |
91 | 86 | labelCol: { |
92 | 87 | xs: { span: 24 }, |
93 | - sm: { span: 6 }, | |
88 | + sm: { span: 5 }, | |
94 | 89 | }, |
95 | 90 | wrapperCol: { |
96 | 91 | xs: { span: 24 }, |
97 | 92 | sm: { span: 16 }, |
98 | 93 | }, |
99 | - labelCol2: { | |
100 | - xs: { span: 24 }, | |
101 | - sm: { span: 3 }, | |
102 | - }, | |
103 | - wrapperCol2: { | |
104 | - xs: { span: 24 }, | |
105 | - sm: { span: 20 }, | |
106 | - }, | |
107 | 94 | <#include "/common/validatorRulesTemplate/sub.ftl"> |
108 | 95 | confirmLoading: false, |
109 | 96 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<#-- ** 引入全局工具方法 ** --> | |
2 | +<#--<#include "/common/utils.ftl">--> | |
3 | +<#include "../../../../../../common/utils.ftl"> | |
4 | +<template> | |
5 | + <div> | |
6 | +<#assign list_need_category=false> | |
7 | +<#assign list_need_pca=false> | |
8 | +<#assign bpm_flag=false> | |
9 | + | |
10 | +<#-- 开始循环 --> | |
11 | +<#list columns as po> | |
12 | +<#if po.fieldDbName=='bpm_status'> | |
13 | + <#assign bpm_flag=true> | |
14 | +</#if> | |
15 | +<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0> | |
16 | +<#assign list_need_category=true> | |
17 | +</#if> | |
18 | +<#if po.classType=='pca'> | |
19 | +<#assign list_need_pca=true> | |
20 | +</#if> | |
21 | +</#list> | |
22 | +<#-- 结束循环 --> | |
23 | + <!--引用表格--> | |
24 | + <BasicTable @register="registerTable" :rowSelection="rowSelection" :expandedRowKeys="expandedRowKeys" @expand="handleExpand"> | |
25 | + <!-- 内嵌table区域 begin --> | |
26 | + <template #expandedRowRender="{record}"> | |
27 | + <a-tabs tabPosition="top"> | |
28 | + <#list subTables as sub> | |
29 | + <a-tab-pane tab="${sub.ftlDescription}" key="${sub.entityName?uncap_first}" forceRender> | |
30 | + <${sub.entityName?uncap_first}SubTable :id="expandedRowKeys[0]"/> | |
31 | + </a-tab-pane> | |
32 | + </#list> | |
33 | + </a-tabs> | |
34 | + </template> | |
35 | + <!-- 内嵌table区域 end --> | |
36 | + <!--插槽:table标题--> | |
37 | + <template #tableTitle> | |
38 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
39 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
40 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
41 | + <a-dropdown v-if="selectedRowKeys.length > 0"> | |
42 | + <template #overlay> | |
43 | + <a-menu> | |
44 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
45 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
46 | + 删除 | |
47 | + </a-menu-item> | |
48 | + </a-menu> | |
49 | + </template> | |
50 | + <a-button>批量操作 | |
51 | + <Icon icon="mdi:chevron-down"></Icon> | |
52 | + </a-button> | |
53 | + </a-dropdown> | |
54 | + </template> | |
55 | + <!--操作栏--> | |
56 | + <template #action="{ record }"> | |
57 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
58 | + </template> | |
59 | + <!--字段回显插槽--> | |
60 | + <template #htmlSlot="{text}"> | |
61 | + <div v-html="text"></div> | |
62 | + </template> | |
63 | + <template #fileSlot="{text}"> | |
64 | + <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |
65 | + <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |
66 | + </template> | |
67 | + </BasicTable> | |
68 | + <!-- 表单区域 --> | |
69 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
70 | + </div> | |
71 | +</template> | |
72 | + | |
73 | +<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup> | |
74 | + import {ref, computed, unref} from 'vue'; | |
75 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
76 | + import { useListPage } from '/@/hooks/system/useListPage' | |
77 | + import {useModal} from '/@/components/Modal'; | |
78 | + import ${entityName}Modal from './components/${entityName}Modal.vue' | |
79 | + <#list subTables as sub> | |
80 | + import ${sub.entityName}SubTable from './subTables/${sub.entityName}SubTable.vue' | |
81 | + </#list> | |
82 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
83 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
84 | + <#if list_need_category> | |
85 | + import { loadCategoryData } from '/@/api/common/api' | |
86 | + import { getAuthCache, setAuthCache } from '/@/utils/auth'; | |
87 | + import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum'; | |
88 | + </#if> | |
89 | + // 展开key | |
90 | + const expandedRowKeys = ref<any[]>([]); | |
91 | + //注册model | |
92 | + const [registerModal, {openModal}] = useModal(); | |
93 | + //注册table数据 | |
94 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
95 | + tableProps:{ | |
96 | + title: '${tableVo.ftlDescription}', | |
97 | + api: list, | |
98 | + columns, | |
99 | + canResize:false, | |
100 | + formConfig: { | |
101 | + labelWidth: 120, | |
102 | + schemas: searchFormSchema, | |
103 | + autoSubmitOnEnter:true, | |
104 | + showAdvancedButton:true, | |
105 | + fieldMapToTime: [ | |
106 | + <#list columns as po> | |
107 | + <#if po.isQuery=='Y'> | |
108 | + <#if po.queryMode!='single'> | |
109 | + <#if po.classType=='date'> | |
110 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'], | |
111 | + <#elseif po.classType=='datetime'> | |
112 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'], | |
113 | + </#if> | |
114 | + </#if> | |
115 | + </#if> | |
116 | + </#list> | |
117 | + ], | |
118 | + }, | |
119 | + actionColumn: { | |
120 | + width: 120, | |
121 | + }, | |
122 | + }, | |
123 | + exportConfig: { | |
124 | + name:"${tableVo.ftlDescription}", | |
125 | + url: getExportUrl, | |
126 | + }, | |
127 | + importConfig: { | |
128 | + url: getImportUrl | |
129 | + }, | |
130 | + }) | |
131 | + | |
132 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
133 | + /** | |
134 | + * 展开事件 | |
135 | + * */ | |
136 | + function handleExpand(expanded, record){ | |
137 | + expandedRowKeys.value=[]; | |
138 | + if (expanded === true) { | |
139 | + expandedRowKeys.value.push(record.id) | |
140 | + } | |
141 | + } | |
142 | + /** | |
143 | + * 新增事件 | |
144 | + */ | |
145 | + function handleAdd() { | |
146 | + openModal(true, { | |
147 | + isUpdate: false, | |
148 | + showFooter: true, | |
149 | + }); | |
150 | + } | |
151 | + /** | |
152 | + * 编辑事件 | |
153 | + */ | |
154 | + function handleEdit(record: Recordable) { | |
155 | + openModal(true, { | |
156 | + record, | |
157 | + isUpdate: true, | |
158 | + showFooter: true, | |
159 | + }); | |
160 | + } | |
161 | + /** | |
162 | + * 详情 | |
163 | + */ | |
164 | + function handleDetail(record: Recordable) { | |
165 | + openModal(true, { | |
166 | + record, | |
167 | + isUpdate: true, | |
168 | + showFooter: false, | |
169 | + }); | |
170 | + } | |
171 | + /** | |
172 | + * 删除事件 | |
173 | + */ | |
174 | + async function handleDelete(record) { | |
175 | + await deleteOne({id: record.id}, reload); | |
176 | + } | |
177 | + /** | |
178 | + * 批量删除事件 | |
179 | + */ | |
180 | + async function batchHandleDelete() { | |
181 | + await batchDelete({ids: selectedRowKeys.value}, reload); | |
182 | + } | |
183 | + /** | |
184 | + * 成功回调 | |
185 | + */ | |
186 | + function handleSuccess() { | |
187 | + reload(); | |
188 | + } | |
189 | + /** | |
190 | + * 操作栏 | |
191 | + */ | |
192 | + function getTableAction(record){ | |
193 | + return [ | |
194 | + { | |
195 | + label: '编辑', | |
196 | + onClick: handleEdit.bind(null, record), | |
197 | + } | |
198 | + ] | |
199 | + } | |
200 | + /** | |
201 | + * 下拉操作栏 | |
202 | + */ | |
203 | + function getDropDownAction(record){ | |
204 | + return [ | |
205 | + { | |
206 | + label: '详情', | |
207 | + onClick: handleDetail.bind(null, record), | |
208 | + }, { | |
209 | + label: '删除', | |
210 | + popConfirm: { | |
211 | + title: '是否确认删除', | |
212 | + confirm: handleDelete.bind(null, record), | |
213 | + } | |
214 | + } | |
215 | + ] | |
216 | + } | |
217 | + <#if list_need_category> | |
218 | + /** | |
219 | + * 初始化字典配置 | |
220 | + */ | |
221 | + function initDictConfig(){ | |
222 | + <#list columns as po> | |
223 | + <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'> | |
224 | + <#if po.classType=='cat_tree' && list_need_category==true> | |
225 | + loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => { | |
226 | + if (res) { | |
227 | + let allDictDate = getAuthCache(DB_DICT_DATA_KEY); | |
228 | + if(!allDictDate['${po.dictField?default("")}']){ | |
229 | + Object.assign(allDictDate,{'${po.dictField?default("")}':res}) | |
230 | + } | |
231 | + setAuthCache(DB_DICT_DATA_KEY,allDictDate) | |
232 | + } | |
233 | + }) | |
234 | + </#if> | |
235 | + </#if> | |
236 | + </#list> | |
237 | + } | |
238 | + initDictConfig(); | |
239 | + </#if> | |
240 | +</script> | |
241 | + | |
242 | +<style scoped> | |
243 | + | |
244 | +</style> | |
0 | 245 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +<#list subTables as sub><#rt/> | |
13 | + ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId', | |
14 | +</#list> | |
15 | +} | |
16 | +/** | |
17 | + * 导出api | |
18 | + * @param params | |
19 | + */ | |
20 | +export const getExportUrl = Api.exportXls; | |
21 | + | |
22 | +/** | |
23 | + * 导入api | |
24 | + */ | |
25 | +export const getImportUrl = Api.importExcel; | |
26 | +<#list subTables as sub><#rt/> | |
27 | +/** | |
28 | + * 子表单查询接口 | |
29 | + * @param params | |
30 | + */ | |
31 | +export const query${sub.entityName} = Api.${sub.entityName?uncap_first}List | |
32 | +</#list> | |
33 | +/** | |
34 | + * 列表接口 | |
35 | + * @param params | |
36 | + */ | |
37 | +export const list = (params) => | |
38 | + defHttp.get({url: Api.list, params}); | |
39 | + | |
40 | +/** | |
41 | + * 删除单个 | |
42 | + */ | |
43 | +export const deleteOne = (params,handleSuccess) => { | |
44 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
45 | + handleSuccess(); | |
46 | + }); | |
47 | +} | |
48 | +/** | |
49 | + * 批量删除 | |
50 | + * @param params | |
51 | + */ | |
52 | +export const batchDelete = (params, handleSuccess) => { | |
53 | + Modal.confirm({ | |
54 | + title: '确认删除', | |
55 | + content: '是否删除选中数据', | |
56 | + okText: '确认', | |
57 | + cancelText: '取消', | |
58 | + onOk: () => { | |
59 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
60 | + handleSuccess(); | |
61 | + }); | |
62 | + } | |
63 | + }); | |
64 | +} | |
65 | +/** | |
66 | + * 保存或者更新 | |
67 | + * @param params | |
68 | + */ | |
69 | +export const saveOrUpdate = (params, isUpdate) => { | |
70 | + let url = isUpdate ? Api.edit : Api.save; | |
71 | + return defHttp.post({url: url, params}); | |
72 | +} | |
73 | +<#list subTables as sub><#rt/> | |
74 | +/** | |
75 | + * 子表列表接口 | |
76 | + * @param params | |
77 | + */ | |
78 | +export const ${sub.entityName?uncap_first}List = (params) => | |
79 | + defHttp.get({url: Api.${sub.entityName?uncap_first}List, params},{isTransformResponse:false}); | |
80 | +</#list> | |
0 | 81 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types' | |
6 | +//列表数据 | |
7 | +export const columns: BasicColumn[] = [ | |
8 | + <#list columns as po> | |
9 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
10 | + { | |
11 | + title: '${po.filedComment}', | |
12 | + align:"center", | |
13 | + <#if po.sort=='Y'> | |
14 | + sorter: true, | |
15 | + </#if> | |
16 | + <#if po.classType=='date'> | |
17 | + dataIndex: '${po.fieldName}', | |
18 | + customRender:({text}) =>{ | |
19 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
20 | + }, | |
21 | + <#elseif po.fieldDbType=='Blob'> | |
22 | + dataIndex: '${po.fieldName}String' | |
23 | + <#elseif po.classType=='umeditor'> | |
24 | + dataIndex: '${po.fieldName}', | |
25 | + slots: { customRender: 'htmlSlot' }, | |
26 | + <#elseif po.classType=='pca'> | |
27 | + dataIndex: '${po.fieldName}', | |
28 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
29 | + <#elseif po.classType=='file'> | |
30 | + dataIndex: '${po.fieldName}', | |
31 | + slots: { customRender: 'fileSlot' }, | |
32 | + <#elseif po.classType=='image'> | |
33 | + dataIndex: '${po.fieldName}', | |
34 | + customRender:render.renderAvatar, | |
35 | + <#elseif po.classType=='switch'> | |
36 | + dataIndex: '${po.fieldName}', | |
37 | +<#assign switch_extend_arr=['Y','N']> | |
38 | +<#if po.dictField?default("")?contains("[")> | |
39 | +<#assign switch_extend_arr=po.dictField?eval> | |
40 | +</#if> | |
41 | +<#list switch_extend_arr as a> | |
42 | +<#if a_index == 0> | |
43 | +<#assign switch_extend_arr1=a> | |
44 | +<#else> | |
45 | +<#assign switch_extend_arr2=a> | |
46 | +</#if> | |
47 | +</#list> | |
48 | + customRender:({text}) => { | |
49 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
50 | + }, | |
51 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
52 | + dataIndex: '${po.fieldName}_dictText' | |
53 | + <#elseif po.classType=='cat_tree'> | |
54 | + dataIndex: '${po.fieldName}', | |
55 | + <#if po.dictText?default("")?trim?length == 0> | |
56 | + customRender:({text}) => { | |
57 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
58 | + }, | |
59 | + <#else> | |
60 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
61 | + </#if> | |
62 | + <#else> | |
63 | + dataIndex: '${po.fieldName}' | |
64 | + </#if> | |
65 | + }, | |
66 | + </#if> | |
67 | + </#list> | |
68 | +]; | |
69 | +//查询数据 | |
70 | +export const searchFormSchema: FormSchema[] = [ | |
71 | +<#-- 开始循环 --> | |
72 | +<#list columns as po> | |
73 | +<#if po.fieldDbName=='bpm_status'> | |
74 | + <#assign bpm_flag=true> | |
75 | +</#if> | |
76 | +<#if po.isQuery=='Y'> | |
77 | +<#assign query_flag=true> | |
78 | + <#assign query_field_dictCode=""> | |
79 | + <#if po.dictTable?default("")?trim?length gt 1> | |
80 | + <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
81 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
82 | + <#assign query_field_dictCode="${po.dictField}"> | |
83 | + </#if> | |
84 | +<#if po.queryMode=='single'> | |
85 | + { | |
86 | + label: "${po.filedComment}", | |
87 | + field: "${po.fieldName}", | |
88 | +<#if po.classType=='sel_search'> | |
89 | + component: 'JSearchSelect', | |
90 | + componentProps:{ | |
91 | + dict:"${po.dictTable},${po.dictText},${po.dictField}" | |
92 | + }, | |
93 | +<#elseif po.classType=='sel_user'> | |
94 | + component: 'JSelectUserByDept', | |
95 | +<#elseif po.classType=='switch'> | |
96 | + component: 'JSwitch', | |
97 | + componentProps:{ | |
98 | + <#if po.dictField != 'is_open'> | |
99 | + options:"${po.dictField}" | |
100 | + </#if> | |
101 | + }, | |
102 | + <#elseif po.classType=='sel_depart'> | |
103 | + component: 'JSelectDept', | |
104 | + <#elseif po.classType=='list_multi'> | |
105 | + component: 'JMultiSelectTag',//暂无该组件 | |
106 | + componentProps:{ | |
107 | + dictCode:"query_field_dictCode?default("")" | |
108 | + }, | |
109 | + <#elseif po.classType=='cat_tree'> | |
110 | + component: 'JCategorySelect', | |
111 | + componentProps:{ | |
112 | + pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题 | |
113 | + }, | |
114 | +<#elseif po.classType=='date'> | |
115 | + component: 'DatePicker', | |
116 | +<#elseif po.classType=='datetime'> | |
117 | + component: 'DatePicker', | |
118 | + componentProps: { | |
119 | + showTime:true | |
120 | + }, | |
121 | +<#elseif po.classType=='pca'> | |
122 | + component: 'JAreaLinkage', | |
123 | +<#elseif po.classType=='popup'> | |
124 | + component: 'JPopup', | |
125 | + componentProps: ({ formActionType }) => { | |
126 | + const {setFieldsValue} = formActionType; | |
127 | + return{ | |
128 | + setFieldsValue:setFieldsValue, | |
129 | + code:"${po.dictTable}", | |
130 | + fieldConfig:"${po.dictField}", | |
131 | + multi:${po.extendParams.popupMulti?c}, | |
132 | + } | |
133 | + }, | |
134 | +<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'> | |
135 | +<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- --> | |
136 | + component: 'JDictSelectTag', | |
137 | + componentProps:{ | |
138 | + <#if po.dictTable?default("")?trim?length gt 1> | |
139 | + dictCode:"${po.dictTable},${po.dictText},${po.dictField}" | |
140 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
141 | + dictCode:"${po.dictField}" | |
142 | + </#if> | |
143 | + }, | |
144 | +<#else> | |
145 | + component: 'Input', | |
146 | +</#if> | |
147 | + colProps: {span: 6}, | |
148 | + }, | |
149 | +<#else> | |
150 | + { | |
151 | + label: "${po.filedComment}", | |
152 | + field: "${po.fieldName}", | |
153 | +<#if po.classType=='date'> | |
154 | + component: 'RangePicker', | |
155 | +<#elseif po.classType=='datetime'> | |
156 | + component: 'RangePicker', | |
157 | + componentProps: { | |
158 | + showTime:true | |
159 | + }, | |
160 | +<#else> | |
161 | + component: 'Input', //TODO 范围查询 | |
162 | +</#if> | |
163 | + colProps: {span: 6}, | |
164 | + }, | |
165 | +</#if> | |
166 | +</#if> | |
167 | +</#list> | |
168 | +<#-- 结束循环 --> | |
169 | +]; | |
170 | +//表单数据 | |
171 | +export const formSchema: FormSchema[] = [ | |
172 | +<#assign form_cat_tree = false> | |
173 | +<#assign form_cat_back = ""> | |
174 | +<#assign bpm_flag=false> | |
175 | +<#list columns as po><#rt/> | |
176 | +<#if po.fieldDbName=='bpm_status'> | |
177 | + <#assign bpm_flag=true> | |
178 | +</#if> | |
179 | +<#if po.isShow =='Y'> | |
180 | +<#assign form_field_dictCode=""> | |
181 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
182 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
183 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
184 | + <#assign form_field_dictCode="${po.dictField}"> | |
185 | + </#if> | |
186 | + { | |
187 | + label: '${po.filedComment}', | |
188 | + field: '${po.fieldName}', | |
189 | + <#if po.classType =='date'> | |
190 | + component: 'DatePicker', | |
191 | + <#elseif po.fieldType =='datetime'> | |
192 | + component: 'DatePicker', | |
193 | + componentProps: { | |
194 | + showTime:true | |
195 | + }, | |
196 | + <#elseif po.fieldType =='time'> | |
197 | + component: 'TimePicker', | |
198 | + <#elseif po.classType =='popup'> | |
199 | + component: 'JPopup', | |
200 | + componentProps: ({ formActionType }) => { | |
201 | + const {setFieldsValue} = formActionType; | |
202 | + return{ | |
203 | + setFieldsValue:setFieldsValue, | |
204 | + code:"${po.dictTable}", | |
205 | + fieldConfig:${po.dictField}, | |
206 | + multi:${po.extendParams.popupMulti?c}, | |
207 | + } | |
208 | + } | |
209 | + <#elseif po.classType =='sel_depart'> | |
210 | + component: 'JSelectDept', | |
211 | + <#elseif po.classType =='switch'> | |
212 | + component: 'JSwitch', | |
213 | + componentProps:{ | |
214 | + <#if po.dictField != 'is_open'> | |
215 | + options:${po.dictField} | |
216 | + </#if> | |
217 | + } | |
218 | + <#elseif po.classType =='pca'> | |
219 | + component: 'JAreaLinkage', | |
220 | + <#elseif po.classType =='markdown'> | |
221 | + component: 'JMarkdownEditor',//注意string转换问题 | |
222 | + <#elseif po.classType =='password'> | |
223 | + component: 'InputPassword', | |
224 | + <#elseif po.classType =='sel_user'> | |
225 | + component: 'JSelectUserByDept', | |
226 | + componentProps:{ | |
227 | + labelKey:'realname', | |
228 | + } | |
229 | + <#elseif po.classType =='textarea'> | |
230 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
231 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
232 | + component: 'JDictSelectTag', | |
233 | + componentProps:{ | |
234 | + dictCode:"${form_field_dictCode}" | |
235 | + } | |
236 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
237 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
238 | + componentProps:{ | |
239 | + dictCode:"${form_field_dictCode}" | |
240 | + } | |
241 | + <#elseif po.classType=='sel_search'> | |
242 | + component: 'JSearchSelect', | |
243 | + componentProps:{ | |
244 | + dict:"${form_field_dictCode}" | |
245 | + } | |
246 | +<#elseif po.classType=='cat_tree'> | |
247 | + <#assign form_cat_tree = true> | |
248 | + component: 'JCategorySelect', | |
249 | + componentProps:{ | |
250 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
251 | + } | |
252 | + <#if po.dictText?default("")?trim?length gt 1> | |
253 | + <#assign form_cat_back = "${po.dictText}"> | |
254 | + </#if> | |
255 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
256 | + component: 'InputNumber', | |
257 | + <#elseif po.classType=='file'> | |
258 | + component: 'JUpload', | |
259 | + componentProps:{ | |
260 | + <#if po.uploadnum??> | |
261 | + maxCount:${po.uploadnum} | |
262 | + </#if> | |
263 | + } | |
264 | + <#elseif po.classType=='image'> | |
265 | + component: 'JImageUpload', | |
266 | + componentProps:{ | |
267 | + <#if po.uploadnum??> | |
268 | + fileMax:${po.uploadnum} | |
269 | + </#if> | |
270 | + } | |
271 | + <#elseif po.classType=='umeditor'> | |
272 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
273 | + <#elseif po.classType == 'sel_tree'> | |
274 | + component: 'JTreeSelect', | |
275 | + componentProps:{ | |
276 | + <#if po.dictText??> | |
277 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
278 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
279 | + <#elseif po.dictText?split(',')[1]??> | |
280 | + pidField:"${po.dictText?split(',')[1]}", | |
281 | + <#elseif po.dictText?split(',')[3]??> | |
282 | + hasChildField:"${po.dictText?split(',')[3]}", | |
283 | + </#if> | |
284 | + </#if> | |
285 | + pidValue:"${po.dictField}", | |
286 | + } | |
287 | + <#else> | |
288 | + component: 'Input', | |
289 | + </#if> | |
290 | + <#include "/common/utils.ftl"> | |
291 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
292 | + dynamicRules: ({model,schema}) => { | |
293 | + <#if po.fieldName != 'id'> | |
294 | + <#assign fieldValidType = po.fieldValidType!''> | |
295 | + return [ | |
296 | + <#-- 非空校验 --> | |
297 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
298 | + { required: true, message: '请输入${po.filedComment}!'}, | |
299 | + <#elseif fieldValidType!=''> | |
300 | + { required: false}, | |
301 | + </#if> | |
302 | + <#-- 唯一校验 --> | |
303 | + <#if fieldValidType == 'only'> | |
304 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
305 | + <#-- 6到16位数字 --> | |
306 | + <#elseif fieldValidType == 'n6-16'> | |
307 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
308 | + <#-- 6到16位任意字符 --> | |
309 | + <#elseif fieldValidType == '*6-16'> | |
310 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
311 | + <#-- 6到18位字符串 --> | |
312 | + <#elseif fieldValidType == 's6-18'> | |
313 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
314 | + <#-- 网址 --> | |
315 | + <#elseif fieldValidType == 'url'> | |
316 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
317 | + <#-- 电子邮件 --> | |
318 | + <#elseif fieldValidType == 'e'> | |
319 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
320 | + <#-- 手机号码 --> | |
321 | + <#elseif fieldValidType == 'm'> | |
322 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
323 | + <#-- 邮政编码 --> | |
324 | + <#elseif fieldValidType == 'p'> | |
325 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
326 | + <#-- 字母 --> | |
327 | + <#elseif fieldValidType == 's'> | |
328 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
329 | + <#-- 数字 --> | |
330 | + <#elseif fieldValidType == 'n'> | |
331 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
332 | + <#-- 整数 --> | |
333 | + <#elseif fieldValidType == 'z'> | |
334 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
335 | + <#-- 金额 --> | |
336 | + <#elseif fieldValidType == 'money'> | |
337 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
338 | + <#-- 正则校验 --> | |
339 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
340 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
341 | + <#-- 无校验 --> | |
342 | + <#else> | |
343 | + <#t> | |
344 | + </#if> | |
345 | + ]; | |
346 | + </#if> | |
347 | + }, | |
348 | + </#if> | |
349 | + <#if po.readonly=='Y'> | |
350 | + dynamicDisabled:true | |
351 | + </#if> | |
352 | + }, | |
353 | +</#if> | |
354 | +</#list> | |
355 | +]; | |
356 | +//子表单数据 | |
357 | +<#list subTables as sub> | |
358 | +//子表列表数据 | |
359 | +export const ${sub.entityName?uncap_first}Columns: BasicColumn[] = [ | |
360 | + <#list sub.originalColumns as po> | |
361 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
362 | + { | |
363 | + title: '${po.filedComment}', | |
364 | + align:"center", | |
365 | + <#if po.sort=='Y'> | |
366 | + sorter: true, | |
367 | + </#if> | |
368 | + <#if po.classType=='date'> | |
369 | + dataIndex: '${po.fieldName}', | |
370 | + customRender:({text}) =>{ | |
371 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
372 | + }, | |
373 | + <#elseif po.fieldDbType=='Blob'> | |
374 | + dataIndex: '${po.fieldName}String' | |
375 | + <#elseif po.classType=='umeditor'> | |
376 | + dataIndex: '${po.fieldName}', | |
377 | + slots: { customRender: 'htmlSlot' }, | |
378 | + <#elseif po.classType=='pca'> | |
379 | + dataIndex: '${po.fieldName}', | |
380 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
381 | + <#elseif po.classType=='file'> | |
382 | + dataIndex: '${po.fieldName}', | |
383 | + slots: { customRender: 'fileSlot' }, | |
384 | + <#elseif po.classType=='image'> | |
385 | + dataIndex: '${po.fieldName}', | |
386 | + customRender:render.renderAvatar, | |
387 | + <#elseif po.classType=='switch'> | |
388 | + dataIndex: '${po.fieldName}', | |
389 | +<#assign switch_extend_arr=['Y','N']> | |
390 | +<#if po.dictField?default("")?contains("[")> | |
391 | +<#assign switch_extend_arr=po.dictField?eval> | |
392 | +</#if> | |
393 | +<#list switch_extend_arr as a> | |
394 | +<#if a_index == 0> | |
395 | +<#assign switch_extend_arr1=a> | |
396 | +<#else> | |
397 | +<#assign switch_extend_arr2=a> | |
398 | +</#if> | |
399 | +</#list> | |
400 | + customRender:({text}) => { | |
401 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
402 | + }, | |
403 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
404 | + dataIndex: '${po.fieldName}_dictText' | |
405 | + <#elseif po.classType=='cat_tree'> | |
406 | + dataIndex: '${po.fieldName}', | |
407 | + <#if po.dictText?default("")?trim?length == 0> | |
408 | + customRender:({text}) => { | |
409 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
410 | + }, | |
411 | + <#else> | |
412 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
413 | + </#if> | |
414 | + <#else> | |
415 | + dataIndex: '${po.fieldName}' | |
416 | + </#if> | |
417 | + }, | |
418 | + </#if> | |
419 | + </#list> | |
420 | +]; | |
421 | +<#if sub.foreignRelationType =='1'> | |
422 | +export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [ | |
423 | +<#assign form_cat_tree = false> | |
424 | +<#assign form_cat_back = ""> | |
425 | +<#assign bpm_flag=false> | |
426 | +<#list sub.colums as po><#rt/> | |
427 | +<#if po.fieldDbName=='bpm_status'> | |
428 | + <#assign bpm_flag=true> | |
429 | +</#if> | |
430 | +<#if po.isShow =='Y'> | |
431 | +<#assign form_field_dictCode=""> | |
432 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
433 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
434 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
435 | + <#assign form_field_dictCode="${po.dictField}"> | |
436 | + </#if> | |
437 | + { | |
438 | + label: '${po.filedComment}', | |
439 | + field: '${po.fieldName}', | |
440 | + <#if po.classType =='date'> | |
441 | + component: 'DatePicker', | |
442 | + <#elseif po.fieldType =='datetime'> | |
443 | + component: 'DatePicker', | |
444 | + componentProps: { | |
445 | + showTime:true | |
446 | + }, | |
447 | + <#elseif po.fieldType =='time'> | |
448 | + component: 'TimePicker', | |
449 | + <#elseif po.classType =='popup'> | |
450 | + component: 'JPopup', | |
451 | + componentProps: ({ formActionType }) => { | |
452 | + const {setFieldsValue} = formActionType; | |
453 | + return{ | |
454 | + setFieldsValue:setFieldsValue, | |
455 | + code:"${po.dictTable}", | |
456 | + fieldConfig:${po.dictField}, | |
457 | + multi:${po.extendParams.popupMulti?c}, | |
458 | + } | |
459 | + } | |
460 | + <#elseif po.classType =='sel_depart'> | |
461 | + component: 'JSelectDept', | |
462 | + <#elseif po.classType =='switch'> | |
463 | + component: 'JSwitch', | |
464 | + componentProps:{ | |
465 | + <#if po.dictField != 'is_open'> | |
466 | + options:${po.dictField} | |
467 | + </#if> | |
468 | + } | |
469 | + <#elseif po.classType =='pca'> | |
470 | + component: 'JAreaLinkage', | |
471 | + <#elseif po.classType =='markdown'> | |
472 | + component: 'JMarkdownEditor',//注意string转换问题 | |
473 | + <#elseif po.classType =='password'> | |
474 | + component: 'InputPassword', | |
475 | + <#elseif po.classType =='sel_user'> | |
476 | + component: 'JSelectUserByDept', | |
477 | + componentProps:{ | |
478 | + labelKey:'realname', | |
479 | + } | |
480 | + <#elseif po.classType =='textarea'> | |
481 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
482 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
483 | + component: 'JDictSelectTag', | |
484 | + componentProps:{ | |
485 | + dictCode:"${form_field_dictCode}" | |
486 | + } | |
487 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
488 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
489 | + componentProps:{ | |
490 | + dictCode:"${form_field_dictCode}" | |
491 | + } | |
492 | + <#elseif po.classType=='sel_search'> | |
493 | + component: 'JSearchSelect', | |
494 | + componentProps:{ | |
495 | + dict:"${form_field_dictCode}" | |
496 | + } | |
497 | +<#elseif po.classType=='cat_tree'> | |
498 | + <#assign form_cat_tree = true> | |
499 | + component: 'JCategorySelect', | |
500 | + componentProps:{ | |
501 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
502 | + } | |
503 | + <#if po.dictText?default("")?trim?length gt 1> | |
504 | + <#assign form_cat_back = "${po.dictText}"> | |
505 | + </#if> | |
506 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
507 | + component: 'InputNumber', | |
508 | + <#elseif po.classType=='file'> | |
509 | + component: 'JUpload', | |
510 | + componentProps:{ | |
511 | + <#if po.uploadnum??> | |
512 | + maxCount:${po.uploadnum} | |
513 | + </#if> | |
514 | + } | |
515 | + <#elseif po.classType=='image'> | |
516 | + component: 'JImageUpload', | |
517 | + componentProps:{ | |
518 | + <#if po.uploadnum??> | |
519 | + fileMax:${po.uploadnum} | |
520 | + </#if> | |
521 | + } | |
522 | + <#elseif po.classType=='umeditor'> | |
523 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
524 | + <#elseif po.classType == 'sel_tree'> | |
525 | + component: 'JTreeSelect', | |
526 | + componentProps:{ | |
527 | + <#if po.dictText??> | |
528 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
529 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
530 | + <#elseif po.dictText?split(',')[1]??> | |
531 | + pidField:"${po.dictText?split(',')[1]}", | |
532 | + <#elseif po.dictText?split(',')[3]??> | |
533 | + hasChildField:"${po.dictText?split(',')[3]}", | |
534 | + </#if> | |
535 | + </#if> | |
536 | + pidValue:"${po.dictField}", | |
537 | + } | |
538 | + <#else> | |
539 | + component: 'Input', | |
540 | + </#if> | |
541 | + <#include "/common/utils.ftl"> | |
542 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
543 | + dynamicRules: ({model,schema}) => { | |
544 | + <#if po.fieldName != 'id'> | |
545 | + <#assign fieldValidType = po.fieldValidType!''> | |
546 | + return [ | |
547 | + <#-- 非空校验 --> | |
548 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
549 | + { required: true, message: '请输入${po.filedComment}!'}, | |
550 | + <#elseif fieldValidType!=''> | |
551 | + { required: false}, | |
552 | + </#if> | |
553 | + <#-- 唯一校验 --> | |
554 | + <#if fieldValidType == 'only'> | |
555 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
556 | + <#-- 6到16位数字 --> | |
557 | + <#elseif fieldValidType == 'n6-16'> | |
558 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
559 | + <#-- 6到16位任意字符 --> | |
560 | + <#elseif fieldValidType == '*6-16'> | |
561 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
562 | + <#-- 6到18位字符串 --> | |
563 | + <#elseif fieldValidType == 's6-18'> | |
564 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
565 | + <#-- 网址 --> | |
566 | + <#elseif fieldValidType == 'url'> | |
567 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
568 | + <#-- 电子邮件 --> | |
569 | + <#elseif fieldValidType == 'e'> | |
570 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
571 | + <#-- 手机号码 --> | |
572 | + <#elseif fieldValidType == 'm'> | |
573 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
574 | + <#-- 邮政编码 --> | |
575 | + <#elseif fieldValidType == 'p'> | |
576 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
577 | + <#-- 字母 --> | |
578 | + <#elseif fieldValidType == 's'> | |
579 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
580 | + <#-- 数字 --> | |
581 | + <#elseif fieldValidType == 'n'> | |
582 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
583 | + <#-- 整数 --> | |
584 | + <#elseif fieldValidType == 'z'> | |
585 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
586 | + <#-- 金额 --> | |
587 | + <#elseif fieldValidType == 'money'> | |
588 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
589 | + <#-- 正则校验 --> | |
590 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
591 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
592 | + <#-- 无校验 --> | |
593 | + <#else> | |
594 | + <#t> | |
595 | + </#if> | |
596 | + ]; | |
597 | + </#if> | |
598 | + }, | |
599 | + </#if> | |
600 | + <#if po.readonly=='Y'> | |
601 | + dynamicDisabled:true | |
602 | + </#if> | |
603 | + }, | |
604 | +</#if> | |
605 | +</#list> | |
606 | +]; | |
607 | +</#if> | |
608 | +</#list> | |
609 | +//子表表格配置 | |
610 | +<#list subTables as sub> | |
611 | +<#if sub.foreignRelationType =='0'> | |
612 | +export const ${sub.entityName?uncap_first}JVxeColumns: JVxeColumn[] = [ | |
613 | +<#assign popupBackFields = ""> | |
614 | + | |
615 | +<#-- 循环子表的列 开始 --> | |
616 | +<#list sub.colums as col><#rt/> | |
617 | +<#if col.isShow =='Y'> | |
618 | +<#if col.filedComment !='外键' > | |
619 | + { | |
620 | + title: '${col.filedComment}', | |
621 | + key: '${autoStringSuffixForModel(col)}', | |
622 | +<#if col.classType =='date'> | |
623 | + type: JVxeTypes.date, | |
624 | + <#if col.readonly=='Y'> | |
625 | + disabled:true, | |
626 | + </#if> | |
627 | +<#elseif col.classType =='datetime'> | |
628 | + type: JVxeTypes.datetime, | |
629 | + <#if col.readonly=='Y'> | |
630 | + disabled:true, | |
631 | + </#if> | |
632 | +<#elseif col.classType =='textarea'> | |
633 | + type: JVxeTypes.textarea, | |
634 | + <#if col.readonly=='Y'> | |
635 | + disabled:true, | |
636 | + </#if> | |
637 | +<#elseif "int,decimal,double,"?contains(col.classType)> | |
638 | + type: JVxeTypes.inputNumber, | |
639 | + <#if col.readonly=='Y'> | |
640 | + disabled:true, | |
641 | + </#if> | |
642 | +<#elseif col.classType =='list' || col.classType =='radio'> | |
643 | + type: JVxeTypes.select, | |
644 | + options:[], | |
645 | + <#if col.dictTable?default("")?trim?length gt 1> | |
646 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
647 | + <#else> | |
648 | + dictCode:"${col.dictField}", | |
649 | + </#if> | |
650 | + <#if col.readonly=='Y'> | |
651 | + disabled:true, | |
652 | + </#if> | |
653 | +<#elseif col.classType =='list_multi' || col.classType =='checkbox'> | |
654 | + type: JVxeTypes.selectMultiple, | |
655 | + options:[], | |
656 | + <#if col.dictTable?default("")?trim?length gt 1> | |
657 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
658 | + <#else> | |
659 | + dictCode:"${col.dictField}", | |
660 | + </#if> | |
661 | + <#if col.readonly=='Y'> | |
662 | + disabled:true, | |
663 | + </#if> | |
664 | +<#elseif col.classType =='sel_search'> | |
665 | + type: JVxeTypes.selectSearch, | |
666 | + <#if col.dictTable?default("")?trim?length gt 1> | |
667 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
668 | + <#else> | |
669 | + dictCode:"${col.dictField}", | |
670 | + </#if> | |
671 | + <#if col.readonly=='Y'> | |
672 | + disabled:true, | |
673 | + </#if> | |
674 | +<#elseif col.classType =='image'> | |
675 | + type: JVxeTypes.image, | |
676 | + token:true, | |
677 | + responseName:"message", | |
678 | + <#if col.readonly=='Y'> | |
679 | + disabled:true, | |
680 | + </#if> | |
681 | + <#if col.uploadnum??> | |
682 | + number: ${col.uploadnum}, | |
683 | + </#if> | |
684 | +<#elseif col.classType =='file'> | |
685 | + type: JVxeTypes.file, | |
686 | + token:true, | |
687 | + responseName:"message", | |
688 | + <#if col.readonly=='Y'> | |
689 | + disabled:true, | |
690 | + </#if> | |
691 | + <#if col.uploadnum??> | |
692 | + number: ${col.uploadnum}, | |
693 | + </#if> | |
694 | +<#elseif col.classType =='switch'> | |
695 | + type: JVxeTypes.checkbox, | |
696 | + <#if col.dictField == 'is_open'> | |
697 | + customValue: ['Y', 'N'], | |
698 | + <#else> | |
699 | + customValue: ${col.dictField}, | |
700 | + </#if> | |
701 | + <#if col.readonly=='Y'> | |
702 | + disabled:true, | |
703 | + </#if> | |
704 | +<#elseif col.classType =='popup'> | |
705 | +<#if popupBackFields?length gt 0> | |
706 | + <#assign popupBackFields = "${popupBackFields}"+","+"${col.dictText}"> | |
707 | +<#else> | |
708 | + <#assign popupBackFields = "${col.dictText}"> | |
709 | +</#if> | |
710 | + type: JVxeTypes.popup, | |
711 | + popupCode:"${col.dictTable}", | |
712 | + field:"${col.dictField}", | |
713 | + orgFields:"${col.dictField}", | |
714 | + destFields:"${Format.underlineToHump(col.dictText)}", | |
715 | + <#if col.readonly=='Y'> | |
716 | + disabled:true, | |
717 | + </#if> | |
718 | +<#else> | |
719 | + type: JVxeTypes.input, | |
720 | + <#if col.readonly=='Y'> | |
721 | + disabled:true, | |
722 | + </#if> | |
723 | +</#if> | |
724 | +<#if col.classType =='list_multi' || col.classType =='checkbox'> | |
725 | + width:"250px", | |
726 | +<#else> | |
727 | + width:"200px", | |
728 | +</#if> | |
729 | +<#if col.classType =='file'> | |
730 | + placeholder: '请选择文件', | |
731 | +<#else> | |
732 | + placeholder: '请输入${'$'}{title}', | |
733 | +</#if> | |
734 | +<#if col.defaultVal??> | |
735 | +<#if col.fieldDbType=="BigDecimal" || col.fieldDbType=="double" || col.fieldDbType=="int"> | |
736 | + defaultValue:${col.defaultVal}, | |
737 | + <#else> | |
738 | + defaultValue:"${col.defaultVal}", | |
739 | +</#if> | |
740 | +<#else> | |
741 | + defaultValue:'', | |
742 | +</#if> | |
743 | +<#-- 子表的校验 --> | |
744 | +<#assign subFieldValidType = col.fieldValidType!''> | |
745 | +<#-- 非空校验 --> | |
746 | +<#if col.nullable == 'N' || subFieldValidType == '*'> | |
747 | + validateRules: [{ required: true, message: '${'$'}{title}不能为空' }], | |
748 | +<#-- 其他情况下,只要有值就被认为是正则校验 --> | |
749 | +<#elseif subFieldValidType?length gt 0> | |
750 | +<#assign subMessage = '格式不正确'> | |
751 | +<#if subFieldValidType == 'only' > | |
752 | + <#assign subMessage = '不能重复'> | |
753 | +</#if> | |
754 | + validateRules: [{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }], | |
755 | +</#if> | |
756 | + }, | |
757 | +</#if> | |
758 | +</#if> | |
759 | +</#list> | |
760 | +<#-- 循环子表的列 结束 --> | |
761 | + ] | |
762 | +</#if> | |
763 | +</#list> | |
0 | 764 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |
3 | + <BasicForm @register="registerForm" ref="formRef"/> | |
4 | + <!-- 子表单区域 --> | |
5 | + <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs"> | |
6 | +<#list subTables as sub><#rt/> | |
7 | + <#if sub.foreignRelationType =='1'> | |
8 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true"> | |
9 | + <${sub.entityName}Form ref="${sub.entityName?uncap_first}Form"></${sub.entityName}Form> | |
10 | + </a-tab-pane> | |
11 | + | |
12 | + <#else> | |
13 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true"> | |
14 | + <JVxeTable | |
15 | + keep-source | |
16 | + resizable | |
17 | + :ref="refKeys[${sub_index}]" | |
18 | + :loading="${sub.entityName?uncap_first}Table.loading" | |
19 | + :columns="${sub.entityName?uncap_first}Table.columns" | |
20 | + :dataSource="${sub.entityName?uncap_first}Table.dataSource" | |
21 | + :maxHeight="300" | |
22 | + :rowNumber="true" | |
23 | + :rowSelection="true" | |
24 | + :toolbar="true" | |
25 | + /> | |
26 | + </a-tab-pane> | |
27 | + </#if> | |
28 | +</#list> | |
29 | + </a-tabs> | |
30 | + </BasicModal> | |
31 | +</template> | |
32 | + | |
33 | +<script lang="ts" setup> | |
34 | + import {ref, computed, unref,reactive} from 'vue'; | |
35 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
36 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
37 | + import { JVxeTable } from '/@/components/jeecg/JVxeTable' | |
38 | + import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts' | |
39 | + <#list subTables as sub> | |
40 | + <#if sub.foreignRelationType =='1'> | |
41 | + import ${sub.entityName}Form from './${sub.entityName}Form.vue' | |
42 | + </#if> | |
43 | + </#list> | |
44 | + import {formSchema<#list subTables as sub><#if sub.foreignRelationType =='0'>,${sub.entityName?uncap_first}JVxeColumns</#if></#list>} from '../${entityName?uncap_first}.data'; | |
45 | + import {saveOrUpdate<#list subTables as sub>,query${sub.entityName}</#list>} from '../${entityName?uncap_first}.api'; | |
46 | + import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils' | |
47 | + // Emits声明 | |
48 | + const emit = defineEmits(['register','success']); | |
49 | + const isUpdate = ref(true); | |
50 | + const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]); | |
51 | + <#assign hasOne2Many = false> | |
52 | + <#assign hasOne2One = false> | |
53 | + const activeKey = ref('${subTables[0].entityName?uncap_first}'); | |
54 | +<#list subTables as sub> | |
55 | +<#if sub.foreignRelationType =='0'> | |
56 | + <#assign hasOne2Many = true> | |
57 | + const ${sub.entityName?uncap_first} = ref(); | |
58 | +</#if> | |
59 | +<#if sub.foreignRelationType =='1'> | |
60 | + <#assign hasOne2One = true> | |
61 | + const ${sub.entityName?uncap_first}Form = ref(); | |
62 | +</#if> | |
63 | +</#list> | |
64 | + const tableRefs = {<#list subTables as sub><#if sub.foreignRelationType =='0'>${sub.entityName?uncap_first}, <#assign hasOne2Many = true></#if></#list>}; | |
65 | + <#list subTables as sub> | |
66 | + <#if sub.foreignRelationType =='0'> | |
67 | + const ${sub.entityName?uncap_first}Table = reactive({ | |
68 | + loading: false, | |
69 | + dataSource: [], | |
70 | + columns:${sub.entityName?uncap_first}JVxeColumns | |
71 | + }) | |
72 | + </#if> | |
73 | + </#list> | |
74 | + //表单配置 | |
75 | + const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |
76 | + labelWidth: 150, | |
77 | + schemas: formSchema, | |
78 | + showActionButtonGroup: false, | |
79 | + }); | |
80 | + //表单赋值 | |
81 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
82 | + //重置表单 | |
83 | + await reset(); | |
84 | + setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter}); | |
85 | + isUpdate.value = !!data?.isUpdate; | |
86 | + if (unref(isUpdate)) { | |
87 | + //表单赋值 | |
88 | + await setFieldsValue({ | |
89 | + ...data.record, | |
90 | + }); | |
91 | + <#list subTables as sub><#rt/> | |
92 | + <#if sub.foreignRelationType =='1'> | |
93 | + ${sub.entityName?uncap_first}Form.value.initFormData(query${sub.entityName},data?.record?.id) | |
94 | + </#if> | |
95 | + </#list> | |
96 | + <#list subTables as sub><#rt/> | |
97 | + <#if sub.foreignRelationType =='0'> | |
98 | + requestSubTableData(query${sub.entityName}, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table) | |
99 | + </#if> | |
100 | + </#list> | |
101 | + } | |
102 | + // 隐藏底部时禁用整个表单 | |
103 | + setProps({ disabled: !data?.showFooter }) | |
104 | + }); | |
105 | + //方法配置 | |
106 | + const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys<#if hasOne2One==true>,validateSubForm</#if>); | |
107 | + | |
108 | + //设置标题 | |
109 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
110 | + | |
111 | + async function reset(){ | |
112 | + await resetFields(); | |
113 | + activeKey.value = ref('${subTables[0].entityName?uncap_first}'); | |
114 | + <#list subTables as sub> | |
115 | + <#if sub.foreignRelationType =='0'> | |
116 | + ${sub.entityName?uncap_first}Table.dataSource = []; | |
117 | + </#if> | |
118 | + <#if sub.foreignRelationType =='1'> | |
119 | + ${sub.entityName?uncap_first}Form.value.resetFields(); | |
120 | + </#if> | |
121 | + </#list> | |
122 | + } | |
123 | + function classifyIntoFormData(allValues) { | |
124 | + let main = Object.assign({}, allValues.formValue) | |
125 | + return { | |
126 | + ...main, // 展开 | |
127 | + <#assign subManyIndex = 0> | |
128 | + <#list subTables as sub><#rt/> | |
129 | + <#if sub.foreignRelationType =='0'> | |
130 | + ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData, | |
131 | + <#assign subManyIndex = subManyIndex+1> | |
132 | + <#else> | |
133 | + ${sub.entityName?uncap_first}List: ${sub.entityName?uncap_first}Form.value.getFormData(), | |
134 | + </#if> | |
135 | + </#list> | |
136 | + } | |
137 | + } | |
138 | + <#if hasOne2One==true> | |
139 | + //校验所有一对一子表表单 | |
140 | + function validateSubForm(allValues){ | |
141 | + return new Promise((resolve,reject)=>{ | |
142 | + Promise.all([ | |
143 | + <#list subTables as sub><#rt/> | |
144 | + <#if sub.foreignRelationType =='1'> | |
145 | + ${sub.entityName?uncap_first}Form.value.validateForm(${sub_index}), | |
146 | + </#if> | |
147 | + </#list> | |
148 | + ]).then(() => { | |
149 | + resolve(allValues) | |
150 | + }).catch(e => { | |
151 | + if (e.error === VALIDATE_FAILED) { | |
152 | + // 如果有未通过表单验证的子表,就自动跳转到它所在的tab | |
153 | + activeKey.value = e.index == null ? unref(activeKey) : refKeys.value[e.index] | |
154 | + } else { | |
155 | + console.error(e) | |
156 | + } | |
157 | + }) | |
158 | + }) | |
159 | + } | |
160 | + </#if> | |
161 | + //表单提交事件 | |
162 | + async function requestAddOrEdit(values) { | |
163 | + try { | |
164 | + setModalProps({confirmLoading: true}); | |
165 | + //提交表单 | |
166 | + await saveOrUpdate(values, isUpdate.value); | |
167 | + //关闭弹窗 | |
168 | + closeModal(); | |
169 | + //刷新列表 | |
170 | + emit('success'); | |
171 | + } finally { | |
172 | + setModalProps({confirmLoading: false}); | |
173 | + } | |
174 | + } | |
175 | +</script> | |
176 | + | |
177 | +<style lang="less" scoped> | |
178 | + | |
179 | +</style> | |
0 | 180 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
0 → 100644
1 | +<#list subTables as sub> | |
2 | +<#if sub.foreignRelationType=='1'> | |
3 | +#segment#${sub.entityName}Form.vue | |
4 | +<template> | |
5 | + <BasicForm @register="registerForm"/> | |
6 | +</template> | |
7 | +<script lang="ts"> | |
8 | + import {defineComponent} from 'vue'; | |
9 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
10 | + import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data'; | |
11 | + import {defHttp} from '/@/utils/http/axios'; | |
12 | + import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils' | |
13 | + | |
14 | + export default defineComponent({ | |
15 | + name:"${sub.entityName}Form", | |
16 | + components: {BasicForm}, | |
17 | + emits:['register'], | |
18 | + setup(_,{emit}) { | |
19 | + const [registerForm, {resetFields, setFieldsValue,getFieldsValue,validate}] = useForm({ | |
20 | + labelWidth: 150, | |
21 | + schemas: ${sub.entityName?uncap_first}FormSchema, | |
22 | + showActionButtonGroup: false, | |
23 | + }); | |
24 | + /** | |
25 | + *初始化加载数据 | |
26 | + */ | |
27 | + function initFormData(url,id){ | |
28 | + if(id){ | |
29 | + defHttp.get({url,params:{id}},{isTransformResponse:false}).then(res=>{ | |
30 | + res.success && setFieldsValue({...res.result.records[0]}); | |
31 | + }) | |
32 | + } | |
33 | + } | |
34 | + /** | |
35 | + *获取表单数据 | |
36 | + */ | |
37 | + function getFormData(){ | |
38 | + return [getFieldsValue()]; | |
39 | + } | |
40 | + /** | |
41 | + *表单校验 | |
42 | + */ | |
43 | + function validateForm(index){ | |
44 | + return new Promise((resolve, reject) => { | |
45 | + // 验证子表表单 | |
46 | + validate().then(()=>{ | |
47 | + return resolve() | |
48 | + }).catch(()=> { | |
49 | + return reject({ error: VALIDATE_FAILED ,index}) | |
50 | + }) | |
51 | + }) | |
52 | + } | |
53 | + return { | |
54 | + registerForm, | |
55 | + resetFields, | |
56 | + initFormData, | |
57 | + getFormData, | |
58 | + validateForm | |
59 | + } | |
60 | + } | |
61 | + }) | |
62 | +</script> | |
63 | +</#if> | |
64 | +</#list> | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/subTables/[1-n]SubTable.vuei
0 → 100644
1 | +<#--noinspection JSDuplicatedDeclaration--> | |
2 | +<#list subTables as sub> | |
3 | +#segment#${sub.entityName}SubTable.vue | |
4 | +<template> | |
5 | + <div> | |
6 | + <#assign list_need_category=false> | |
7 | + <#assign list_need_pca=false> | |
8 | + <#assign bpm_flag=false> | |
9 | + | |
10 | + <#-- 开始循环 --> | |
11 | + <#list columns as po> | |
12 | + <#if po.fieldDbName=='bpm_status'> | |
13 | + <#assign bpm_flag=true> | |
14 | + </#if> | |
15 | + <#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0> | |
16 | + <#assign list_need_category=true> | |
17 | + </#if> | |
18 | + <#if po.classType=='pca'> | |
19 | + <#assign list_need_pca=true> | |
20 | + </#if> | |
21 | + </#list> | |
22 | + <#-- 结束循环 --> | |
23 | + <!--引用表格--> | |
24 | + <BasicTable bordered size="middle" :loading="loading" rowKey="id" :canResize="false" :columns="${sub.entityName?uncap_first}Columns" :dataSource="dataSource" :pagination="false"> | |
25 | + <!--字段回显插槽--> | |
26 | + <template #htmlSlot="{text}"> | |
27 | + <div v-html="text"></div> | |
28 | + </template> | |
29 | + <template #fileSlot="{text}"> | |
30 | + <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |
31 | + <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |
32 | + </template> | |
33 | + </BasicTable> | |
34 | + </div> | |
35 | +</template> | |
36 | + | |
37 | +<script lang="ts" setup> | |
38 | + import {ref,watchEffect} from 'vue'; | |
39 | + import {BasicTable} from '/@/components/Table'; | |
40 | + import {${sub.entityName?uncap_first}Columns} from '../${entityName}.data'; | |
41 | + import {${sub.entityName?uncap_first}List} from '../${entityName}.api'; | |
42 | + | |
43 | + const props = defineProps({ | |
44 | + id: { | |
45 | + type: String, | |
46 | + default: '', | |
47 | + }, | |
48 | + }) | |
49 | + | |
50 | + const loading = ref(false); | |
51 | + const dataSource = ref([]); | |
52 | + | |
53 | + watchEffect(() => { | |
54 | + props.id && loadData(props.id); | |
55 | + }); | |
56 | + | |
57 | + function loadData(id) { | |
58 | + dataSource.value = [] | |
59 | + loading.value = true | |
60 | + ${sub.entityName?uncap_first}List({id}).then((res) => { | |
61 | + if (res.success) { | |
62 | + dataSource.value = res.result.records | |
63 | + } | |
64 | + }).finally(() => { | |
65 | + loading.value = false | |
66 | + }) | |
67 | + } | |
68 | +</script> | |
69 | +</#list> | |
0 | 70 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
... | ... | @@ -28,13 +28,8 @@ |
28 | 28 | <#elseif po.dictField?default("")?trim?length gt 1> |
29 | 29 | <#assign form_field_dictCode="${po.dictField}"> |
30 | 30 | </#if> |
31 | - <#if po.classType =='textarea'> | |
32 | - <a-col :span="24"> | |
33 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
34 | - <#else> | |
35 | 31 | <a-col :span="${form_span}" > |
36 | 32 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
37 | - </#if> | |
38 | 33 | <#if po.classType =='date'> |
39 | 34 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/> |
40 | 35 | <#elseif po.classType =='datetime'> |
... | ... | @@ -140,7 +135,7 @@ |
140 | 135 | </#list> |
141 | 136 | </a-tabs> |
142 | 137 | <#if bpm_flag> |
143 | - <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button @click="handleOk">提 交</a-button></a-row> | |
138 | + <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button icon="check" style="width: 126px" type="primary" @click="handleOk">提 交</a-button></a-row> | |
144 | 139 | </#if> |
145 | 140 | </a-spin> |
146 | 141 | </template> |
... | ... | @@ -174,20 +169,12 @@ |
174 | 169 | return { |
175 | 170 | labelCol: { |
176 | 171 | xs: { span: 24 }, |
177 | - sm: { span: 6 }, | |
172 | + sm: { span: 5 }, | |
178 | 173 | }, |
179 | 174 | wrapperCol: { |
180 | 175 | xs: { span: 24 }, |
181 | 176 | sm: { span: 16 }, |
182 | 177 | }, |
183 | - labelCol2: { | |
184 | - xs: { span: 24 }, | |
185 | - sm: { span: 3 }, | |
186 | - }, | |
187 | - wrapperCol2: { | |
188 | - xs: { span: 24 }, | |
189 | - sm: { span: 20 }, | |
190 | - }, | |
191 | 178 | model:{ |
192 | 179 | <#include "/common/init/initValue.ftl"> |
193 | 180 | }, |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
... | ... | @@ -25,13 +25,8 @@ |
25 | 25 | <#elseif po.dictField?default("")?trim?length gt 1> |
26 | 26 | <#assign form_field_dictCode="${po.dictField}"> |
27 | 27 | </#if> |
28 | - <#if po.classType =='textarea'> | |
29 | - <a-col :span="24"> | |
30 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
31 | - <#else> | |
32 | 28 | <a-col :span="${form_span}"> |
33 | 29 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
34 | - </#if> | |
35 | 30 | <#if po.classType =='date'> |
36 | 31 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%"/> |
37 | 32 | <#elseif po.classType =='datetime'> |
... | ... | @@ -117,20 +112,12 @@ |
117 | 112 | }, |
118 | 113 | labelCol: { |
119 | 114 | xs: { span: 24 }, |
120 | - sm: { span: 6 }, | |
115 | + sm: { span: 5 }, | |
121 | 116 | }, |
122 | 117 | wrapperCol: { |
123 | 118 | xs: { span: 24 }, |
124 | 119 | sm: { span: 16 }, |
125 | 120 | }, |
126 | - labelCol2: { | |
127 | - xs: { span: 24 }, | |
128 | - sm: { span: 3 }, | |
129 | - }, | |
130 | - wrapperCol2: { | |
131 | - xs: { span: 24 }, | |
132 | - sm: { span: 20 }, | |
133 | - }, | |
134 | 121 | <#include "/common/validatorRulesTemplate/sub.ftl"> |
135 | 122 | confirmLoading: false, |
136 | 123 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | +<#assign list_need_category=false> | |
4 | +<#assign list_need_pca=false> | |
5 | +<#assign bpm_flag=false> | |
6 | + | |
7 | +<#-- 开始循环 --> | |
8 | +<#list columns as po> | |
9 | +<#if po.fieldDbName=='bpm_status'> | |
10 | + <#assign bpm_flag=true> | |
11 | +</#if> | |
12 | +<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0> | |
13 | +<#assign list_need_category=true> | |
14 | +</#if> | |
15 | +<#if po.classType=='pca'> | |
16 | +<#assign list_need_pca=true> | |
17 | +</#if> | |
18 | +</#list> | |
19 | +<#-- 结束循环 --> | |
20 | + <!--引用表格--> | |
21 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
22 | + <!--插槽:table标题--> | |
23 | + <template #tableTitle> | |
24 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
25 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
26 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
27 | + <a-dropdown v-if="checkedKeys.length > 0"> | |
28 | + <template #overlay> | |
29 | + <a-menu> | |
30 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
31 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
32 | + 删除 | |
33 | + </a-menu-item> | |
34 | + </a-menu> | |
35 | + </template> | |
36 | + <a-button>批量操作 | |
37 | + <Icon icon="mdi:chevron-down"></Icon> | |
38 | + </a-button> | |
39 | + </a-dropdown> | |
40 | + </template> | |
41 | + <!--操作栏--> | |
42 | + <template #action="{ record }"> | |
43 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
44 | + </template> | |
45 | + <!--字段回显插槽--> | |
46 | + <template #htmlSlot="{text}"> | |
47 | + <div v-html="text"></div> | |
48 | + </template> | |
49 | + <template #fileSlot="{text}"> | |
50 | + <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |
51 | + <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |
52 | + </template> | |
53 | + </BasicTable> | |
54 | + <!-- 表单区域 --> | |
55 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
56 | + </div> | |
57 | +</template> | |
58 | + | |
59 | +<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup> | |
60 | + import {ref, computed, unref} from 'vue'; | |
61 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
62 | + import { useListPage } from '/@/hooks/system/useListPage' | |
63 | + import {useModal} from '/@/components/Modal'; | |
64 | + import ${entityName}Modal from './components/${entityName}Modal.vue' | |
65 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
66 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
67 | + <#if list_need_category> | |
68 | + import { loadCategoryData } from '/@/api/common/api' | |
69 | + import { getAuthCache, setAuthCache } from '/@/utils/auth'; | |
70 | + import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum'; | |
71 | + </#if> | |
72 | + const checkedKeys = ref<Array<string | number>>([]); | |
73 | + //注册model | |
74 | + const [registerModal, {openModal}] = useModal(); | |
75 | + //注册table数据 | |
76 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
77 | + tableProps:{ | |
78 | + title: '${tableVo.ftlDescription}', | |
79 | + api: list, | |
80 | + columns, | |
81 | + canResize:false, | |
82 | + formConfig: { | |
83 | + labelWidth: 120, | |
84 | + schemas: searchFormSchema, | |
85 | + autoSubmitOnEnter:true, | |
86 | + showAdvancedButton:true, | |
87 | + fieldMapToTime: [ | |
88 | + <#list columns as po> | |
89 | + <#if po.isQuery=='Y'> | |
90 | + <#if po.queryMode!='single'> | |
91 | + <#if po.classType=='date'> | |
92 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'], | |
93 | + <#elseif po.classType=='datetime'> | |
94 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'], | |
95 | + </#if> | |
96 | + </#if> | |
97 | + </#if> | |
98 | + </#list> | |
99 | + ], | |
100 | + }, | |
101 | + actionColumn: { | |
102 | + width: 120, | |
103 | + }, | |
104 | + }, | |
105 | + exportConfig: { | |
106 | + name:"${tableVo.ftlDescription}", | |
107 | + url: getExportUrl, | |
108 | + }, | |
109 | + importConfig: { | |
110 | + url: getImportUrl | |
111 | + }, | |
112 | + }) | |
113 | + | |
114 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
115 | + | |
116 | + /** | |
117 | + * 新增事件 | |
118 | + */ | |
119 | + function handleAdd() { | |
120 | + openModal(true, { | |
121 | + isUpdate: false, | |
122 | + showFooter: true, | |
123 | + }); | |
124 | + } | |
125 | + /** | |
126 | + * 编辑事件 | |
127 | + */ | |
128 | + function handleEdit(record: Recordable) { | |
129 | + openModal(true, { | |
130 | + record, | |
131 | + isUpdate: true, | |
132 | + showFooter: true, | |
133 | + }); | |
134 | + } | |
135 | + /** | |
136 | + * 详情 | |
137 | + */ | |
138 | + function handleDetail(record: Recordable) { | |
139 | + openModal(true, { | |
140 | + record, | |
141 | + isUpdate: true, | |
142 | + showFooter: false, | |
143 | + }); | |
144 | + } | |
145 | + /** | |
146 | + * 删除事件 | |
147 | + */ | |
148 | + async function handleDelete(record) { | |
149 | + await deleteOne({id: record.id}, reload); | |
150 | + } | |
151 | + /** | |
152 | + * 批量删除事件 | |
153 | + */ | |
154 | + async function batchHandleDelete() { | |
155 | + await batchDelete({ids: checkedKeys.value}, reload); | |
156 | + } | |
157 | + /** | |
158 | + * 成功回调 | |
159 | + */ | |
160 | + function handleSuccess() { | |
161 | + reload(); | |
162 | + } | |
163 | + /** | |
164 | + * 操作栏 | |
165 | + */ | |
166 | + function getTableAction(record){ | |
167 | + return [ | |
168 | + { | |
169 | + label: '编辑', | |
170 | + onClick: handleEdit.bind(null, record), | |
171 | + } | |
172 | + ] | |
173 | + } | |
174 | + /** | |
175 | + * 下拉操作栏 | |
176 | + */ | |
177 | + function getDropDownAction(record){ | |
178 | + return [ | |
179 | + { | |
180 | + label: '详情', | |
181 | + onClick: handleDetail.bind(null, record), | |
182 | + }, { | |
183 | + label: '删除', | |
184 | + popConfirm: { | |
185 | + title: '是否确认删除', | |
186 | + confirm: handleDelete.bind(null, record), | |
187 | + } | |
188 | + } | |
189 | + ] | |
190 | + } | |
191 | + <#if list_need_category> | |
192 | + /** | |
193 | + * 初始化字典配置 | |
194 | + */ | |
195 | + function initDictConfig(){ | |
196 | + <#list columns as po> | |
197 | + <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'> | |
198 | + <#if po.classType=='cat_tree' && list_need_category==true> | |
199 | + loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => { | |
200 | + if (res) { | |
201 | + let allDictDate = getAuthCache(DB_DICT_DATA_KEY); | |
202 | + if(!allDictDate['${po.dictField?default("")}']){ | |
203 | + Object.assign(allDictDate,{'${po.dictField?default("")}':res}) | |
204 | + } | |
205 | + setAuthCache(DB_DICT_DATA_KEY,allDictDate) | |
206 | + } | |
207 | + }) | |
208 | + </#if> | |
209 | + </#if> | |
210 | + </#list> | |
211 | + } | |
212 | + initDictConfig(); | |
213 | + </#if> | |
214 | +</script> | |
215 | + | |
216 | +<style scoped> | |
217 | + | |
218 | +</style> | |
0 | 219 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +<#list subTables as sub><#rt/> | |
13 | + ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId', | |
14 | +</#list> | |
15 | +} | |
16 | +/** | |
17 | + * 导出api | |
18 | + * @param params | |
19 | + */ | |
20 | +export const getExportUrl = Api.exportXls; | |
21 | + | |
22 | +/** | |
23 | + * 导入api | |
24 | + */ | |
25 | +export const getImportUrl = Api.importExcel; | |
26 | +<#list subTables as sub><#rt/> | |
27 | +/** | |
28 | + * 查询子表数据 | |
29 | + * @param params | |
30 | + */ | |
31 | +export const ${sub.entityName?uncap_first}List = Api.${sub.entityName?uncap_first}List; | |
32 | +</#list> | |
33 | +/** | |
34 | + * 列表接口 | |
35 | + * @param params | |
36 | + */ | |
37 | +export const list = (params) => | |
38 | + defHttp.get({url: Api.list, params}); | |
39 | + | |
40 | +/** | |
41 | + * 删除单个 | |
42 | + */ | |
43 | +export const deleteOne = (params,handleSuccess) => { | |
44 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
45 | + handleSuccess(); | |
46 | + }); | |
47 | +} | |
48 | +/** | |
49 | + * 批量删除 | |
50 | + * @param params | |
51 | + */ | |
52 | +export const batchDelete = (params, handleSuccess) => { | |
53 | + Modal.confirm({ | |
54 | + title: '确认删除', | |
55 | + content: '是否删除选中数据', | |
56 | + okText: '确认', | |
57 | + cancelText: '取消', | |
58 | + onOk: () => { | |
59 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
60 | + handleSuccess(); | |
61 | + }); | |
62 | + } | |
63 | + }); | |
64 | +} | |
65 | +/** | |
66 | + * 保存或者更新 | |
67 | + * @param params | |
68 | + */ | |
69 | +export const saveOrUpdate = (params, isUpdate) => { | |
70 | + let url = isUpdate ? Api.edit : Api.save; | |
71 | + return defHttp.post({url: url, params}); | |
72 | +} | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types' | |
6 | +//列表数据 | |
7 | +export const columns: BasicColumn[] = [ | |
8 | + <#list columns as po> | |
9 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
10 | + { | |
11 | + title: '${po.filedComment}', | |
12 | + align:"center", | |
13 | + <#if po.sort=='Y'> | |
14 | + sorter: true, | |
15 | + </#if> | |
16 | + <#if po.classType=='date'> | |
17 | + dataIndex: '${po.fieldName}', | |
18 | + customRender:({text}) =>{ | |
19 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
20 | + }, | |
21 | + <#elseif po.fieldDbType=='Blob'> | |
22 | + dataIndex: '${po.fieldName}String' | |
23 | + <#elseif po.classType=='umeditor'> | |
24 | + dataIndex: '${po.fieldName}', | |
25 | + slots: { customRender: 'htmlSlot' }, | |
26 | + <#elseif po.classType=='pca'> | |
27 | + dataIndex: '${po.fieldName}', | |
28 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
29 | + <#elseif po.classType=='file'> | |
30 | + dataIndex: '${po.fieldName}', | |
31 | + slots: { customRender: 'fileSlot' }, | |
32 | + <#elseif po.classType=='image'> | |
33 | + dataIndex: '${po.fieldName}', | |
34 | + customRender:render.renderAvatar, | |
35 | + <#elseif po.classType=='switch'> | |
36 | + dataIndex: '${po.fieldName}', | |
37 | +<#assign switch_extend_arr=['Y','N']> | |
38 | +<#if po.dictField?default("")?contains("[")> | |
39 | +<#assign switch_extend_arr=po.dictField?eval> | |
40 | +</#if> | |
41 | +<#list switch_extend_arr as a> | |
42 | +<#if a_index == 0> | |
43 | +<#assign switch_extend_arr1=a> | |
44 | +<#else> | |
45 | +<#assign switch_extend_arr2=a> | |
46 | +</#if> | |
47 | +</#list> | |
48 | + customRender:({text}) => { | |
49 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
50 | + }, | |
51 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
52 | + dataIndex: '${po.fieldName}_dictText' | |
53 | + <#elseif po.classType=='cat_tree'> | |
54 | + dataIndex: '${po.fieldName}', | |
55 | + <#if po.dictText?default("")?trim?length == 0> | |
56 | + customRender:({text}) => { | |
57 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
58 | + }, | |
59 | + <#else> | |
60 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
61 | + </#if> | |
62 | + <#else> | |
63 | + dataIndex: '${po.fieldName}' | |
64 | + </#if> | |
65 | + }, | |
66 | + </#if> | |
67 | + </#list> | |
68 | +]; | |
69 | +//查询数据 | |
70 | +export const searchFormSchema: FormSchema[] = [ | |
71 | +<#-- 开始循环 --> | |
72 | +<#list columns as po> | |
73 | +<#if po.fieldDbName=='bpm_status'> | |
74 | + <#assign bpm_flag=true> | |
75 | +</#if> | |
76 | +<#if po.isQuery=='Y'> | |
77 | +<#assign query_flag=true> | |
78 | + <#assign query_field_dictCode=""> | |
79 | + <#if po.dictTable?default("")?trim?length gt 1> | |
80 | + <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
81 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
82 | + <#assign query_field_dictCode="${po.dictField}"> | |
83 | + </#if> | |
84 | +<#if po.queryMode=='single'> | |
85 | + { | |
86 | + label: "${po.filedComment}", | |
87 | + field: "${po.fieldName}", | |
88 | +<#if po.classType=='sel_search'> | |
89 | + component: 'JSearchSelect', | |
90 | + componentProps:{ | |
91 | + dict:"${po.dictTable},${po.dictText},${po.dictField}" | |
92 | + }, | |
93 | +<#elseif po.classType=='sel_user'> | |
94 | + component: 'JSelectUserByDept', | |
95 | +<#elseif po.classType=='switch'> | |
96 | + component: 'JSwitch', | |
97 | + componentProps:{ | |
98 | + <#if po.dictField != 'is_open'> | |
99 | + options:"${po.dictField}" | |
100 | + </#if> | |
101 | + }, | |
102 | + <#elseif po.classType=='sel_depart'> | |
103 | + component: 'JSelectDept', | |
104 | + <#elseif po.classType=='list_multi'> | |
105 | + component: 'JMultiSelectTag',//暂无该组件 | |
106 | + componentProps:{ | |
107 | + dictCode:"query_field_dictCode?default("")" | |
108 | + }, | |
109 | + <#elseif po.classType=='cat_tree'> | |
110 | + component: 'JCategorySelect', | |
111 | + componentProps:{ | |
112 | + pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题 | |
113 | + }, | |
114 | +<#elseif po.classType=='date'> | |
115 | + component: 'DatePicker', | |
116 | +<#elseif po.classType=='datetime'> | |
117 | + component: 'DatePicker', | |
118 | + componentProps: { | |
119 | + showTime:true | |
120 | + }, | |
121 | +<#elseif po.classType=='pca'> | |
122 | + component: 'JAreaLinkage', | |
123 | +<#elseif po.classType=='popup'> | |
124 | + component: 'JPopup', | |
125 | + componentProps: ({ formActionType }) => { | |
126 | + const {setFieldsValue} = formActionType; | |
127 | + return{ | |
128 | + setFieldsValue:setFieldsValue, | |
129 | + code:"${po.dictTable}", | |
130 | + fieldConfig:"${po.dictField}", | |
131 | + multi:${po.extendParams.popupMulti?c}, | |
132 | + } | |
133 | + }, | |
134 | +<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'> | |
135 | +<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- --> | |
136 | + component: 'JDictSelectTag', | |
137 | + componentProps:{ | |
138 | + <#if po.dictTable?default("")?trim?length gt 1> | |
139 | + dictCode:"${po.dictTable},${po.dictText},${po.dictField}" | |
140 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
141 | + dictCode:"${po.dictField}" | |
142 | + </#if> | |
143 | + }, | |
144 | +<#else> | |
145 | + component: 'Input', | |
146 | +</#if> | |
147 | + colProps: {span: 6}, | |
148 | + }, | |
149 | +<#else> | |
150 | + { | |
151 | + label: "${po.filedComment}", | |
152 | + field: "${po.fieldName}", | |
153 | +<#if po.classType=='date'> | |
154 | + component: 'RangePicker', | |
155 | +<#elseif po.classType=='datetime'> | |
156 | + component: 'RangePicker', | |
157 | + componentProps: { | |
158 | + showTime:true | |
159 | + }, | |
160 | +<#else> | |
161 | + component: 'Input', //TODO 范围查询 | |
162 | +</#if> | |
163 | + colProps: {span: 6}, | |
164 | + }, | |
165 | +</#if> | |
166 | +</#if> | |
167 | +</#list> | |
168 | +<#-- 结束循环 --> | |
169 | +]; | |
170 | +//表单数据 | |
171 | +export const formSchema: FormSchema[] = [ | |
172 | +<#assign form_cat_tree = false> | |
173 | +<#assign form_cat_back = ""> | |
174 | +<#assign bpm_flag=false> | |
175 | +<#list columns as po><#rt/> | |
176 | +<#if po.fieldDbName=='bpm_status'> | |
177 | + <#assign bpm_flag=true> | |
178 | +</#if> | |
179 | +<#if po.isShow =='Y'> | |
180 | +<#assign form_field_dictCode=""> | |
181 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
182 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
183 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
184 | + <#assign form_field_dictCode="${po.dictField}"> | |
185 | + </#if> | |
186 | + { | |
187 | + label: '${po.filedComment}', | |
188 | + field: '${po.fieldName}', | |
189 | + <#if po.classType =='date'> | |
190 | + component: 'DatePicker', | |
191 | + <#elseif po.fieldType =='datetime'> | |
192 | + component: 'DatePicker', | |
193 | + componentProps: { | |
194 | + showTime:true | |
195 | + }, | |
196 | + <#elseif po.fieldType =='time'> | |
197 | + component: 'TimePicker', | |
198 | + <#elseif po.classType =='popup'> | |
199 | + component: 'JPopup', | |
200 | + componentProps: ({ formActionType }) => { | |
201 | + const {setFieldsValue} = formActionType; | |
202 | + return{ | |
203 | + setFieldsValue:setFieldsValue, | |
204 | + code:"${po.dictTable}", | |
205 | + fieldConfig:${po.dictField}, | |
206 | + multi:${po.extendParams.popupMulti?c}, | |
207 | + } | |
208 | + } | |
209 | + <#elseif po.classType =='sel_depart'> | |
210 | + component: 'JSelectDept', | |
211 | + <#elseif po.classType =='switch'> | |
212 | + component: 'JSwitch', | |
213 | + componentProps:{ | |
214 | + <#if po.dictField != 'is_open'> | |
215 | + options:${po.dictField} | |
216 | + </#if> | |
217 | + } | |
218 | + <#elseif po.classType =='pca'> | |
219 | + component: 'JAreaLinkage', | |
220 | + <#elseif po.classType =='markdown'> | |
221 | + component: 'JMarkdownEditor',//注意string转换问题 | |
222 | + <#elseif po.classType =='password'> | |
223 | + component: 'InputPassword', | |
224 | + <#elseif po.classType =='sel_user'> | |
225 | + component: 'JSelectUserByDept', | |
226 | + componentProps:{ | |
227 | + labelKey:'realname', | |
228 | + } | |
229 | + <#elseif po.classType =='textarea'> | |
230 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
231 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
232 | + component: 'JDictSelectTag', | |
233 | + componentProps:{ | |
234 | + dictCode:"${form_field_dictCode}" | |
235 | + } | |
236 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
237 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
238 | + componentProps:{ | |
239 | + dictCode:"${form_field_dictCode}" | |
240 | + } | |
241 | + <#elseif po.classType=='sel_search'> | |
242 | + component: 'JSearchSelect', | |
243 | + componentProps:{ | |
244 | + dict:"${form_field_dictCode}" | |
245 | + } | |
246 | +<#elseif po.classType=='cat_tree'> | |
247 | + <#assign form_cat_tree = true> | |
248 | + component: 'JCategorySelect', | |
249 | + componentProps:{ | |
250 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
251 | + } | |
252 | + <#if po.dictText?default("")?trim?length gt 1> | |
253 | + <#assign form_cat_back = "${po.dictText}"> | |
254 | + </#if> | |
255 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
256 | + component: 'InputNumber', | |
257 | + <#elseif po.classType=='file'> | |
258 | + component: 'JUpload', | |
259 | + componentProps:{ | |
260 | + <#if po.uploadnum??> | |
261 | + maxCount:${po.uploadnum} | |
262 | + </#if> | |
263 | + } | |
264 | + <#elseif po.classType=='image'> | |
265 | + component: 'JImageUpload', | |
266 | + componentProps:{ | |
267 | + <#if po.uploadnum??> | |
268 | + fileMax:${po.uploadnum} | |
269 | + </#if> | |
270 | + } | |
271 | + <#elseif po.classType=='umeditor'> | |
272 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
273 | + <#elseif po.classType == 'sel_tree'> | |
274 | + component: 'JTreeSelect', | |
275 | + componentProps:{ | |
276 | + <#if po.dictText??> | |
277 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
278 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
279 | + <#elseif po.dictText?split(',')[1]??> | |
280 | + pidField:"${po.dictText?split(',')[1]}", | |
281 | + <#elseif po.dictText?split(',')[3]??> | |
282 | + hasChildField:"${po.dictText?split(',')[3]}", | |
283 | + </#if> | |
284 | + </#if> | |
285 | + pidValue:"${po.dictField}", | |
286 | + } | |
287 | + <#else> | |
288 | + component: 'Input', | |
289 | + </#if> | |
290 | + <#include "/common/utils.ftl"> | |
291 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
292 | + dynamicRules: ({model,schema}) => { | |
293 | + <#if po.fieldName != 'id'> | |
294 | + <#assign fieldValidType = po.fieldValidType!''> | |
295 | + return [ | |
296 | + <#-- 非空校验 --> | |
297 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
298 | + { required: true, message: '请输入${po.filedComment}!'}, | |
299 | + <#elseif fieldValidType!=''> | |
300 | + { required: false}, | |
301 | + </#if> | |
302 | + <#-- 唯一校验 --> | |
303 | + <#if fieldValidType == 'only'> | |
304 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
305 | + <#-- 6到16位数字 --> | |
306 | + <#elseif fieldValidType == 'n6-16'> | |
307 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
308 | + <#-- 6到16位任意字符 --> | |
309 | + <#elseif fieldValidType == '*6-16'> | |
310 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
311 | + <#-- 6到18位字符串 --> | |
312 | + <#elseif fieldValidType == 's6-18'> | |
313 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
314 | + <#-- 网址 --> | |
315 | + <#elseif fieldValidType == 'url'> | |
316 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
317 | + <#-- 电子邮件 --> | |
318 | + <#elseif fieldValidType == 'e'> | |
319 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
320 | + <#-- 手机号码 --> | |
321 | + <#elseif fieldValidType == 'm'> | |
322 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
323 | + <#-- 邮政编码 --> | |
324 | + <#elseif fieldValidType == 'p'> | |
325 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
326 | + <#-- 字母 --> | |
327 | + <#elseif fieldValidType == 's'> | |
328 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
329 | + <#-- 数字 --> | |
330 | + <#elseif fieldValidType == 'n'> | |
331 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
332 | + <#-- 整数 --> | |
333 | + <#elseif fieldValidType == 'z'> | |
334 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
335 | + <#-- 金额 --> | |
336 | + <#elseif fieldValidType == 'money'> | |
337 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
338 | + <#-- 正则校验 --> | |
339 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
340 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
341 | + <#-- 无校验 --> | |
342 | + <#else> | |
343 | + <#t> | |
344 | + </#if> | |
345 | + ]; | |
346 | + </#if> | |
347 | + }, | |
348 | + </#if> | |
349 | + <#if po.readonly=='Y'> | |
350 | + dynamicDisabled:true | |
351 | + </#if> | |
352 | + }, | |
353 | +</#if> | |
354 | +</#list> | |
355 | +]; | |
356 | +//子表单数据 | |
357 | +<#list subTables as sub> | |
358 | +<#if sub.foreignRelationType =='1'> | |
359 | +export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [ | |
360 | +<#assign form_cat_tree = false> | |
361 | +<#assign form_cat_back = ""> | |
362 | +<#assign bpm_flag=false> | |
363 | +<#list sub.colums as po><#rt/> | |
364 | +<#if po.fieldDbName=='bpm_status'> | |
365 | + <#assign bpm_flag=true> | |
366 | +</#if> | |
367 | +<#if po.isShow =='Y'> | |
368 | +<#assign form_field_dictCode=""> | |
369 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
370 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
371 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
372 | + <#assign form_field_dictCode="${po.dictField}"> | |
373 | + </#if> | |
374 | + { | |
375 | + label: '${po.filedComment}', | |
376 | + field: '${po.fieldName}', | |
377 | + <#if po.classType =='date'> | |
378 | + component: 'DatePicker', | |
379 | + <#elseif po.fieldType =='datetime'> | |
380 | + component: 'DatePicker', | |
381 | + componentProps: { | |
382 | + showTime:true | |
383 | + }, | |
384 | + <#elseif po.fieldType =='time'> | |
385 | + component: 'TimePicker', | |
386 | + <#elseif po.classType =='popup'> | |
387 | + component: 'JPopup', | |
388 | + componentProps: ({ formActionType }) => { | |
389 | + const {setFieldsValue} = formActionType; | |
390 | + return{ | |
391 | + setFieldsValue:setFieldsValue, | |
392 | + code:"${po.dictTable}", | |
393 | + fieldConfig:${po.dictField}, | |
394 | + multi:${po.extendParams.popupMulti?c}, | |
395 | + } | |
396 | + } | |
397 | + <#elseif po.classType =='sel_depart'> | |
398 | + component: 'JSelectDept', | |
399 | + <#elseif po.classType =='switch'> | |
400 | + component: 'JSwitch', | |
401 | + componentProps:{ | |
402 | + <#if po.dictField != 'is_open'> | |
403 | + options:${po.dictField} | |
404 | + </#if> | |
405 | + } | |
406 | + <#elseif po.classType =='pca'> | |
407 | + component: 'JAreaLinkage', | |
408 | + <#elseif po.classType =='markdown'> | |
409 | + component: 'JMarkdownEditor',//注意string转换问题 | |
410 | + <#elseif po.classType =='password'> | |
411 | + component: 'InputPassword', | |
412 | + <#elseif po.classType =='sel_user'> | |
413 | + component: 'JSelectUserByDept', | |
414 | + componentProps:{ | |
415 | + labelKey:'realname', | |
416 | + } | |
417 | + <#elseif po.classType =='textarea'> | |
418 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
419 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
420 | + component: 'JDictSelectTag', | |
421 | + componentProps:{ | |
422 | + dictCode:"${form_field_dictCode}" | |
423 | + } | |
424 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
425 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
426 | + componentProps:{ | |
427 | + dictCode:"${form_field_dictCode}" | |
428 | + } | |
429 | + <#elseif po.classType=='sel_search'> | |
430 | + component: 'JSearchSelect', | |
431 | + componentProps:{ | |
432 | + dict:"${form_field_dictCode}" | |
433 | + } | |
434 | +<#elseif po.classType=='cat_tree'> | |
435 | + <#assign form_cat_tree = true> | |
436 | + component: 'JCategorySelect', | |
437 | + componentProps:{ | |
438 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
439 | + } | |
440 | + <#if po.dictText?default("")?trim?length gt 1> | |
441 | + <#assign form_cat_back = "${po.dictText}"> | |
442 | + </#if> | |
443 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
444 | + component: 'InputNumber', | |
445 | + <#elseif po.classType=='file'> | |
446 | + component: 'JUpload', | |
447 | + componentProps:{ | |
448 | + <#if po.uploadnum??> | |
449 | + maxCount:${po.uploadnum} | |
450 | + </#if> | |
451 | + } | |
452 | + <#elseif po.classType=='image'> | |
453 | + component: 'JImageUpload', | |
454 | + componentProps:{ | |
455 | + <#if po.uploadnum??> | |
456 | + fileMax:${po.uploadnum} | |
457 | + </#if> | |
458 | + } | |
459 | + <#elseif po.classType=='umeditor'> | |
460 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
461 | + <#elseif po.classType == 'sel_tree'> | |
462 | + component: 'JTreeSelect', | |
463 | + componentProps:{ | |
464 | + <#if po.dictText??> | |
465 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
466 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
467 | + <#elseif po.dictText?split(',')[1]??> | |
468 | + pidField:"${po.dictText?split(',')[1]}", | |
469 | + <#elseif po.dictText?split(',')[3]??> | |
470 | + hasChildField:"${po.dictText?split(',')[3]}", | |
471 | + </#if> | |
472 | + </#if> | |
473 | + pidValue:"${po.dictField}", | |
474 | + } | |
475 | + <#else> | |
476 | + component: 'Input', | |
477 | + </#if> | |
478 | + <#include "/common/utils.ftl"> | |
479 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
480 | + dynamicRules: ({model,schema}) => { | |
481 | + <#if po.fieldName != 'id'> | |
482 | + <#assign fieldValidType = po.fieldValidType!''> | |
483 | + return [ | |
484 | + <#-- 非空校验 --> | |
485 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
486 | + { required: true, message: '请输入${po.filedComment}!'}, | |
487 | + <#elseif fieldValidType!=''> | |
488 | + { required: false}, | |
489 | + </#if> | |
490 | + <#-- 唯一校验 --> | |
491 | + <#if fieldValidType == 'only'> | |
492 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
493 | + <#-- 6到16位数字 --> | |
494 | + <#elseif fieldValidType == 'n6-16'> | |
495 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
496 | + <#-- 6到16位任意字符 --> | |
497 | + <#elseif fieldValidType == '*6-16'> | |
498 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
499 | + <#-- 6到18位字符串 --> | |
500 | + <#elseif fieldValidType == 's6-18'> | |
501 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
502 | + <#-- 网址 --> | |
503 | + <#elseif fieldValidType == 'url'> | |
504 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
505 | + <#-- 电子邮件 --> | |
506 | + <#elseif fieldValidType == 'e'> | |
507 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
508 | + <#-- 手机号码 --> | |
509 | + <#elseif fieldValidType == 'm'> | |
510 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
511 | + <#-- 邮政编码 --> | |
512 | + <#elseif fieldValidType == 'p'> | |
513 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
514 | + <#-- 字母 --> | |
515 | + <#elseif fieldValidType == 's'> | |
516 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
517 | + <#-- 数字 --> | |
518 | + <#elseif fieldValidType == 'n'> | |
519 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
520 | + <#-- 整数 --> | |
521 | + <#elseif fieldValidType == 'z'> | |
522 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
523 | + <#-- 金额 --> | |
524 | + <#elseif fieldValidType == 'money'> | |
525 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
526 | + <#-- 正则校验 --> | |
527 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
528 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
529 | + <#-- 无校验 --> | |
530 | + <#else> | |
531 | + <#t> | |
532 | + </#if> | |
533 | + ]; | |
534 | + </#if> | |
535 | + }, | |
536 | + </#if> | |
537 | + <#if po.readonly=='Y'> | |
538 | + dynamicDisabled:true | |
539 | + </#if> | |
540 | + }, | |
541 | +</#if> | |
542 | +</#list> | |
543 | +]; | |
544 | +</#if> | |
545 | +</#list> | |
546 | +//子表表格配置 | |
547 | +<#list subTables as sub> | |
548 | +<#if sub.foreignRelationType =='0'> | |
549 | +export const ${sub.entityName?uncap_first}Columns: JVxeColumn[] = [ | |
550 | +<#assign popupBackFields = ""> | |
551 | + | |
552 | +<#-- 循环子表的列 开始 --> | |
553 | +<#list sub.colums as col><#rt/> | |
554 | +<#if col.isShow =='Y'> | |
555 | +<#if col.filedComment !='外键' > | |
556 | + { | |
557 | + title: '${col.filedComment}', | |
558 | + key: '${autoStringSuffixForModel(col)}', | |
559 | +<#if col.classType =='date'> | |
560 | + type: JVxeTypes.date, | |
561 | + <#if col.readonly=='Y'> | |
562 | + disabled:true, | |
563 | + </#if> | |
564 | +<#elseif col.classType =='datetime'> | |
565 | + type: JVxeTypes.datetime, | |
566 | + <#if col.readonly=='Y'> | |
567 | + disabled:true, | |
568 | + </#if> | |
569 | +<#elseif col.classType =='textarea'> | |
570 | + type: JVxeTypes.textarea, | |
571 | + <#if col.readonly=='Y'> | |
572 | + disabled:true, | |
573 | + </#if> | |
574 | +<#elseif "int,decimal,double,"?contains(col.classType)> | |
575 | + type: JVxeTypes.inputNumber, | |
576 | + <#if col.readonly=='Y'> | |
577 | + disabled:true, | |
578 | + </#if> | |
579 | +<#elseif col.classType =='list' || col.classType =='radio'> | |
580 | + type: JVxeTypes.select, | |
581 | + options:[], | |
582 | + <#if col.dictTable?default("")?trim?length gt 1> | |
583 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
584 | + <#else> | |
585 | + dictCode:"${col.dictField}", | |
586 | + </#if> | |
587 | + <#if col.readonly=='Y'> | |
588 | + disabled:true, | |
589 | + </#if> | |
590 | +<#elseif col.classType =='list_multi' || col.classType =='checkbox'> | |
591 | + type: JVxeTypes.selectMultiple, | |
592 | + options:[], | |
593 | + <#if col.dictTable?default("")?trim?length gt 1> | |
594 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
595 | + <#else> | |
596 | + dictCode:"${col.dictField}", | |
597 | + </#if> | |
598 | + <#if col.readonly=='Y'> | |
599 | + disabled:true, | |
600 | + </#if> | |
601 | +<#elseif col.classType =='sel_search'> | |
602 | + type: JVxeTypes.selectSearch, | |
603 | + <#if col.dictTable?default("")?trim?length gt 1> | |
604 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
605 | + <#else> | |
606 | + dictCode:"${col.dictField}", | |
607 | + </#if> | |
608 | + <#if col.readonly=='Y'> | |
609 | + disabled:true, | |
610 | + </#if> | |
611 | +<#elseif col.classType =='image'> | |
612 | + type: JVxeTypes.image, | |
613 | + token:true, | |
614 | + responseName:"message", | |
615 | + <#if col.readonly=='Y'> | |
616 | + disabled:true, | |
617 | + </#if> | |
618 | + <#if col.uploadnum??> | |
619 | + number: ${col.uploadnum}, | |
620 | + </#if> | |
621 | +<#elseif col.classType =='file'> | |
622 | + type: JVxeTypes.file, | |
623 | + token:true, | |
624 | + responseName:"message", | |
625 | + <#if col.readonly=='Y'> | |
626 | + disabled:true, | |
627 | + </#if> | |
628 | + <#if col.uploadnum??> | |
629 | + number: ${col.uploadnum}, | |
630 | + </#if> | |
631 | +<#elseif col.classType =='switch'> | |
632 | + type: JVxeTypes.checkbox, | |
633 | + <#if col.dictField == 'is_open'> | |
634 | + customValue: ['Y', 'N'], | |
635 | + <#else> | |
636 | + customValue: ${col.dictField}, | |
637 | + </#if> | |
638 | + <#if col.readonly=='Y'> | |
639 | + disabled:true, | |
640 | + </#if> | |
641 | +<#elseif col.classType =='popup'> | |
642 | +<#if popupBackFields?length gt 0> | |
643 | + <#assign popupBackFields = "${popupBackFields}"+","+"${col.dictText}"> | |
644 | +<#else> | |
645 | + <#assign popupBackFields = "${col.dictText}"> | |
646 | +</#if> | |
647 | + type: JVxeTypes.popup, | |
648 | + popupCode:"${col.dictTable}", | |
649 | + field:"${col.dictField}", | |
650 | + orgFields:"${col.dictField}", | |
651 | + destFields:"${Format.underlineToHump(col.dictText)}", | |
652 | + <#if col.readonly=='Y'> | |
653 | + disabled:true, | |
654 | + </#if> | |
655 | +<#else> | |
656 | + type: JVxeTypes.input, | |
657 | + <#if col.readonly=='Y'> | |
658 | + disabled:true, | |
659 | + </#if> | |
660 | +</#if> | |
661 | +<#if col.classType =='list_multi' || col.classType =='checkbox'> | |
662 | + width:"250px", | |
663 | +<#else> | |
664 | + width:"200px", | |
665 | +</#if> | |
666 | +<#if col.classType =='file'> | |
667 | + placeholder: '请选择文件', | |
668 | +<#else> | |
669 | + placeholder: '请输入${'$'}{title}', | |
670 | +</#if> | |
671 | +<#if col.defaultVal??> | |
672 | +<#if col.fieldDbType=="BigDecimal" || col.fieldDbType=="double" || col.fieldDbType=="int"> | |
673 | + defaultValue:${col.defaultVal}, | |
674 | + <#else> | |
675 | + defaultValue:"${col.defaultVal}", | |
676 | +</#if> | |
677 | +<#else> | |
678 | + defaultValue:'', | |
679 | +</#if> | |
680 | +<#-- 子表的校验 --> | |
681 | +<#assign subFieldValidType = col.fieldValidType!''> | |
682 | +<#-- 非空校验 --> | |
683 | +<#if col.nullable == 'N' || subFieldValidType == '*'> | |
684 | + validateRules: [{ required: true, message: '${'$'}{title}不能为空' }], | |
685 | +<#-- 其他情况下,只要有值就被认为是正则校验 --> | |
686 | +<#elseif subFieldValidType?length gt 0> | |
687 | +<#assign subMessage = '格式不正确'> | |
688 | +<#if subFieldValidType == 'only' > | |
689 | + <#assign subMessage = '不能重复'> | |
690 | +</#if> | |
691 | + validateRules: [{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }], | |
692 | +</#if> | |
693 | + }, | |
694 | +</#if> | |
695 | +</#if> | |
696 | +</#list> | |
697 | +<#-- 循环子表的列 结束 --> | |
698 | + ] | |
699 | +</#if> | |
700 | +</#list> | |
0 | 701 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |
3 | + <BasicForm @register="registerForm" ref="formRef"/> | |
4 | + <!-- 子表单区域 --> | |
5 | + <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs"> | |
6 | +<#list subTables as sub><#rt/> | |
7 | + <#if sub.foreignRelationType =='1'> | |
8 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true"> | |
9 | + <${sub.entityName}Form ref="${sub.entityName?uncap_first}Form"></${sub.entityName}Form> | |
10 | + </a-tab-pane> | |
11 | + | |
12 | + <#else> | |
13 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true"> | |
14 | + <JVxeTable | |
15 | + keep-source | |
16 | + resizable | |
17 | + :ref="refKeys[${sub_index}]" | |
18 | + :loading="${sub.entityName?uncap_first}Table.loading" | |
19 | + :columns="${sub.entityName?uncap_first}Table.columns" | |
20 | + :dataSource="${sub.entityName?uncap_first}Table.dataSource" | |
21 | + :maxHeight="300" | |
22 | + :rowNumber="true" | |
23 | + :rowSelection="true" | |
24 | + :toolbar="true" | |
25 | + /> | |
26 | + </a-tab-pane> | |
27 | + </#if> | |
28 | +</#list> | |
29 | + </a-tabs> | |
30 | + </BasicModal> | |
31 | +</template> | |
32 | + | |
33 | +<script lang="ts" setup> | |
34 | + import {ref, computed, unref,reactive} from 'vue'; | |
35 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
36 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
37 | + import { JVxeTable } from '/@/components/jeecg/JVxeTable' | |
38 | + import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts' | |
39 | + <#list subTables as sub> | |
40 | + <#if sub.foreignRelationType =='1'> | |
41 | + import ${sub.entityName}Form from './${sub.entityName}Form.vue' | |
42 | + </#if> | |
43 | + </#list> | |
44 | + import {formSchema<#list subTables as sub><#if sub.foreignRelationType =='0'>,${sub.entityName?uncap_first}Columns</#if></#list>} from '../${entityName?uncap_first}.data'; | |
45 | + import {saveOrUpdate<#list subTables as sub>,${sub.entityName?uncap_first}List</#list>} from '../${entityName?uncap_first}.api'; | |
46 | + import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils' | |
47 | + // Emits声明 | |
48 | + const emit = defineEmits(['register','success']); | |
49 | + const isUpdate = ref(true); | |
50 | + const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]); | |
51 | + <#assign hasOne2Many = false> | |
52 | + <#assign hasOne2One = false> | |
53 | + const activeKey = ref('${subTables[0].entityName?uncap_first}'); | |
54 | +<#list subTables as sub> | |
55 | +<#if sub.foreignRelationType =='0'> | |
56 | + <#assign hasOne2Many = true> | |
57 | + const ${sub.entityName?uncap_first} = ref(); | |
58 | +</#if> | |
59 | +<#if sub.foreignRelationType =='1'> | |
60 | + <#assign hasOne2One = true> | |
61 | + const ${sub.entityName?uncap_first}Form = ref(); | |
62 | +</#if> | |
63 | +</#list> | |
64 | + const tableRefs = {<#list subTables as sub><#if sub.foreignRelationType =='0'>${sub.entityName?uncap_first}, <#assign hasOne2Many = true></#if></#list>}; | |
65 | + <#list subTables as sub> | |
66 | + <#if sub.foreignRelationType =='0'> | |
67 | + const ${sub.entityName?uncap_first}Table = reactive({ | |
68 | + loading: false, | |
69 | + dataSource: [], | |
70 | + columns:${sub.entityName?uncap_first}Columns | |
71 | + }) | |
72 | + </#if> | |
73 | + </#list> | |
74 | + //表单配置 | |
75 | + const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |
76 | + labelWidth: 150, | |
77 | + schemas: formSchema, | |
78 | + showActionButtonGroup: false, | |
79 | + }); | |
80 | + //表单赋值 | |
81 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
82 | + //重置表单 | |
83 | + await reset(); | |
84 | + setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter}); | |
85 | + isUpdate.value = !!data?.isUpdate; | |
86 | + if (unref(isUpdate)) { | |
87 | + //表单赋值 | |
88 | + await setFieldsValue({ | |
89 | + ...data.record, | |
90 | + }); | |
91 | + <#list subTables as sub><#rt/> | |
92 | + <#if sub.foreignRelationType =='1'> | |
93 | + ${sub.entityName?uncap_first}Form.value.initFormData(${sub.entityName?uncap_first}List,data?.record?.id) | |
94 | + </#if> | |
95 | + </#list> | |
96 | + <#list subTables as sub><#rt/> | |
97 | + <#if sub.foreignRelationType =='0'> | |
98 | + requestSubTableData(${sub.entityName?uncap_first}List, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table) | |
99 | + </#if> | |
100 | + </#list> | |
101 | + } | |
102 | + // 隐藏底部时禁用整个表单 | |
103 | + setProps({ disabled: !data?.showFooter }) | |
104 | + }); | |
105 | + //方法配置 | |
106 | + const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys<#if hasOne2One==true>,validateSubForm</#if>); | |
107 | + | |
108 | + //设置标题 | |
109 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
110 | + | |
111 | + async function reset(){ | |
112 | + await resetFields(); | |
113 | + activeKey.value = ref('${subTables[0].entityName?uncap_first}'); | |
114 | + <#list subTables as sub> | |
115 | + <#if sub.foreignRelationType =='0'> | |
116 | + ${sub.entityName?uncap_first}Table.dataSource = []; | |
117 | + </#if> | |
118 | + <#if sub.foreignRelationType =='1'> | |
119 | + ${sub.entityName?uncap_first}Form.value.resetFields(); | |
120 | + </#if> | |
121 | + </#list> | |
122 | + } | |
123 | + function classifyIntoFormData(allValues) { | |
124 | + let main = Object.assign({}, allValues.formValue) | |
125 | + return { | |
126 | + ...main, // 展开 | |
127 | + <#assign subManyIndex = 0> | |
128 | + <#list subTables as sub><#rt/> | |
129 | + <#if sub.foreignRelationType =='0'> | |
130 | + ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData, | |
131 | + <#assign subManyIndex = subManyIndex+1> | |
132 | + <#else> | |
133 | + ${sub.entityName?uncap_first}List: ${sub.entityName?uncap_first}Form.value.getFormData(), | |
134 | + </#if> | |
135 | + </#list> | |
136 | + } | |
137 | + } | |
138 | + <#if hasOne2One==true> | |
139 | + //校验所有一对一子表表单 | |
140 | + function validateSubForm(allValues){ | |
141 | + return new Promise((resolve,reject)=>{ | |
142 | + Promise.all([ | |
143 | + <#list subTables as sub><#rt/> | |
144 | + <#if sub.foreignRelationType =='1'> | |
145 | + ${sub.entityName?uncap_first}Form.value.validateForm(${sub_index}), | |
146 | + </#if> | |
147 | + </#list> | |
148 | + ]).then(() => { | |
149 | + resolve(allValues) | |
150 | + }).catch(e => { | |
151 | + if (e.error === VALIDATE_FAILED) { | |
152 | + // 如果有未通过表单验证的子表,就自动跳转到它所在的tab | |
153 | + activeKey.value = e.index == null ? unref(activeKey) : refKeys.value[e.index] | |
154 | + } else { | |
155 | + console.error(e) | |
156 | + } | |
157 | + }) | |
158 | + }) | |
159 | + } | |
160 | + </#if> | |
161 | + //表单提交事件 | |
162 | + async function requestAddOrEdit(values) { | |
163 | + try { | |
164 | + setModalProps({confirmLoading: true}); | |
165 | + //提交表单 | |
166 | + await saveOrUpdate(values, isUpdate.value); | |
167 | + //关闭弹窗 | |
168 | + closeModal(); | |
169 | + //刷新列表 | |
170 | + emit('success'); | |
171 | + } finally { | |
172 | + setModalProps({confirmLoading: false}); | |
173 | + } | |
174 | + } | |
175 | +</script> | |
176 | + | |
177 | +<style lang="less" scoped> | |
178 | + | |
179 | +</style> | |
0 | 180 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
0 → 100644
1 | +<#list subTables as sub> | |
2 | +<#if sub.foreignRelationType=='1'> | |
3 | +#segment#${sub.entityName}Form.vue | |
4 | +<template> | |
5 | + <BasicForm @register="registerForm"/> | |
6 | +</template> | |
7 | +<script lang="ts"> | |
8 | + import {defineComponent} from 'vue'; | |
9 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
10 | + import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data'; | |
11 | + import {defHttp} from '/@/utils/http/axios'; | |
12 | + import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils' | |
13 | + | |
14 | + export default defineComponent({ | |
15 | + name:"${sub.entityName}Form", | |
16 | + components: {BasicForm}, | |
17 | + emits:['register'], | |
18 | + setup(_,{emit}) { | |
19 | + const [registerForm, {resetFields, setFieldsValue,getFieldsValue,validate}] = useForm({ | |
20 | + labelWidth: 150, | |
21 | + schemas: ${sub.entityName?uncap_first}FormSchema, | |
22 | + showActionButtonGroup: false, | |
23 | + }); | |
24 | + /** | |
25 | + *初始化加载数据 | |
26 | + */ | |
27 | + function initFormData(url,id){ | |
28 | + if(id){ | |
29 | + defHttp.get({url,params:{id}},{isTransformResponse:false}).then(res=>{ | |
30 | + res.success && setFieldsValue({...res.result[0]}); | |
31 | + }) | |
32 | + } | |
33 | + } | |
34 | + /** | |
35 | + *获取表单数据 | |
36 | + */ | |
37 | + function getFormData(){ | |
38 | + return [getFieldsValue()]; | |
39 | + } | |
40 | + /** | |
41 | + *表单校验 | |
42 | + */ | |
43 | + function validateForm(index){ | |
44 | + return new Promise((resolve, reject) => { | |
45 | + // 验证子表表单 | |
46 | + validate().then(()=>{ | |
47 | + return resolve() | |
48 | + }).catch(()=> { | |
49 | + return reject({ error: VALIDATE_FAILED ,index}) | |
50 | + }) | |
51 | + }) | |
52 | + } | |
53 | + return { | |
54 | + registerForm, | |
55 | + resetFields, | |
56 | + initFormData, | |
57 | + getFormData, | |
58 | + validateForm | |
59 | + } | |
60 | + } | |
61 | + }) | |
62 | +</script> | |
63 | +</#if> | |
64 | +</#list> | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -110,7 +110,7 @@ public class ${entityName}Controller { |
110 | 110 | */ |
111 | 111 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
112 | 112 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
113 | - @PutMapping(value = "/edit") | |
113 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
114 | 114 | public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) { |
115 | 115 | ${entityName} ${entityName?uncap_first} = new ${entityName}(); |
116 | 116 | BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first}); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | |
9 | 9 | <a-tabs v-model="activeKey" @change="handleChangeTabs"> |
10 | 10 | <!--主表区域 --> |
11 | - <a-tab-pane tab="${tableVo.ftlDescription}" :key="refKeys[0]" :forceRender="true"> | |
11 | + <a-tab-pane tab="${tableVo.ftlDescription}" :key="refKeys[0]" :forceRender="true" :class="'jeecg-tabs-top'" :animated="false"> | |
12 | 12 | <a-form-model ref="form" :model="model" :rules="validatorRules"> |
13 | 13 | <a-row> |
14 | 14 | <#list columns as po> |
... | ... | @@ -19,13 +19,8 @@ |
19 | 19 | <#elseif po.dictField?default("")?trim?length gt 1> |
20 | 20 | <#assign form_field_dictCode="${po.dictField}"> |
21 | 21 | </#if> |
22 | - <#if po.classType =='textarea'> | |
23 | - <a-col :span="24"> | |
24 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
25 | - <#else> | |
26 | 22 | <a-col :xs="24" :sm="12"> |
27 | 23 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
28 | - </#if> | |
29 | 24 | <#if po.classType =='date'> |
30 | 25 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/> |
31 | 26 | <#elseif po.classType =='datetime'> |
... | ... | @@ -160,20 +155,12 @@ export default { |
160 | 155 | return { |
161 | 156 | labelCol: { |
162 | 157 | xs: { span: 24 }, |
163 | - sm: { span: 6 }, | |
158 | + sm: { span: 5 }, | |
164 | 159 | }, |
165 | 160 | wrapperCol: { |
166 | 161 | xs: { span: 24 }, |
167 | 162 | sm: { span: 16 }, |
168 | 163 | }, |
169 | - labelCol2: { | |
170 | - xs: { span: 24 }, | |
171 | - sm: { span: 3 }, | |
172 | - }, | |
173 | - wrapperCol2: { | |
174 | - xs: { span: 24 }, | |
175 | - sm: { span: 20 }, | |
176 | - }, | |
177 | 164 | // 新增时子表默认添加几行空数据 |
178 | 165 | addDefaultRowNum: 1, |
179 | 166 | model:{ |
... | ... | @@ -516,4 +503,8 @@ export default { |
516 | 503 | </script> |
517 | 504 | |
518 | 505 | <style scoped> |
506 | + /** tab panel 中有下拉框/日期 这类带下拉效果的,需要加此样式 */ | |
507 | + /deep/ .jeecg-tabs-top { | |
508 | + overflow: visible; | |
509 | + } | |
519 | 510 | </style> |
520 | 511 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
... | ... | @@ -25,13 +25,8 @@ |
25 | 25 | <#elseif po.dictField?default("")?trim?length gt 1> |
26 | 26 | <#assign form_field_dictCode="${po.dictField}"> |
27 | 27 | </#if> |
28 | - <#if po.classType =='textarea'> | |
29 | - <a-col :span="24"> | |
30 | - <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}"> | |
31 | - <#else> | |
32 | 28 | <a-col :span="${form_span}"> |
33 | 29 | <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}"> |
34 | - </#if> | |
35 | 30 | <#if po.classType =='date'> |
36 | 31 | <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%"/> |
37 | 32 | <#elseif po.classType =='datetime'> |
... | ... | @@ -118,20 +113,12 @@ |
118 | 113 | }, |
119 | 114 | labelCol: { |
120 | 115 | xs: { span: 24 }, |
121 | - sm: { span: 6 }, | |
116 | + sm: { span: 5 }, | |
122 | 117 | }, |
123 | 118 | wrapperCol: { |
124 | 119 | xs: { span: 24 }, |
125 | 120 | sm: { span: 16 }, |
126 | 121 | }, |
127 | - labelCol2: { | |
128 | - xs: { span: 24 }, | |
129 | - sm: { span: 3 }, | |
130 | - }, | |
131 | - wrapperCol2: { | |
132 | - xs: { span: 24 }, | |
133 | - sm: { span: 20 }, | |
134 | - }, | |
135 | 122 | <#include "/common/validatorRulesTemplate/sub.ftl"> |
136 | 123 | confirmLoading: false, |
137 | 124 | } |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | +<#assign list_need_category=false> | |
4 | +<#assign list_need_pca=false> | |
5 | +<#assign bpm_flag=false> | |
6 | + | |
7 | +<#-- 开始循环 --> | |
8 | +<#list columns as po> | |
9 | +<#if po.fieldDbName=='bpm_status'> | |
10 | + <#assign bpm_flag=true> | |
11 | +</#if> | |
12 | +<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0> | |
13 | +<#assign list_need_category=true> | |
14 | +</#if> | |
15 | +<#if po.classType=='pca'> | |
16 | +<#assign list_need_pca=true> | |
17 | +</#if> | |
18 | +</#list> | |
19 | +<#-- 结束循环 --> | |
20 | + <!--引用表格--> | |
21 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
22 | + <!--插槽:table标题--> | |
23 | + <template #tableTitle> | |
24 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
25 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
26 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
27 | + <a-dropdown v-if="checkedKeys.length > 0"> | |
28 | + <template #overlay> | |
29 | + <a-menu> | |
30 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
31 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
32 | + 删除 | |
33 | + </a-menu-item> | |
34 | + </a-menu> | |
35 | + </template> | |
36 | + <a-button>批量操作 | |
37 | + <Icon icon="mdi:chevron-down"></Icon> | |
38 | + </a-button> | |
39 | + </a-dropdown> | |
40 | + </template> | |
41 | + <!--操作栏--> | |
42 | + <template #action="{ record }"> | |
43 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
44 | + </template> | |
45 | + <!--字段回显插槽--> | |
46 | + <template #htmlSlot="{text}"> | |
47 | + <div v-html="text"></div> | |
48 | + </template> | |
49 | + <template #fileSlot="{text}"> | |
50 | + <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span> | |
51 | + <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button> | |
52 | + </template> | |
53 | + </BasicTable> | |
54 | + <!-- 表单区域 --> | |
55 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
56 | + </div> | |
57 | +</template> | |
58 | + | |
59 | +<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup> | |
60 | + import {ref, computed, unref} from 'vue'; | |
61 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
62 | + import { useListPage } from '/@/hooks/system/useListPage' | |
63 | + import {useModal} from '/@/components/Modal'; | |
64 | + import ${entityName}Modal from './components/${entityName}Modal.vue' | |
65 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
66 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
67 | + <#if list_need_category> | |
68 | + import { loadCategoryData } from '/@/api/common/api' | |
69 | + import { getAuthCache, setAuthCache } from '/@/utils/auth'; | |
70 | + import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum'; | |
71 | + </#if> | |
72 | + const checkedKeys = ref<Array<string | number>>([]); | |
73 | + //注册model | |
74 | + const [registerModal, {openModal}] = useModal(); | |
75 | + //注册table数据 | |
76 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
77 | + tableProps:{ | |
78 | + title: '${tableVo.ftlDescription}', | |
79 | + api: list, | |
80 | + columns, | |
81 | + canResize:false, | |
82 | + formConfig: { | |
83 | + labelWidth: 120, | |
84 | + schemas: searchFormSchema, | |
85 | + autoSubmitOnEnter:true, | |
86 | + showAdvancedButton:true, | |
87 | + fieldMapToTime: [ | |
88 | + <#list columns as po> | |
89 | + <#if po.isQuery=='Y'> | |
90 | + <#if po.queryMode!='single'> | |
91 | + <#if po.classType=='date'> | |
92 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'], | |
93 | + <#elseif po.classType=='datetime'> | |
94 | + ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'], | |
95 | + </#if> | |
96 | + </#if> | |
97 | + </#if> | |
98 | + </#list> | |
99 | + ], | |
100 | + }, | |
101 | + actionColumn: { | |
102 | + width: 120, | |
103 | + }, | |
104 | + }, | |
105 | + exportConfig: { | |
106 | + name:"${tableVo.ftlDescription}", | |
107 | + url: getExportUrl, | |
108 | + }, | |
109 | + importConfig: { | |
110 | + url: getImportUrl | |
111 | + }, | |
112 | + }) | |
113 | + | |
114 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
115 | + | |
116 | + /** | |
117 | + * 新增事件 | |
118 | + */ | |
119 | + function handleAdd() { | |
120 | + openModal(true, { | |
121 | + isUpdate: false, | |
122 | + showFooter: true, | |
123 | + }); | |
124 | + } | |
125 | + /** | |
126 | + * 编辑事件 | |
127 | + */ | |
128 | + function handleEdit(record: Recordable) { | |
129 | + openModal(true, { | |
130 | + record, | |
131 | + isUpdate: true, | |
132 | + showFooter: true, | |
133 | + }); | |
134 | + } | |
135 | + /** | |
136 | + * 详情 | |
137 | + */ | |
138 | + function handleDetail(record: Recordable) { | |
139 | + openModal(true, { | |
140 | + record, | |
141 | + isUpdate: true, | |
142 | + showFooter: false, | |
143 | + }); | |
144 | + } | |
145 | + /** | |
146 | + * 删除事件 | |
147 | + */ | |
148 | + async function handleDelete(record) { | |
149 | + await deleteOne({id: record.id}, reload); | |
150 | + } | |
151 | + /** | |
152 | + * 批量删除事件 | |
153 | + */ | |
154 | + async function batchHandleDelete() { | |
155 | + await batchDelete({ids: checkedKeys.value}, reload); | |
156 | + } | |
157 | + /** | |
158 | + * 成功回调 | |
159 | + */ | |
160 | + function handleSuccess() { | |
161 | + reload(); | |
162 | + } | |
163 | + /** | |
164 | + * 操作栏 | |
165 | + */ | |
166 | + function getTableAction(record){ | |
167 | + return [ | |
168 | + { | |
169 | + label: '编辑', | |
170 | + onClick: handleEdit.bind(null, record), | |
171 | + } | |
172 | + ] | |
173 | + } | |
174 | + /** | |
175 | + * 下拉操作栏 | |
176 | + */ | |
177 | + function getDropDownAction(record){ | |
178 | + return [ | |
179 | + { | |
180 | + label: '详情', | |
181 | + onClick: handleDetail.bind(null, record), | |
182 | + }, { | |
183 | + label: '删除', | |
184 | + popConfirm: { | |
185 | + title: '是否确认删除', | |
186 | + confirm: handleDelete.bind(null, record), | |
187 | + } | |
188 | + } | |
189 | + ] | |
190 | + } | |
191 | + <#if list_need_category> | |
192 | + /** | |
193 | + * 初始化字典配置 | |
194 | + */ | |
195 | + function initDictConfig(){ | |
196 | + <#list columns as po> | |
197 | + <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'> | |
198 | + <#if po.classType=='cat_tree' && list_need_category==true> | |
199 | + loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => { | |
200 | + if (res) { | |
201 | + let allDictDate = getAuthCache(DB_DICT_DATA_KEY); | |
202 | + if(!allDictDate['${po.dictField?default("")}']){ | |
203 | + Object.assign(allDictDate,{'${po.dictField?default("")}':res}) | |
204 | + } | |
205 | + setAuthCache(DB_DICT_DATA_KEY,allDictDate) | |
206 | + } | |
207 | + }) | |
208 | + </#if> | |
209 | + </#if> | |
210 | + </#list> | |
211 | + } | |
212 | + initDictConfig(); | |
213 | + </#if> | |
214 | +</script> | |
215 | + | |
216 | +<style scoped> | |
217 | + | |
218 | +</style> | |
0 | 219 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +<#list subTables as sub><#rt/> | |
13 | + ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId', | |
14 | +</#list> | |
15 | +} | |
16 | +/** | |
17 | + * 导出api | |
18 | + * @param params | |
19 | + */ | |
20 | +export const getExportUrl = Api.exportXls; | |
21 | + | |
22 | +/** | |
23 | + * 导入api | |
24 | + */ | |
25 | +export const getImportUrl = Api.importExcel; | |
26 | +<#list subTables as sub><#rt/> | |
27 | +/** | |
28 | + * 查询子表数据 | |
29 | + * @param params | |
30 | + */ | |
31 | +export const ${sub.entityName?uncap_first}List = Api.${sub.entityName?uncap_first}List; | |
32 | +</#list> | |
33 | +/** | |
34 | + * 列表接口 | |
35 | + * @param params | |
36 | + */ | |
37 | +export const list = (params) => | |
38 | + defHttp.get({url: Api.list, params}); | |
39 | + | |
40 | +/** | |
41 | + * 删除单个 | |
42 | + */ | |
43 | +export const deleteOne = (params,handleSuccess) => { | |
44 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
45 | + handleSuccess(); | |
46 | + }); | |
47 | +} | |
48 | +/** | |
49 | + * 批量删除 | |
50 | + * @param params | |
51 | + */ | |
52 | +export const batchDelete = (params, handleSuccess) => { | |
53 | + Modal.confirm({ | |
54 | + title: '确认删除', | |
55 | + content: '是否删除选中数据', | |
56 | + okText: '确认', | |
57 | + cancelText: '取消', | |
58 | + onOk: () => { | |
59 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
60 | + handleSuccess(); | |
61 | + }); | |
62 | + } | |
63 | + }); | |
64 | +} | |
65 | +/** | |
66 | + * 保存或者更新 | |
67 | + * @param params | |
68 | + */ | |
69 | +export const saveOrUpdate = (params, isUpdate) => { | |
70 | + let url = isUpdate ? Api.edit : Api.save; | |
71 | + return defHttp.post({url: url, params}); | |
72 | +} | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types' | |
6 | +//列表数据 | |
7 | +export const columns: BasicColumn[] = [ | |
8 | + <#list columns as po> | |
9 | + <#if po.isShowList =='Y' && po.fieldName !='id'> | |
10 | + { | |
11 | + title: '${po.filedComment}', | |
12 | + align:"center", | |
13 | + <#if po.sort=='Y'> | |
14 | + sorter: true, | |
15 | + </#if> | |
16 | + <#if po.classType=='date'> | |
17 | + dataIndex: '${po.fieldName}', | |
18 | + customRender:({text}) =>{ | |
19 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
20 | + }, | |
21 | + <#elseif po.fieldDbType=='Blob'> | |
22 | + dataIndex: '${po.fieldName}String' | |
23 | + <#elseif po.classType=='umeditor'> | |
24 | + dataIndex: '${po.fieldName}', | |
25 | + slots: { customRender: 'htmlSlot' }, | |
26 | + <#elseif po.classType=='pca'> | |
27 | + dataIndex: '${po.fieldName}', | |
28 | + slots: { customRender: 'pcaSlot' },//TODO 未翻译 | |
29 | + <#elseif po.classType=='file'> | |
30 | + dataIndex: '${po.fieldName}', | |
31 | + slots: { customRender: 'fileSlot' }, | |
32 | + <#elseif po.classType=='image'> | |
33 | + dataIndex: '${po.fieldName}', | |
34 | + customRender:render.renderAvatar, | |
35 | + <#elseif po.classType=='switch'> | |
36 | + dataIndex: '${po.fieldName}', | |
37 | +<#assign switch_extend_arr=['Y','N']> | |
38 | +<#if po.dictField?default("")?contains("[")> | |
39 | +<#assign switch_extend_arr=po.dictField?eval> | |
40 | +</#if> | |
41 | +<#list switch_extend_arr as a> | |
42 | +<#if a_index == 0> | |
43 | +<#assign switch_extend_arr1=a> | |
44 | +<#else> | |
45 | +<#assign switch_extend_arr2=a> | |
46 | +</#if> | |
47 | +</#list> | |
48 | + customRender:({text}) => { | |
49 | + return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}]) | |
50 | + }, | |
51 | + <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'> | |
52 | + dataIndex: '${po.fieldName}_dictText' | |
53 | + <#elseif po.classType=='cat_tree'> | |
54 | + dataIndex: '${po.fieldName}', | |
55 | + <#if po.dictText?default("")?trim?length == 0> | |
56 | + customRender:({text}) => { | |
57 | + return render.renderCategoryTree(text,'${po.dictField?default("")}') | |
58 | + }, | |
59 | + <#else> | |
60 | + customRender: (text, record) => (text ? record['${po.dictText}'] : '') | |
61 | + </#if> | |
62 | + <#else> | |
63 | + dataIndex: '${po.fieldName}' | |
64 | + </#if> | |
65 | + }, | |
66 | + </#if> | |
67 | + </#list> | |
68 | +]; | |
69 | +//查询数据 | |
70 | +export const searchFormSchema: FormSchema[] = [ | |
71 | +<#-- 开始循环 --> | |
72 | +<#list columns as po> | |
73 | +<#if po.fieldDbName=='bpm_status'> | |
74 | + <#assign bpm_flag=true> | |
75 | +</#if> | |
76 | +<#if po.isQuery=='Y'> | |
77 | +<#assign query_flag=true> | |
78 | + <#assign query_field_dictCode=""> | |
79 | + <#if po.dictTable?default("")?trim?length gt 1> | |
80 | + <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
81 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
82 | + <#assign query_field_dictCode="${po.dictField}"> | |
83 | + </#if> | |
84 | +<#if po.queryMode=='single'> | |
85 | + { | |
86 | + label: "${po.filedComment}", | |
87 | + field: "${po.fieldName}", | |
88 | +<#if po.classType=='sel_search'> | |
89 | + component: 'JSearchSelect', | |
90 | + componentProps:{ | |
91 | + dict:"${po.dictTable},${po.dictText},${po.dictField}" | |
92 | + }, | |
93 | +<#elseif po.classType=='sel_user'> | |
94 | + component: 'JSelectUserByDept', | |
95 | +<#elseif po.classType=='switch'> | |
96 | + component: 'JSwitch', | |
97 | + componentProps:{ | |
98 | + <#if po.dictField != 'is_open'> | |
99 | + options:"${po.dictField}" | |
100 | + </#if> | |
101 | + }, | |
102 | + <#elseif po.classType=='sel_depart'> | |
103 | + component: 'JSelectDept', | |
104 | + <#elseif po.classType=='list_multi'> | |
105 | + component: 'JMultiSelectTag',//暂无该组件 | |
106 | + componentProps:{ | |
107 | + dictCode:"query_field_dictCode?default("")" | |
108 | + }, | |
109 | + <#elseif po.classType=='cat_tree'> | |
110 | + component: 'JCategorySelect', | |
111 | + componentProps:{ | |
112 | + pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题 | |
113 | + }, | |
114 | +<#elseif po.classType=='date'> | |
115 | + component: 'DatePicker', | |
116 | +<#elseif po.classType=='datetime'> | |
117 | + component: 'DatePicker', | |
118 | + componentProps: { | |
119 | + showTime:true | |
120 | + }, | |
121 | +<#elseif po.classType=='pca'> | |
122 | + component: 'JAreaLinkage', | |
123 | +<#elseif po.classType=='popup'> | |
124 | + component: 'JPopup', | |
125 | + componentProps: ({ formActionType }) => { | |
126 | + const {setFieldsValue} = formActionType; | |
127 | + return{ | |
128 | + setFieldsValue:setFieldsValue, | |
129 | + code:"${po.dictTable}", | |
130 | + fieldConfig:"${po.dictField}", | |
131 | + multi:${po.extendParams.popupMulti?c}, | |
132 | + } | |
133 | + }, | |
134 | +<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'> | |
135 | +<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- --> | |
136 | + component: 'JDictSelectTag', | |
137 | + componentProps:{ | |
138 | + <#if po.dictTable?default("")?trim?length gt 1> | |
139 | + dictCode:"${po.dictTable},${po.dictText},${po.dictField}" | |
140 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
141 | + dictCode:"${po.dictField}" | |
142 | + </#if> | |
143 | + }, | |
144 | +<#else> | |
145 | + component: 'Input', | |
146 | +</#if> | |
147 | + colProps: {span: 6}, | |
148 | + }, | |
149 | +<#else> | |
150 | + { | |
151 | + label: "${po.filedComment}", | |
152 | + field: "${po.fieldName}", | |
153 | +<#if po.classType=='date'> | |
154 | + component: 'RangePicker', | |
155 | +<#elseif po.classType=='datetime'> | |
156 | + component: 'RangePicker', | |
157 | + componentProps: { | |
158 | + showTime:true | |
159 | + }, | |
160 | +<#else> | |
161 | + component: 'Input', //TODO 范围查询 | |
162 | +</#if> | |
163 | + colProps: {span: 6}, | |
164 | + }, | |
165 | +</#if> | |
166 | +</#if> | |
167 | +</#list> | |
168 | +<#-- 结束循环 --> | |
169 | +]; | |
170 | +//表单数据 | |
171 | +export const formSchema: FormSchema[] = [ | |
172 | +<#assign form_cat_tree = false> | |
173 | +<#assign form_cat_back = ""> | |
174 | +<#assign bpm_flag=false> | |
175 | +<#list columns as po><#rt/> | |
176 | +<#if po.fieldDbName=='bpm_status'> | |
177 | + <#assign bpm_flag=true> | |
178 | +</#if> | |
179 | +<#if po.isShow =='Y'> | |
180 | +<#assign form_field_dictCode=""> | |
181 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
182 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
183 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
184 | + <#assign form_field_dictCode="${po.dictField}"> | |
185 | + </#if> | |
186 | + { | |
187 | + label: '${po.filedComment}', | |
188 | + field: '${po.fieldName}', | |
189 | + <#if po.classType =='date'> | |
190 | + component: 'DatePicker', | |
191 | + <#elseif po.fieldType =='datetime'> | |
192 | + component: 'DatePicker', | |
193 | + componentProps: { | |
194 | + showTime:true | |
195 | + }, | |
196 | + <#elseif po.fieldType =='time'> | |
197 | + component: 'TimePicker', | |
198 | + <#elseif po.classType =='popup'> | |
199 | + component: 'JPopup', | |
200 | + componentProps: ({ formActionType }) => { | |
201 | + const {setFieldsValue} = formActionType; | |
202 | + return{ | |
203 | + setFieldsValue:setFieldsValue, | |
204 | + code:"${po.dictTable}", | |
205 | + fieldConfig:${po.dictField}, | |
206 | + multi:${po.extendParams.popupMulti?c}, | |
207 | + } | |
208 | + } | |
209 | + <#elseif po.classType =='sel_depart'> | |
210 | + component: 'JSelectDept', | |
211 | + <#elseif po.classType =='switch'> | |
212 | + component: 'JSwitch', | |
213 | + componentProps:{ | |
214 | + <#if po.dictField != 'is_open'> | |
215 | + options:${po.dictField} | |
216 | + </#if> | |
217 | + } | |
218 | + <#elseif po.classType =='pca'> | |
219 | + component: 'JAreaLinkage', | |
220 | + <#elseif po.classType =='markdown'> | |
221 | + component: 'JMarkdownEditor',//注意string转换问题 | |
222 | + <#elseif po.classType =='password'> | |
223 | + component: 'InputPassword', | |
224 | + <#elseif po.classType =='sel_user'> | |
225 | + component: 'JSelectUserByDept', | |
226 | + componentProps:{ | |
227 | + labelKey:'realname', | |
228 | + } | |
229 | + <#elseif po.classType =='textarea'> | |
230 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
231 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
232 | + component: 'JDictSelectTag', | |
233 | + componentProps:{ | |
234 | + dictCode:"${form_field_dictCode}" | |
235 | + } | |
236 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
237 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
238 | + componentProps:{ | |
239 | + dictCode:"${form_field_dictCode}" | |
240 | + } | |
241 | + <#elseif po.classType=='sel_search'> | |
242 | + component: 'JSearchSelect', | |
243 | + componentProps:{ | |
244 | + dict:"${form_field_dictCode}" | |
245 | + } | |
246 | +<#elseif po.classType=='cat_tree'> | |
247 | + <#assign form_cat_tree = true> | |
248 | + component: 'JCategorySelect', | |
249 | + componentProps:{ | |
250 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
251 | + } | |
252 | + <#if po.dictText?default("")?trim?length gt 1> | |
253 | + <#assign form_cat_back = "${po.dictText}"> | |
254 | + </#if> | |
255 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
256 | + component: 'InputNumber', | |
257 | + <#elseif po.classType=='file'> | |
258 | + component: 'JUpload', | |
259 | + componentProps:{ | |
260 | + <#if po.uploadnum??> | |
261 | + maxCount:${po.uploadnum} | |
262 | + </#if> | |
263 | + } | |
264 | + <#elseif po.classType=='image'> | |
265 | + component: 'JImageUpload', | |
266 | + componentProps:{ | |
267 | + <#if po.uploadnum??> | |
268 | + fileMax:${po.uploadnum} | |
269 | + </#if> | |
270 | + } | |
271 | + <#elseif po.classType=='umeditor'> | |
272 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
273 | + <#elseif po.classType == 'sel_tree'> | |
274 | + component: 'JTreeSelect', | |
275 | + componentProps:{ | |
276 | + <#if po.dictText??> | |
277 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
278 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
279 | + <#elseif po.dictText?split(',')[1]??> | |
280 | + pidField:"${po.dictText?split(',')[1]}", | |
281 | + <#elseif po.dictText?split(',')[3]??> | |
282 | + hasChildField:"${po.dictText?split(',')[3]}", | |
283 | + </#if> | |
284 | + </#if> | |
285 | + pidValue:"${po.dictField}", | |
286 | + } | |
287 | + <#else> | |
288 | + component: 'Input', | |
289 | + </#if> | |
290 | + <#include "/common/utils.ftl"> | |
291 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
292 | + dynamicRules: ({model,schema}) => { | |
293 | + <#if po.fieldName != 'id'> | |
294 | + <#assign fieldValidType = po.fieldValidType!''> | |
295 | + return [ | |
296 | + <#-- 非空校验 --> | |
297 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
298 | + { required: true, message: '请输入${po.filedComment}!'}, | |
299 | + <#elseif fieldValidType!=''> | |
300 | + { required: false}, | |
301 | + </#if> | |
302 | + <#-- 唯一校验 --> | |
303 | + <#if fieldValidType == 'only'> | |
304 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
305 | + <#-- 6到16位数字 --> | |
306 | + <#elseif fieldValidType == 'n6-16'> | |
307 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
308 | + <#-- 6到16位任意字符 --> | |
309 | + <#elseif fieldValidType == '*6-16'> | |
310 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
311 | + <#-- 6到18位字符串 --> | |
312 | + <#elseif fieldValidType == 's6-18'> | |
313 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
314 | + <#-- 网址 --> | |
315 | + <#elseif fieldValidType == 'url'> | |
316 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
317 | + <#-- 电子邮件 --> | |
318 | + <#elseif fieldValidType == 'e'> | |
319 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
320 | + <#-- 手机号码 --> | |
321 | + <#elseif fieldValidType == 'm'> | |
322 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
323 | + <#-- 邮政编码 --> | |
324 | + <#elseif fieldValidType == 'p'> | |
325 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
326 | + <#-- 字母 --> | |
327 | + <#elseif fieldValidType == 's'> | |
328 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
329 | + <#-- 数字 --> | |
330 | + <#elseif fieldValidType == 'n'> | |
331 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
332 | + <#-- 整数 --> | |
333 | + <#elseif fieldValidType == 'z'> | |
334 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
335 | + <#-- 金额 --> | |
336 | + <#elseif fieldValidType == 'money'> | |
337 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
338 | + <#-- 正则校验 --> | |
339 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
340 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
341 | + <#-- 无校验 --> | |
342 | + <#else> | |
343 | + <#t> | |
344 | + </#if> | |
345 | + ]; | |
346 | + </#if> | |
347 | + }, | |
348 | + </#if> | |
349 | + <#if po.readonly=='Y'> | |
350 | + dynamicDisabled:true | |
351 | + </#if> | |
352 | + }, | |
353 | +</#if> | |
354 | +</#list> | |
355 | +]; | |
356 | +//子表单数据 | |
357 | +<#list subTables as sub> | |
358 | +<#if sub.foreignRelationType =='1'> | |
359 | +export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [ | |
360 | +<#assign form_cat_tree = false> | |
361 | +<#assign form_cat_back = ""> | |
362 | +<#assign bpm_flag=false> | |
363 | +<#list sub.colums as po><#rt/> | |
364 | +<#if po.fieldDbName=='bpm_status'> | |
365 | + <#assign bpm_flag=true> | |
366 | +</#if> | |
367 | +<#if po.isShow =='Y'> | |
368 | +<#assign form_field_dictCode=""> | |
369 | + <#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1> | |
370 | + <#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}"> | |
371 | + <#elseif po.dictField?default("")?trim?length gt 1> | |
372 | + <#assign form_field_dictCode="${po.dictField}"> | |
373 | + </#if> | |
374 | + { | |
375 | + label: '${po.filedComment}', | |
376 | + field: '${po.fieldName}', | |
377 | + <#if po.classType =='date'> | |
378 | + component: 'DatePicker', | |
379 | + <#elseif po.fieldType =='datetime'> | |
380 | + component: 'DatePicker', | |
381 | + componentProps: { | |
382 | + showTime:true | |
383 | + }, | |
384 | + <#elseif po.fieldType =='time'> | |
385 | + component: 'TimePicker', | |
386 | + <#elseif po.classType =='popup'> | |
387 | + component: 'JPopup', | |
388 | + componentProps: ({ formActionType }) => { | |
389 | + const {setFieldsValue} = formActionType; | |
390 | + return{ | |
391 | + setFieldsValue:setFieldsValue, | |
392 | + code:"${po.dictTable}", | |
393 | + fieldConfig:${po.dictField}, | |
394 | + multi:${po.extendParams.popupMulti?c}, | |
395 | + } | |
396 | + } | |
397 | + <#elseif po.classType =='sel_depart'> | |
398 | + component: 'JSelectDept', | |
399 | + <#elseif po.classType =='switch'> | |
400 | + component: 'JSwitch', | |
401 | + componentProps:{ | |
402 | + <#if po.dictField != 'is_open'> | |
403 | + options:${po.dictField} | |
404 | + </#if> | |
405 | + } | |
406 | + <#elseif po.classType =='pca'> | |
407 | + component: 'JAreaLinkage', | |
408 | + <#elseif po.classType =='markdown'> | |
409 | + component: 'JMarkdownEditor',//注意string转换问题 | |
410 | + <#elseif po.classType =='password'> | |
411 | + component: 'InputPassword', | |
412 | + <#elseif po.classType =='sel_user'> | |
413 | + component: 'JSelectUserByDept', | |
414 | + componentProps:{ | |
415 | + labelKey:'realname', | |
416 | + } | |
417 | + <#elseif po.classType =='textarea'> | |
418 | + component: 'InputTextArea',//TODO 注意string转换问题 | |
419 | + <#elseif po.classType=='list' || po.classType=='radio'> | |
420 | + component: 'JDictSelectTag', | |
421 | + componentProps:{ | |
422 | + dictCode:"${form_field_dictCode}" | |
423 | + } | |
424 | + <#elseif po.classType=='list_multi' || po.classType=='checkbox'> | |
425 | + component: 'JMultiSelectTag',//TODO 暂无该组件 | |
426 | + componentProps:{ | |
427 | + dictCode:"${form_field_dictCode}" | |
428 | + } | |
429 | + <#elseif po.classType=='sel_search'> | |
430 | + component: 'JSearchSelect', | |
431 | + componentProps:{ | |
432 | + dict:"${form_field_dictCode}" | |
433 | + } | |
434 | +<#elseif po.classType=='cat_tree'> | |
435 | + <#assign form_cat_tree = true> | |
436 | + component: 'JCategorySelect', | |
437 | + componentProps:{ | |
438 | + pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题 | |
439 | + } | |
440 | + <#if po.dictText?default("")?trim?length gt 1> | |
441 | + <#assign form_cat_back = "${po.dictText}"> | |
442 | + </#if> | |
443 | + <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'> | |
444 | + component: 'InputNumber', | |
445 | + <#elseif po.classType=='file'> | |
446 | + component: 'JUpload', | |
447 | + componentProps:{ | |
448 | + <#if po.uploadnum??> | |
449 | + maxCount:${po.uploadnum} | |
450 | + </#if> | |
451 | + } | |
452 | + <#elseif po.classType=='image'> | |
453 | + component: 'JImageUpload', | |
454 | + componentProps:{ | |
455 | + <#if po.uploadnum??> | |
456 | + fileMax:${po.uploadnum} | |
457 | + </#if> | |
458 | + } | |
459 | + <#elseif po.classType=='umeditor'> | |
460 | + component: 'JCodeEditor', //TODO String后缀暂未添加 | |
461 | + <#elseif po.classType == 'sel_tree'> | |
462 | + component: 'JTreeSelect', | |
463 | + componentProps:{ | |
464 | + <#if po.dictText??> | |
465 | + <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??> | |
466 | + dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}", | |
467 | + <#elseif po.dictText?split(',')[1]??> | |
468 | + pidField:"${po.dictText?split(',')[1]}", | |
469 | + <#elseif po.dictText?split(',')[3]??> | |
470 | + hasChildField:"${po.dictText?split(',')[3]}", | |
471 | + </#if> | |
472 | + </#if> | |
473 | + pidValue:"${po.dictField}", | |
474 | + } | |
475 | + <#else> | |
476 | + component: 'Input', | |
477 | + </#if> | |
478 | + <#include "/common/utils.ftl"> | |
479 | + <#if po.isShow == 'Y' && poHasCheck(po)> | |
480 | + dynamicRules: ({model,schema}) => { | |
481 | + <#if po.fieldName != 'id'> | |
482 | + <#assign fieldValidType = po.fieldValidType!''> | |
483 | + return [ | |
484 | + <#-- 非空校验 --> | |
485 | + <#if po.nullable == 'N' || fieldValidType == '*'> | |
486 | + { required: true, message: '请输入${po.filedComment}!'}, | |
487 | + <#elseif fieldValidType!=''> | |
488 | + { required: false}, | |
489 | + </#if> | |
490 | + <#-- 唯一校验 --> | |
491 | + <#if fieldValidType == 'only'> | |
492 | + {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]}, | |
493 | + <#-- 6到16位数字 --> | |
494 | + <#elseif fieldValidType == 'n6-16'> | |
495 | + { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'}, | |
496 | + <#-- 6到16位任意字符 --> | |
497 | + <#elseif fieldValidType == '*6-16'> | |
498 | + { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'}, | |
499 | + <#-- 6到18位字符串 --> | |
500 | + <#elseif fieldValidType == 's6-18'> | |
501 | + { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'}, | |
502 | + <#-- 网址 --> | |
503 | + <#elseif fieldValidType == 'url'> | |
504 | + { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'}, | |
505 | + <#-- 电子邮件 --> | |
506 | + <#elseif fieldValidType == 'e'> | |
507 | + { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'}, | |
508 | + <#-- 手机号码 --> | |
509 | + <#elseif fieldValidType == 'm'> | |
510 | + { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'}, | |
511 | + <#-- 邮政编码 --> | |
512 | + <#elseif fieldValidType == 'p'> | |
513 | + { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'}, | |
514 | + <#-- 字母 --> | |
515 | + <#elseif fieldValidType == 's'> | |
516 | + { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'}, | |
517 | + <#-- 数字 --> | |
518 | + <#elseif fieldValidType == 'n'> | |
519 | + { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'}, | |
520 | + <#-- 整数 --> | |
521 | + <#elseif fieldValidType == 'z'> | |
522 | + { pattern: /^-?\d+$/, message: '请输入整数!'}, | |
523 | + <#-- 金额 --> | |
524 | + <#elseif fieldValidType == 'money'> | |
525 | + { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'}, | |
526 | + <#-- 正则校验 --> | |
527 | + <#elseif fieldValidType != '' && fieldValidType != '*'> | |
528 | + { pattern: '${fieldValidType}', message: '不符合校验规则!'}, | |
529 | + <#-- 无校验 --> | |
530 | + <#else> | |
531 | + <#t> | |
532 | + </#if> | |
533 | + ]; | |
534 | + </#if> | |
535 | + }, | |
536 | + </#if> | |
537 | + <#if po.readonly=='Y'> | |
538 | + dynamicDisabled:true | |
539 | + </#if> | |
540 | + }, | |
541 | +</#if> | |
542 | +</#list> | |
543 | +]; | |
544 | +</#if> | |
545 | +</#list> | |
546 | +//子表表格配置 | |
547 | +<#list subTables as sub> | |
548 | +<#if sub.foreignRelationType =='0'> | |
549 | +export const ${sub.entityName?uncap_first}Columns: JVxeColumn[] = [ | |
550 | +<#assign popupBackFields = ""> | |
551 | + | |
552 | +<#-- 循环子表的列 开始 --> | |
553 | +<#list sub.colums as col><#rt/> | |
554 | +<#if col.isShow =='Y'> | |
555 | +<#if col.filedComment !='外键' > | |
556 | + { | |
557 | + title: '${col.filedComment}', | |
558 | + key: '${autoStringSuffixForModel(col)}', | |
559 | +<#if col.classType =='date'> | |
560 | + type: JVxeTypes.date, | |
561 | + <#if col.readonly=='Y'> | |
562 | + disabled:true, | |
563 | + </#if> | |
564 | +<#elseif col.classType =='datetime'> | |
565 | + type: JVxeTypes.datetime, | |
566 | + <#if col.readonly=='Y'> | |
567 | + disabled:true, | |
568 | + </#if> | |
569 | +<#elseif col.classType =='textarea'> | |
570 | + type: JVxeTypes.textarea, | |
571 | + <#if col.readonly=='Y'> | |
572 | + disabled:true, | |
573 | + </#if> | |
574 | +<#elseif "int,decimal,double,"?contains(col.classType)> | |
575 | + type: JVxeTypes.inputNumber, | |
576 | + <#if col.readonly=='Y'> | |
577 | + disabled:true, | |
578 | + </#if> | |
579 | +<#elseif col.classType =='list' || col.classType =='radio'> | |
580 | + type: JVxeTypes.select, | |
581 | + options:[], | |
582 | + <#if col.dictTable?default("")?trim?length gt 1> | |
583 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
584 | + <#else> | |
585 | + dictCode:"${col.dictField}", | |
586 | + </#if> | |
587 | + <#if col.readonly=='Y'> | |
588 | + disabled:true, | |
589 | + </#if> | |
590 | +<#elseif col.classType =='list_multi' || col.classType =='checkbox'> | |
591 | + type: JVxeTypes.selectMultiple, | |
592 | + options:[], | |
593 | + <#if col.dictTable?default("")?trim?length gt 1> | |
594 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
595 | + <#else> | |
596 | + dictCode:"${col.dictField}", | |
597 | + </#if> | |
598 | + <#if col.readonly=='Y'> | |
599 | + disabled:true, | |
600 | + </#if> | |
601 | +<#elseif col.classType =='sel_search'> | |
602 | + type: JVxeTypes.selectSearch, | |
603 | + <#if col.dictTable?default("")?trim?length gt 1> | |
604 | + dictCode:"${col.dictTable},${col.dictText},${col.dictField}", | |
605 | + <#else> | |
606 | + dictCode:"${col.dictField}", | |
607 | + </#if> | |
608 | + <#if col.readonly=='Y'> | |
609 | + disabled:true, | |
610 | + </#if> | |
611 | +<#elseif col.classType =='image'> | |
612 | + type: JVxeTypes.image, | |
613 | + token:true, | |
614 | + responseName:"message", | |
615 | + <#if col.readonly=='Y'> | |
616 | + disabled:true, | |
617 | + </#if> | |
618 | + <#if col.uploadnum??> | |
619 | + number: ${col.uploadnum}, | |
620 | + </#if> | |
621 | +<#elseif col.classType =='file'> | |
622 | + type: JVxeTypes.file, | |
623 | + token:true, | |
624 | + responseName:"message", | |
625 | + <#if col.readonly=='Y'> | |
626 | + disabled:true, | |
627 | + </#if> | |
628 | + <#if col.uploadnum??> | |
629 | + number: ${col.uploadnum}, | |
630 | + </#if> | |
631 | +<#elseif col.classType =='switch'> | |
632 | + type: JVxeTypes.checkbox, | |
633 | + <#if col.dictField == 'is_open'> | |
634 | + customValue: ['Y', 'N'], | |
635 | + <#else> | |
636 | + customValue: ${col.dictField}, | |
637 | + </#if> | |
638 | + <#if col.readonly=='Y'> | |
639 | + disabled:true, | |
640 | + </#if> | |
641 | +<#elseif col.classType =='popup'> | |
642 | +<#if popupBackFields?length gt 0> | |
643 | + <#assign popupBackFields = "${popupBackFields}"+","+"${col.dictText}"> | |
644 | +<#else> | |
645 | + <#assign popupBackFields = "${col.dictText}"> | |
646 | +</#if> | |
647 | + type: JVxeTypes.popup, | |
648 | + popupCode:"${col.dictTable}", | |
649 | + field:"${col.dictField}", | |
650 | + orgFields:"${col.dictField}", | |
651 | + destFields:"${Format.underlineToHump(col.dictText)}", | |
652 | + <#if col.readonly=='Y'> | |
653 | + disabled:true, | |
654 | + </#if> | |
655 | +<#else> | |
656 | + type: JVxeTypes.input, | |
657 | + <#if col.readonly=='Y'> | |
658 | + disabled:true, | |
659 | + </#if> | |
660 | +</#if> | |
661 | +<#if col.classType =='list_multi' || col.classType =='checkbox'> | |
662 | + width:"250px", | |
663 | +<#else> | |
664 | + width:"200px", | |
665 | +</#if> | |
666 | +<#if col.classType =='file'> | |
667 | + placeholder: '请选择文件', | |
668 | +<#else> | |
669 | + placeholder: '请输入${'$'}{title}', | |
670 | +</#if> | |
671 | +<#if col.defaultVal??> | |
672 | +<#if col.fieldDbType=="BigDecimal" || col.fieldDbType=="double" || col.fieldDbType=="int"> | |
673 | + defaultValue:${col.defaultVal}, | |
674 | + <#else> | |
675 | + defaultValue:"${col.defaultVal}", | |
676 | +</#if> | |
677 | +<#else> | |
678 | + defaultValue:'', | |
679 | +</#if> | |
680 | +<#-- 子表的校验 --> | |
681 | +<#assign subFieldValidType = col.fieldValidType!''> | |
682 | +<#-- 非空校验 --> | |
683 | +<#if col.nullable == 'N' || subFieldValidType == '*'> | |
684 | + validateRules: [{ required: true, message: '${'$'}{title}不能为空' }], | |
685 | +<#-- 其他情况下,只要有值就被认为是正则校验 --> | |
686 | +<#elseif subFieldValidType?length gt 0> | |
687 | +<#assign subMessage = '格式不正确'> | |
688 | +<#if subFieldValidType == 'only' > | |
689 | + <#assign subMessage = '不能重复'> | |
690 | +</#if> | |
691 | + validateRules: [{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }], | |
692 | +</#if> | |
693 | + }, | |
694 | +</#if> | |
695 | +</#if> | |
696 | +</#list> | |
697 | +<#-- 循环子表的列 结束 --> | |
698 | + ] | |
699 | +</#if> | |
700 | +</#list> | |
0 | 701 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit"> | |
3 | + <!-- 子表单区域 --> | |
4 | + <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs"> | |
5 | + <!--主表区域 --> | |
6 | + <a-tab-pane tab="${tableVo.ftlDescription}" :key="refKeys[0]" :forceRender="true"> | |
7 | + <BasicForm @register="registerForm" ref="formRef"/> | |
8 | + </a-tab-pane> | |
9 | + <!--子表单区域 --> | |
10 | +<#list subTables as sub><#rt/> | |
11 | + <#if sub.foreignRelationType =='1'> | |
12 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index+1}]" :forceRender="true"> | |
13 | + <${sub.entityName}Form ref="${sub.entityName?uncap_first}Form"></${sub.entityName}Form> | |
14 | + </a-tab-pane> | |
15 | + | |
16 | + <#else> | |
17 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index+1}]" :forceRender="true"> | |
18 | + <JVxeTable | |
19 | + keep-source | |
20 | + resizable | |
21 | + :ref="refKeys[${sub_index+1}]" | |
22 | + :loading="${sub.entityName?uncap_first}Table.loading" | |
23 | + :columns="${sub.entityName?uncap_first}Table.columns" | |
24 | + :dataSource="${sub.entityName?uncap_first}Table.dataSource" | |
25 | + :maxHeight="300" | |
26 | + :rowNumber="true" | |
27 | + :rowSelection="true" | |
28 | + :toolbar="true" | |
29 | + /> | |
30 | + </a-tab-pane> | |
31 | + </#if> | |
32 | +</#list> | |
33 | + </a-tabs> | |
34 | + </BasicModal> | |
35 | +</template> | |
36 | + | |
37 | +<script lang="ts" setup> | |
38 | + import {ref, computed, unref,reactive} from 'vue'; | |
39 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
40 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
41 | + import { JVxeTable } from '/@/components/jeecg/JVxeTable' | |
42 | + import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts' | |
43 | + <#list subTables as sub> | |
44 | + <#if sub.foreignRelationType =='1'> | |
45 | + import ${sub.entityName}Form from './${sub.entityName}Form.vue' | |
46 | + </#if> | |
47 | + </#list> | |
48 | + import {formSchema<#list subTables as sub><#if sub.foreignRelationType =='0'>,${sub.entityName?uncap_first}Columns</#if></#list>} from '../${entityName?uncap_first}.data'; | |
49 | + import {saveOrUpdate<#list subTables as sub>,${sub.entityName?uncap_first}List</#list>} from '../${entityName?uncap_first}.api'; | |
50 | + import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils' | |
51 | + // Emits声明 | |
52 | + const emit = defineEmits(['register','success']); | |
53 | + const isUpdate = ref(true); | |
54 | + const refKeys = ref(['${tableVo.entityName?uncap_first}',<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]); | |
55 | + <#assign hasOne2Many = false> | |
56 | + <#assign hasOne2One = false> | |
57 | + const activeKey = ref('${tableVo.entityName?uncap_first}'); | |
58 | +<#list subTables as sub> | |
59 | +<#if sub.foreignRelationType =='0'> | |
60 | + <#assign hasOne2Many = true> | |
61 | + const ${sub.entityName?uncap_first} = ref(); | |
62 | +</#if> | |
63 | +<#if sub.foreignRelationType =='1'> | |
64 | + <#assign hasOne2One = true> | |
65 | + const ${sub.entityName?uncap_first}Form = ref(); | |
66 | +</#if> | |
67 | +</#list> | |
68 | + const tableRefs = {<#list subTables as sub><#if sub.foreignRelationType =='0'>${sub.entityName?uncap_first}, <#assign hasOne2Many = true></#if></#list>}; | |
69 | + <#list subTables as sub> | |
70 | + <#if sub.foreignRelationType =='0'> | |
71 | + const ${sub.entityName?uncap_first}Table = reactive({ | |
72 | + loading: false, | |
73 | + dataSource: [], | |
74 | + columns:${sub.entityName?uncap_first}Columns | |
75 | + }) | |
76 | + </#if> | |
77 | + </#list> | |
78 | + //表单配置 | |
79 | + const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |
80 | + labelWidth: 150, | |
81 | + schemas: formSchema, | |
82 | + showActionButtonGroup: false, | |
83 | + }); | |
84 | + //表单赋值 | |
85 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
86 | + //重置表单 | |
87 | + await reset(); | |
88 | + setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter}); | |
89 | + isUpdate.value = !!data?.isUpdate; | |
90 | + if (unref(isUpdate)) { | |
91 | + //表单赋值 | |
92 | + await setFieldsValue({ | |
93 | + ...data.record, | |
94 | + }); | |
95 | + <#list subTables as sub><#rt/> | |
96 | + <#if sub.foreignRelationType =='1'> | |
97 | + ${sub.entityName?uncap_first}Form.value.initFormData(${sub.entityName?uncap_first}List,data?.record?.id) | |
98 | + </#if> | |
99 | + </#list> | |
100 | + <#list subTables as sub><#rt/> | |
101 | + <#if sub.foreignRelationType =='0'> | |
102 | + requestSubTableData(${sub.entityName?uncap_first}List, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table) | |
103 | + </#if> | |
104 | + </#list> | |
105 | + } | |
106 | + // 隐藏底部时禁用整个表单 | |
107 | + setProps({ disabled: !data?.showFooter }) | |
108 | + }); | |
109 | + //方法配置 | |
110 | + const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys<#if hasOne2One==true>,validateSubForm</#if>); | |
111 | + | |
112 | + //设置标题 | |
113 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
114 | + | |
115 | + async function reset(){ | |
116 | + await resetFields(); | |
117 | + activeKey.value = ref('${tableVo.entityName?uncap_first}'); | |
118 | + <#list subTables as sub> | |
119 | + <#if sub.foreignRelationType =='0'> | |
120 | + ${sub.entityName?uncap_first}Table.dataSource = []; | |
121 | + </#if> | |
122 | + <#if sub.foreignRelationType =='1'> | |
123 | + ${sub.entityName?uncap_first}Form.value.resetFields(); | |
124 | + </#if> | |
125 | + </#list> | |
126 | + } | |
127 | + function classifyIntoFormData(allValues) { | |
128 | + let main = Object.assign({}, allValues.formValue) | |
129 | + return { | |
130 | + ...main, // 展开 | |
131 | + <#assign subManyIndex = 0> | |
132 | + <#list subTables as sub><#rt/> | |
133 | + <#if sub.foreignRelationType =='0'> | |
134 | + ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData, | |
135 | + <#assign subManyIndex = subManyIndex+1> | |
136 | + <#else> | |
137 | + ${sub.entityName?uncap_first}List: ${sub.entityName?uncap_first}Form.value.getFormData(), | |
138 | + </#if> | |
139 | + </#list> | |
140 | + } | |
141 | + } | |
142 | + <#if hasOne2One==true> | |
143 | + //校验所有一对一子表表单 | |
144 | + function validateSubForm(allValues){ | |
145 | + return new Promise((resolve,reject)=>{ | |
146 | + Promise.all([ | |
147 | + <#list subTables as sub><#rt/> | |
148 | + <#if sub.foreignRelationType =='1'> | |
149 | + ${sub.entityName?uncap_first}Form.value.validateForm(${sub_index+1}), | |
150 | + </#if> | |
151 | + </#list> | |
152 | + ]).then(() => { | |
153 | + resolve(allValues) | |
154 | + }).catch(e => { | |
155 | + if (e.error === VALIDATE_FAILED) { | |
156 | + // 如果有未通过表单验证的子表,就自动跳转到它所在的tab | |
157 | + activeKey.value = e.index == null ? unref(activeKey) : refKeys.value[e.index] | |
158 | + } else { | |
159 | + console.error(e) | |
160 | + } | |
161 | + }) | |
162 | + }) | |
163 | + } | |
164 | + </#if> | |
165 | + //表单提交事件 | |
166 | + async function requestAddOrEdit(values) { | |
167 | + try { | |
168 | + setModalProps({confirmLoading: true}); | |
169 | + //提交表单 | |
170 | + await saveOrUpdate(values, isUpdate.value); | |
171 | + //关闭弹窗 | |
172 | + closeModal(); | |
173 | + //刷新列表 | |
174 | + emit('success'); | |
175 | + } finally { | |
176 | + setModalProps({confirmLoading: false}); | |
177 | + } | |
178 | + } | |
179 | +</script> | |
180 | + | |
181 | +<style lang="less" scoped> | |
182 | + | |
183 | +</style> | |
0 | 184 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
0 → 100644
1 | +<#list subTables as sub> | |
2 | +<#if sub.foreignRelationType=='1'> | |
3 | +#segment#${sub.entityName}Form.vue | |
4 | +<template> | |
5 | + <BasicForm @register="registerForm"/> | |
6 | +</template> | |
7 | +<script lang="ts"> | |
8 | + import {defineComponent} from 'vue'; | |
9 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
10 | + import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data'; | |
11 | + import {defHttp} from '/@/utils/http/axios'; | |
12 | + import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils' | |
13 | + | |
14 | + export default defineComponent({ | |
15 | + name:"${sub.entityName}Form", | |
16 | + components: {BasicForm}, | |
17 | + emits:['register'], | |
18 | + setup(_,{emit}) { | |
19 | + const [registerForm, {resetFields, setFieldsValue,getFieldsValue,validate}] = useForm({ | |
20 | + labelWidth: 150, | |
21 | + schemas: ${sub.entityName?uncap_first}FormSchema, | |
22 | + showActionButtonGroup: false, | |
23 | + }); | |
24 | + /** | |
25 | + *初始化加载数据 | |
26 | + */ | |
27 | + function initFormData(url,id){ | |
28 | + if(id){ | |
29 | + defHttp.get({url,params:{id}},{isTransformResponse:false}).then(res=>{ | |
30 | + res.success && setFieldsValue({...res.result[0]}); | |
31 | + }) | |
32 | + } | |
33 | + } | |
34 | + /** | |
35 | + *获取表单数据 | |
36 | + */ | |
37 | + function getFormData(){ | |
38 | + return [getFieldsValue()]; | |
39 | + } | |
40 | + /** | |
41 | + *表单校验 | |
42 | + */ | |
43 | + function validateForm(index){ | |
44 | + return new Promise((resolve, reject) => { | |
45 | + // 验证子表表单 | |
46 | + validate().then(()=>{ | |
47 | + return resolve() | |
48 | + }).catch(()=> { | |
49 | + return reject({ error: VALIDATE_FAILED ,index}) | |
50 | + }) | |
51 | + }) | |
52 | + } | |
53 | + return { | |
54 | + registerForm, | |
55 | + resetFields, | |
56 | + initFormData, | |
57 | + getFormData, | |
58 | + validateForm | |
59 | + } | |
60 | + } | |
61 | + }) | |
62 | +</script> | |
63 | +</#if> | |
64 | +</#list> | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -93,7 +93,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
93 | 93 | */ |
94 | 94 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
95 | 95 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
96 | - @PutMapping(value = "/edit") | |
96 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
97 | 97 | public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) { |
98 | 98 | ${entityName?uncap_first}Service.updateById(${entityName?uncap_first}); |
99 | 99 | return Result.OK("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}Form.vuei
0 → 100644
1 | +<template> | |
2 | + <view> | |
3 | + <!--标题和返回--> | |
4 | + <cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName"> | |
5 | + <block slot="backText">返回</block> | |
6 | + <block slot="content">${tableVo.ftlDescription}</block> | |
7 | + </cu-custom> | |
8 | + <!--表单区域--> | |
9 | + <view> | |
10 | + <form> | |
11 | + <#list columns as po><#rt/> | |
12 | + <#if po.fieldName !='id'><#rt/> | |
13 | + <#if po.fieldType =='date'> | |
14 | + <my-date label="${po.filedComment}:" fields="day" v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}"></my-date> | |
15 | + <#elseif po.fieldType =='datetime'> | |
16 | + <my-date label="${po.filedComment}:" v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}"></my-date> | |
17 | + <#else> | |
18 | + <view class="cu-form-group"> | |
19 | + <view class="flex align-center"> | |
20 | + <view class="title"><text space="ensp">${po.filedComment}:</text></view> | |
21 | + <input <#if "int,decimal,double,"?contains(po.fieldType)>type="number"</#if> placeholder="请输入${po.filedComment}" v-model="model.${po.fieldName}"/> | |
22 | + </view> | |
23 | + </view> | |
24 | + </#if> | |
25 | + </#if> | |
26 | + </#list> | |
27 | + <view class="padding"> | |
28 | + <button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit"> | |
29 | + <text v-if="loading" class="cuIcon-loading2 cuIconfont-spin"></text>提交 | |
30 | + </button> | |
31 | + </view> | |
32 | + </form> | |
33 | + </view> | |
34 | + </view> | |
35 | +</template> | |
36 | + | |
37 | +<script> | |
38 | + import myDate from '@/components/my-componets/my-date.vue' | |
39 | + | |
40 | + export default { | |
41 | + name: "${entityName}Form", | |
42 | + components:{myDate}, | |
43 | + props:{ | |
44 | + formData:{ | |
45 | + type:Object, | |
46 | + default:()=>{}, | |
47 | + required:false | |
48 | + } | |
49 | + }, | |
50 | + data(){ | |
51 | + return { | |
52 | + CustomBar: this.CustomBar, | |
53 | + NavBarColor: this.NavBarColor, | |
54 | + loading:false, | |
55 | + model: {}, | |
56 | + backRouteName:'index', | |
57 | + url: { | |
58 | + queryById: "/${entityPackage}/${entityName?uncap_first}/queryById", | |
59 | + add: "/${entityPackage}/${entityName?uncap_first}/add", | |
60 | + edit: "/${entityPackage}/${entityName?uncap_first}/edit", | |
61 | + }, | |
62 | + } | |
63 | + }, | |
64 | + created(){ | |
65 | + this.initFormData(); | |
66 | + }, | |
67 | + methods:{ | |
68 | + initFormData(){ | |
69 | + if(this.formData){ | |
70 | + let dataId = this.formData.dataId; | |
71 | + this.$http.get(this.url.queryById,{params:{id:dataId}}).then((res)=>{ | |
72 | + if(res.data.success){ | |
73 | + console.log("表单数据",res); | |
74 | + this.model = res.data.result; | |
75 | + } | |
76 | + }) | |
77 | + } | |
78 | + }, | |
79 | + onSubmit() { | |
80 | + let myForm = {...this.model}; | |
81 | + this.loading = true; | |
82 | + let url = myForm.id?this.url.edit:this.url.add; | |
83 | + this.$http.post(url,myForm).then(res=>{ | |
84 | + console.log("res",res) | |
85 | + this.loading = false | |
86 | + this.$Router.push({name:this.backRouteName}) | |
87 | + }).catch(()=>{ | |
88 | + this.loading = false | |
89 | + }); | |
90 | + } | |
91 | + } | |
92 | + } | |
93 | +</script> | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <view> | |
3 | + <!--标题和返回--> | |
4 | + <cu-custom :bgColor="NavBarColor" isBack> | |
5 | + <block slot="backText">返回</block> | |
6 | + <block slot="content">${tableVo.ftlDescription}</block> | |
7 | + </cu-custom> | |
8 | + <!--滚动加载列表--> | |
9 | + <mescroll-body ref="mescrollRef" bottom="88" @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback"> | |
10 | + <view class="cu-list menu"> | |
11 | + <view class="cu-item" v-for="(item,index) in list" :key="index" @click="goHome"> | |
12 | + <view class="flex" style="width:100%"> | |
13 | + <text class="text-lg" style="color: #000;"> | |
14 | + {{ item.createBy}} | |
15 | + </text> | |
16 | + </view> | |
17 | + </view> | |
18 | + </view> | |
19 | + </mescroll-body> | |
20 | + </view> | |
21 | +</template> | |
22 | + | |
23 | +<script> | |
24 | + import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js"; | |
25 | + import Mixin from "@/common/mixin/Mixin.js"; | |
26 | + | |
27 | + export default { | |
28 | + name: '${tableVo.ftlDescription}', | |
29 | + mixins: [MescrollMixin,Mixin], | |
30 | + data() { | |
31 | + return { | |
32 | + CustomBar:this.CustomBar, | |
33 | + NavBarColor:this.NavBarColor, | |
34 | + url: "/${entityPackage}/${entityName?uncap_first}/list", | |
35 | + }; | |
36 | + }, | |
37 | + methods: { | |
38 | + goHome(){ | |
39 | + this.$Router.push({name: "index"}) | |
40 | + } | |
41 | + } | |
42 | + } | |
43 | +</script> | |
44 | + | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <!--引用表格--> | |
4 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
5 | + <!--插槽:table标题--> | |
6 | + <template #tableTitle> | |
7 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
8 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
9 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
10 | + <a-dropdown v-if="checkedKeys.length > 0"> | |
11 | + <template #overlay> | |
12 | + <a-menu> | |
13 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
14 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
15 | + 删除 | |
16 | + </a-menu-item> | |
17 | + </a-menu> | |
18 | + </template> | |
19 | + <a-button>批量操作 | |
20 | + <Icon icon="mdi:chevron-down"></Icon> | |
21 | + </a-button> | |
22 | + </a-dropdown> | |
23 | + </template> | |
24 | + <!--操作栏--> | |
25 | + <template #action="{ record }"> | |
26 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
27 | + </template> | |
28 | + </BasicTable> | |
29 | + | |
30 | + <!-- 表单区域 --> | |
31 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
32 | + </div> | |
33 | +</template> | |
34 | + | |
35 | +<script lang="ts" setup> | |
36 | + import {ref, computed, unref} from 'vue'; | |
37 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
38 | + import {useModal} from '/@/components/Modal'; | |
39 | + import { useListPage } from '/@/hooks/system/useListPage' | |
40 | + import ${entityName}Modal from './modules/${entityName}Modal.vue' | |
41 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
42 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
43 | + | |
44 | + const checkedKeys = ref<Array<string | number>>([]); | |
45 | + //注册model | |
46 | + const [registerModal, {openModal}] = useModal(); | |
47 | + //注册table数据 | |
48 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
49 | + tableProps:{ | |
50 | + title: '${tableVo.ftlDescription}', | |
51 | + api: list, | |
52 | + columns, | |
53 | + canResize:false, | |
54 | + formConfig: { | |
55 | + labelWidth: 120, | |
56 | + schemas: searchFormSchema, | |
57 | + autoSubmitOnEnter:true, | |
58 | + showAdvancedButton:true, | |
59 | + }, | |
60 | + actionColumn: { | |
61 | + width: 120, | |
62 | + }, | |
63 | + }, | |
64 | + exportConfig: { | |
65 | + name:"${tableVo.ftlDescription}", | |
66 | + url: getExportUrl, | |
67 | + }, | |
68 | + importConfig: { | |
69 | + url: getImportUrl | |
70 | + }, | |
71 | + }) | |
72 | + | |
73 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
74 | + | |
75 | + /** | |
76 | + * 新增事件 | |
77 | + */ | |
78 | + function handleAdd() { | |
79 | + openModal(true, { | |
80 | + isUpdate: false, | |
81 | + showFooter: true, | |
82 | + }); | |
83 | + } | |
84 | + /** | |
85 | + * 编辑事件 | |
86 | + */ | |
87 | + function handleEdit(record: Recordable) { | |
88 | + openModal(true, { | |
89 | + record, | |
90 | + isUpdate: true, | |
91 | + showFooter: true, | |
92 | + }); | |
93 | + } | |
94 | + /** | |
95 | + * 详情 | |
96 | + */ | |
97 | + function handleDetail(record: Recordable) { | |
98 | + openModal(true, { | |
99 | + record, | |
100 | + isUpdate: true, | |
101 | + showFooter: false, | |
102 | + }); | |
103 | + } | |
104 | + /** | |
105 | + * 删除事件 | |
106 | + */ | |
107 | + async function handleDelete(record) { | |
108 | + await deleteOne({id: record.id}, reload); | |
109 | + } | |
110 | + /** | |
111 | + * 批量删除事件 | |
112 | + */ | |
113 | + async function batchHandleDelete() { | |
114 | + await batchDelete({ids: checkedKeys.value}, reload); | |
115 | + } | |
116 | + /** | |
117 | + * 成功回调 | |
118 | + */ | |
119 | + function handleSuccess({isUpdate, values}) { | |
120 | + reload(); | |
121 | + } | |
122 | + /** | |
123 | + * 操作栏 | |
124 | + */ | |
125 | + function getTableAction(record){ | |
126 | + return [ | |
127 | + { | |
128 | + label: '编辑', | |
129 | + onClick: handleEdit.bind(null, record), | |
130 | + } | |
131 | + ] | |
132 | + } | |
133 | + /** | |
134 | + * 下拉操作栏 | |
135 | + */ | |
136 | + function getDropDownAction(record){ | |
137 | + return [ | |
138 | + { | |
139 | + label: '详情', | |
140 | + onClick: handleDetail.bind(null, record), | |
141 | + }, { | |
142 | + label: '删除', | |
143 | + popConfirm: { | |
144 | + title: '是否确认删除', | |
145 | + confirm: handleDelete.bind(null, record), | |
146 | + } | |
147 | + } | |
148 | + ] | |
149 | + } | |
150 | +</script> | |
151 | +<style scoped> | |
152 | + | |
153 | +</style> | |
0 | 154 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +} | |
13 | +/** | |
14 | + * 导出api | |
15 | + * @param params | |
16 | + */ | |
17 | +export const getExportUrl = Api.exportXls; | |
18 | +/** | |
19 | + * 导入api | |
20 | + */ | |
21 | +export const getImportUrl = Api.importExcel; | |
22 | +/** | |
23 | + * 列表接口 | |
24 | + * @param params | |
25 | + */ | |
26 | +export const list = (params) => | |
27 | + defHttp.get({url: Api.list, params}); | |
28 | + | |
29 | +/** | |
30 | + * 删除单个 | |
31 | + */ | |
32 | +export const deleteOne = (params,handleSuccess) => { | |
33 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
34 | + handleSuccess(); | |
35 | + }); | |
36 | +} | |
37 | +/** | |
38 | + * 批量删除 | |
39 | + * @param params | |
40 | + */ | |
41 | +export const batchDelete = (params, handleSuccess) => { | |
42 | + Modal.confirm({ | |
43 | + title: '确认删除', | |
44 | + content: '是否删除选中数据', | |
45 | + okText: '确认', | |
46 | + cancelText: '取消', | |
47 | + onOk: () => { | |
48 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
49 | + handleSuccess(); | |
50 | + }); | |
51 | + } | |
52 | + }); | |
53 | +} | |
54 | +/** | |
55 | + * 保存或者更新 | |
56 | + * @param params | |
57 | + */ | |
58 | +export const saveOrUpdate = (params, isUpdate) => { | |
59 | + let url = isUpdate ? Api.edit : Api.save; | |
60 | + return defHttp.post({url: url, params}); | |
61 | +} | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | + | |
6 | +export const columns: BasicColumn[] = [ | |
7 | + <#list columns as po> | |
8 | + <#if po.fieldName !='id'> | |
9 | + { | |
10 | + title: '${po.filedComment}', | |
11 | + dataIndex: '${po.fieldName}' | |
12 | + }, | |
13 | + </#if> | |
14 | + </#list> | |
15 | +]; | |
16 | + | |
17 | +export const searchFormSchema: FormSchema[] = [ | |
18 | +<#list columns as po> | |
19 | +<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum> | |
20 | + { | |
21 | + label: '${po.filedComment}', | |
22 | + field: '${po.fieldName}', | |
23 | + <#if po.fieldType =='date'> | |
24 | + component: 'DatePicker' | |
25 | + <#elseif po.fieldType =='datetime'> | |
26 | + component: 'TimePicker' | |
27 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
28 | + component: 'InputNumber' | |
29 | + <#else> | |
30 | + component: 'Input' | |
31 | + </#if> | |
32 | + }, | |
33 | +</#if> | |
34 | +</#list> | |
35 | +]; | |
36 | + | |
37 | +export const formSchema: FormSchema[] = [ | |
38 | +<#list columns as po><#rt/> | |
39 | + { | |
40 | + label: '${po.filedComment}', | |
41 | + field: '${po.fieldName}', | |
42 | + <#if po.fieldType =='date'> | |
43 | + component: 'DatePicker' | |
44 | + <#elseif po.fieldType =='datetime'> | |
45 | + component: 'TimePicker' | |
46 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
47 | + component: 'InputNumber' | |
48 | + <#else> | |
49 | + component: 'Input' | |
50 | + </#if> | |
51 | + <#if po.fieldName =='id'><#rt/> | |
52 | + show:false | |
53 | + </#if> | |
54 | + }, | |
55 | +</#list> | |
56 | +]; | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%"> | |
3 | + <BasicForm @register="registerForm"/> | |
4 | + </BasicModal> | |
5 | +</template> | |
6 | + | |
7 | +<script lang="ts" setup> | |
8 | + import {ref, computed, unref} from 'vue'; | |
9 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
10 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
11 | + import {formSchema} from '../${entityName?uncap_first}.data'; | |
12 | + import {saveOrUpdate} from '../${entityName?uncap_first}.api'; | |
13 | + // Emits声明 | |
14 | + const emit = defineEmits(['register','success']); | |
15 | + const isUpdate = ref(true); | |
16 | + //表单配置 | |
17 | + const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({ | |
18 | + labelWidth: 150, | |
19 | + schemas: formSchema, | |
20 | + showActionButtonGroup: false, | |
21 | + }); | |
22 | + //表单赋值 | |
23 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
24 | + //重置表单 | |
25 | + await resetFields(); | |
26 | + setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter}); | |
27 | + isUpdate.value = !!data?.isUpdate; | |
28 | + if (unref(isUpdate)) { | |
29 | + //表单赋值 | |
30 | + await setFieldsValue({ | |
31 | + ...data.record, | |
32 | + }); | |
33 | + } | |
34 | + }); | |
35 | + //设置标题 | |
36 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
37 | + //表单提交事件 | |
38 | + async function handleSubmit(v) { | |
39 | + try { | |
40 | + let values = await validate(); | |
41 | + setModalProps({confirmLoading: true}); | |
42 | + //提交表单 | |
43 | + await saveOrUpdate(values, isUpdate.value); | |
44 | + //关闭弹窗 | |
45 | + closeModal(); | |
46 | + //刷新列表 | |
47 | + emit('success'); | |
48 | + } finally { | |
49 | + setModalProps({confirmLoading: false}); | |
50 | + } | |
51 | + } | |
52 | +</script> | |
53 | + | |
54 | +<style lang="less" scoped> | |
55 | + | |
56 | +</style> | |
0 | 57 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/controller/${entityPackage}/${entityName}Controller.javai renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/controller/${entityPackage}/${entityName}Controller.javai
... | ... | @@ -97,7 +97,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e |
97 | 97 | */ |
98 | 98 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
99 | 99 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
100 | - @PutMapping(value = "/edit") | |
100 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
101 | 101 | public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) { |
102 | 102 | ${entityName?uncap_first}Service.updateById(${entityName?uncap_first}); |
103 | 103 | return Result.OK("编辑成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/entity/${entityPackage}/${entityName}.javai renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/entity/${entityPackage}/${entityName}.javai
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/${entityName}Mapper.javai renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/${entityName}Mapper.javai
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/I${entityName}Service.javai renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/I${entityName}Service.javai
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/${entityName}List.vuei renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/${entityName}List.vuei
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei renamed to jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <!--引用表格--> | |
4 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
5 | + <!--插槽:table标题--> | |
6 | + <template #tableTitle> | |
7 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
8 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
9 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
10 | + <a-dropdown v-if="checkedKeys.length > 0"> | |
11 | + <template #overlay> | |
12 | + <a-menu> | |
13 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
14 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
15 | + 删除 | |
16 | + </a-menu-item> | |
17 | + </a-menu> | |
18 | + </template> | |
19 | + <a-button>批量操作 | |
20 | + <Icon icon="mdi:chevron-down"></Icon> | |
21 | + </a-button> | |
22 | + </a-dropdown> | |
23 | + </template> | |
24 | + <!--操作栏--> | |
25 | + <template #action="{ record }"> | |
26 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
27 | + </template> | |
28 | + </BasicTable> | |
29 | + | |
30 | + <!-- 表单区域 --> | |
31 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
32 | + </div> | |
33 | +</template> | |
34 | + | |
35 | +<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup> | |
36 | + import {ref, computed, unref} from 'vue'; | |
37 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
38 | + import {useModal} from '/@/components/Modal'; | |
39 | + import { useListPage } from '/@/hooks/system/useListPage' | |
40 | + import ${entityName}Modal from './modules/${entityName}Modal.vue' | |
41 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
42 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
43 | + | |
44 | + const checkedKeys = ref<Array<string | number>>([]); | |
45 | + //注册model | |
46 | + const [registerModal, {openModal}] = useModal(); | |
47 | + //注册table数据 | |
48 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
49 | + tableProps:{ | |
50 | + title: '${tableVo.ftlDescription}', | |
51 | + api: list, | |
52 | + columns, | |
53 | + canResize:false, | |
54 | + formConfig: { | |
55 | + labelWidth: 120, | |
56 | + schemas: searchFormSchema, | |
57 | + autoSubmitOnEnter:true, | |
58 | + showAdvancedButton:true, | |
59 | + }, | |
60 | + actionColumn: { | |
61 | + width: 120, | |
62 | + }, | |
63 | + }, | |
64 | + exportConfig: { | |
65 | + name:"${tableVo.ftlDescription}", | |
66 | + url: getExportUrl, | |
67 | + }, | |
68 | + importConfig: { | |
69 | + url: getImportUrl | |
70 | + }, | |
71 | + }) | |
72 | + | |
73 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
74 | + | |
75 | + /** | |
76 | + * 新增事件 | |
77 | + */ | |
78 | + function handleAdd() { | |
79 | + openModal(true, { | |
80 | + isUpdate: false, | |
81 | + showFooter: true, | |
82 | + }); | |
83 | + } | |
84 | + /** | |
85 | + * 编辑事件 | |
86 | + */ | |
87 | + function handleEdit(record: Recordable) { | |
88 | + openModal(true, { | |
89 | + record, | |
90 | + isUpdate: true, | |
91 | + showFooter: true, | |
92 | + }); | |
93 | + } | |
94 | + /** | |
95 | + * 详情 | |
96 | + */ | |
97 | + function handleDetail(record: Recordable) { | |
98 | + openModal(true, { | |
99 | + record, | |
100 | + isUpdate: true, | |
101 | + showFooter: false, | |
102 | + }); | |
103 | + } | |
104 | + /** | |
105 | + * 删除事件 | |
106 | + */ | |
107 | + async function handleDelete(record) { | |
108 | + await deleteOne({id: record.id}, reload); | |
109 | + } | |
110 | + /** | |
111 | + * 批量删除事件 | |
112 | + */ | |
113 | + async function batchHandleDelete() { | |
114 | + await batchDelete({ids: checkedKeys.value}, reload); | |
115 | + } | |
116 | + /** | |
117 | + * 成功回调 | |
118 | + */ | |
119 | + function handleSuccess({isUpdate, values}) { | |
120 | + reload(); | |
121 | + } | |
122 | + /** | |
123 | + * 操作栏 | |
124 | + */ | |
125 | + function getTableAction(record){ | |
126 | + return [ | |
127 | + { | |
128 | + label: '编辑', | |
129 | + onClick: handleEdit.bind(null, record), | |
130 | + } | |
131 | + ] | |
132 | + } | |
133 | + /** | |
134 | + * 下拉操作栏 | |
135 | + */ | |
136 | + function getDropDownAction(record){ | |
137 | + return [ | |
138 | + { | |
139 | + label: '详情', | |
140 | + onClick: handleDetail.bind(null, record), | |
141 | + }, { | |
142 | + label: '删除', | |
143 | + popConfirm: { | |
144 | + title: '是否确认删除', | |
145 | + confirm: handleDelete.bind(null, record), | |
146 | + } | |
147 | + } | |
148 | + ] | |
149 | + } | |
150 | +</script> | |
151 | +<style scoped> | |
152 | + | |
153 | +</style> | |
0 | 154 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +} | |
13 | +/** | |
14 | + * 导出api | |
15 | + * @param params | |
16 | + */ | |
17 | +export const getExportUrl = Api.exportXls; | |
18 | +/** | |
19 | + * 导入api | |
20 | + */ | |
21 | +export const getImportUrl = Api.importExcel; | |
22 | +/** | |
23 | + * 列表接口 | |
24 | + * @param params | |
25 | + */ | |
26 | +export const list = (params) => | |
27 | + defHttp.get({url: Api.list, params}); | |
28 | + | |
29 | +/** | |
30 | + * 删除单个 | |
31 | + */ | |
32 | +export const deleteOne = (params,handleSuccess) => { | |
33 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
34 | + handleSuccess(); | |
35 | + }); | |
36 | +} | |
37 | +/** | |
38 | + * 批量删除 | |
39 | + * @param params | |
40 | + */ | |
41 | +export const batchDelete = (params, handleSuccess) => { | |
42 | + Modal.confirm({ | |
43 | + title: '确认删除', | |
44 | + content: '是否删除选中数据', | |
45 | + okText: '确认', | |
46 | + cancelText: '取消', | |
47 | + onOk: () => { | |
48 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
49 | + handleSuccess(); | |
50 | + }); | |
51 | + } | |
52 | + }); | |
53 | +} | |
54 | +/** | |
55 | + * 保存或者更新 | |
56 | + * @param params | |
57 | + */ | |
58 | +export const saveOrUpdate = (params, isUpdate) => { | |
59 | + let url = isUpdate ? Api.edit : Api.save; | |
60 | + return defHttp.post({url: url, params}); | |
61 | +} | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | + | |
6 | +export const columns: BasicColumn[] = [ | |
7 | + <#list columns as po> | |
8 | + <#if po.fieldName !='id'> | |
9 | + { | |
10 | + title: '${po.filedComment}', | |
11 | + dataIndex: '${po.fieldName}' | |
12 | + }, | |
13 | + </#if> | |
14 | + </#list> | |
15 | +]; | |
16 | + | |
17 | +export const searchFormSchema: FormSchema[] = [ | |
18 | +<#list columns as po> | |
19 | +<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum> | |
20 | + { | |
21 | + label: '${po.filedComment}', | |
22 | + field: '${po.fieldName}', | |
23 | + <#if po.fieldType =='date'> | |
24 | + component: 'DatePicker' | |
25 | + <#elseif po.fieldType =='datetime'> | |
26 | + component: 'TimePicker' | |
27 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
28 | + component: 'InputNumber' | |
29 | + <#else> | |
30 | + component: 'Input' | |
31 | + </#if> | |
32 | + }, | |
33 | +</#if> | |
34 | +</#list> | |
35 | +]; | |
36 | + | |
37 | +export const formSchema: FormSchema[] = [ | |
38 | +<#list columns as po><#rt/> | |
39 | + { | |
40 | + label: '${po.filedComment}', | |
41 | + field: '${po.fieldName}', | |
42 | + <#if po.fieldType =='date'> | |
43 | + component: 'DatePicker' | |
44 | + <#elseif po.fieldType =='datetime'> | |
45 | + component: 'TimePicker' | |
46 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
47 | + component: 'InputNumber' | |
48 | + <#else> | |
49 | + component: 'Input' | |
50 | + </#if> | |
51 | + <#if po.fieldName =='id'><#rt/> | |
52 | + show:false | |
53 | + </#if> | |
54 | + }, | |
55 | +</#list> | |
56 | +]; | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%"> | |
3 | + <BasicForm @register="registerForm"/> | |
4 | + </BasicModal> | |
5 | +</template> | |
6 | + | |
7 | +<script lang="ts" setup> | |
8 | + import {ref, computed, unref} from 'vue'; | |
9 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
10 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
11 | + import {formSchema} from '../${entityName?uncap_first}.data'; | |
12 | + import {saveOrUpdate} from '../${entityName?uncap_first}.api'; | |
13 | + // Emits声明 | |
14 | + const emit = defineEmits(['register','success']); | |
15 | + const isUpdate = ref(true); | |
16 | + //表单配置 | |
17 | + const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({ | |
18 | + labelWidth: 150, | |
19 | + schemas: formSchema, | |
20 | + showActionButtonGroup: false, | |
21 | + }); | |
22 | + //表单赋值 | |
23 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
24 | + //重置表单 | |
25 | + await resetFields(); | |
26 | + setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter}); | |
27 | + isUpdate.value = !!data?.isUpdate; | |
28 | + if (unref(isUpdate)) { | |
29 | + //表单赋值 | |
30 | + await setFieldsValue({ | |
31 | + ...data.record, | |
32 | + }); | |
33 | + } | |
34 | + }); | |
35 | + //设置标题 | |
36 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
37 | + //表单提交事件 | |
38 | + async function handleSubmit(v) { | |
39 | + try { | |
40 | + let values = await validate(); | |
41 | + setModalProps({confirmLoading: true}); | |
42 | + //提交表单 | |
43 | + await saveOrUpdate(values, isUpdate.value); | |
44 | + //关闭弹窗 | |
45 | + closeModal(); | |
46 | + //刷新列表 | |
47 | + emit('success'); | |
48 | + } finally { | |
49 | + setModalProps({confirmLoading: false}); | |
50 | + } | |
51 | + } | |
52 | +</script> | |
53 | + | |
54 | +<style lang="less" scoped> | |
55 | + | |
56 | +</style> | |
0 | 57 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -109,7 +109,7 @@ public class ${entityName}Controller { |
109 | 109 | */ |
110 | 110 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
111 | 111 | @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") |
112 | - @PutMapping(value = "/edit") | |
112 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
113 | 113 | public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) { |
114 | 114 | ${entityName} ${entityName?uncap_first} = new ${entityName}(); |
115 | 115 | BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first}); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <!--引用表格--> | |
4 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
5 | + <!--插槽:table标题--> | |
6 | + <template #tableTitle> | |
7 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
8 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
9 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
10 | + <a-dropdown v-if="checkedKeys.length > 0"> | |
11 | + <template #overlay> | |
12 | + <a-menu> | |
13 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
14 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
15 | + 删除 | |
16 | + </a-menu-item> | |
17 | + </a-menu> | |
18 | + </template> | |
19 | + <a-button>批量操作 | |
20 | + <Icon icon="mdi:chevron-down"></Icon> | |
21 | + </a-button> | |
22 | + </a-dropdown> | |
23 | + </template> | |
24 | + <!--操作栏--> | |
25 | + <template #action="{ record }"> | |
26 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
27 | + </template> | |
28 | + </BasicTable> | |
29 | + <!-- 表单区域 --> | |
30 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
31 | + </div> | |
32 | +</template> | |
33 | + | |
34 | +<script lang="ts" setup> | |
35 | + import {ref, computed, unref} from 'vue'; | |
36 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
37 | + import { useListPage } from '/@/hooks/system/useListPage' | |
38 | + import {useModal} from '/@/components/Modal'; | |
39 | + import ${entityName}Modal from './modules/${entityName}Modal.vue' | |
40 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
41 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
42 | + const checkedKeys = ref<Array<string | number>>([]); | |
43 | + //注册model | |
44 | + const [registerModal, {openModal}] = useModal(); | |
45 | + //注册table数据 | |
46 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
47 | + tableProps:{ | |
48 | + title: '${tableVo.ftlDescription}', | |
49 | + api: list, | |
50 | + columns, | |
51 | + canResize:false, | |
52 | + formConfig: { | |
53 | + labelWidth: 120, | |
54 | + schemas: searchFormSchema, | |
55 | + autoSubmitOnEnter:true, | |
56 | + showAdvancedButton:true, | |
57 | + }, | |
58 | + actionColumn: { | |
59 | + width: 120, | |
60 | + }, | |
61 | + }, | |
62 | + exportConfig: { | |
63 | + name:"${tableVo.ftlDescription}", | |
64 | + url: getExportUrl, | |
65 | + }, | |
66 | + importConfig: { | |
67 | + url: getImportUrl | |
68 | + }, | |
69 | + }) | |
70 | + | |
71 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
72 | + | |
73 | + /** | |
74 | + * 新增事件 | |
75 | + */ | |
76 | + function handleAdd() { | |
77 | + openModal(true, { | |
78 | + isUpdate: false, | |
79 | + showFooter: true, | |
80 | + }); | |
81 | + } | |
82 | + /** | |
83 | + * 编辑事件 | |
84 | + */ | |
85 | + function handleEdit(record: Recordable) { | |
86 | + openModal(true, { | |
87 | + record, | |
88 | + isUpdate: true, | |
89 | + showFooter: true, | |
90 | + }); | |
91 | + } | |
92 | + /** | |
93 | + * 详情 | |
94 | + */ | |
95 | + function handleDetail(record: Recordable) { | |
96 | + openModal(true, { | |
97 | + record, | |
98 | + isUpdate: true, | |
99 | + showFooter: false, | |
100 | + }); | |
101 | + } | |
102 | + /** | |
103 | + * 删除事件 | |
104 | + */ | |
105 | + async function handleDelete(record) { | |
106 | + await deleteOne({id: record.id}, reload); | |
107 | + } | |
108 | + /** | |
109 | + * 批量删除事件 | |
110 | + */ | |
111 | + async function batchHandleDelete() { | |
112 | + await batchDelete({ids: checkedKeys.value}, reload); | |
113 | + } | |
114 | + /** | |
115 | + * 成功回调 | |
116 | + */ | |
117 | + function handleSuccess() { | |
118 | + reload(); | |
119 | + } | |
120 | + /** | |
121 | + * 操作栏 | |
122 | + */ | |
123 | + function getTableAction(record){ | |
124 | + return [ | |
125 | + { | |
126 | + label: '编辑', | |
127 | + onClick: handleEdit.bind(null, record), | |
128 | + } | |
129 | + ] | |
130 | + } | |
131 | + /** | |
132 | + * 下拉操作栏 | |
133 | + */ | |
134 | + function getDropDownAction(record){ | |
135 | + return [ | |
136 | + { | |
137 | + label: '详情', | |
138 | + onClick: handleDetail.bind(null, record), | |
139 | + }, { | |
140 | + label: '删除', | |
141 | + popConfirm: { | |
142 | + title: '是否确认删除', | |
143 | + confirm: handleDelete.bind(null, record), | |
144 | + } | |
145 | + } | |
146 | + ] | |
147 | + } | |
148 | +</script> | |
149 | + | |
150 | +<style scoped> | |
151 | + | |
152 | +</style> | |
0 | 153 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +<#list subTables as sub><#rt/> | |
13 | + ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId', | |
14 | +</#list> | |
15 | +} | |
16 | +/** | |
17 | + * 导出api | |
18 | + * @param params | |
19 | + */ | |
20 | +export const getExportUrl = Api.exportXls; | |
21 | + | |
22 | +/** | |
23 | + * 导入api | |
24 | + */ | |
25 | +export const getImportUrl = Api.importExcel; | |
26 | +<#list subTables as sub><#rt/> | |
27 | +/** | |
28 | + * 查询子表数据 | |
29 | + * @param params | |
30 | + */ | |
31 | +export const ${sub.entityName?uncap_first}List = Api.${sub.entityName?uncap_first}List; | |
32 | +</#list> | |
33 | +/** | |
34 | + * 列表接口 | |
35 | + * @param params | |
36 | + */ | |
37 | +export const list = (params) => | |
38 | + defHttp.get({url: Api.list, params}); | |
39 | + | |
40 | +/** | |
41 | + * 删除单个 | |
42 | + */ | |
43 | +export const deleteOne = (params,handleSuccess) => { | |
44 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
45 | + handleSuccess(); | |
46 | + }); | |
47 | +} | |
48 | +/** | |
49 | + * 批量删除 | |
50 | + * @param params | |
51 | + */ | |
52 | +export const batchDelete = (params, handleSuccess) => { | |
53 | + Modal.confirm({ | |
54 | + title: '确认删除', | |
55 | + content: '是否删除选中数据', | |
56 | + okText: '确认', | |
57 | + cancelText: '取消', | |
58 | + onOk: () => { | |
59 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
60 | + handleSuccess(); | |
61 | + }); | |
62 | + } | |
63 | + }); | |
64 | +} | |
65 | +/** | |
66 | + * 保存或者更新 | |
67 | + * @param params | |
68 | + */ | |
69 | +export const saveOrUpdate = (params, isUpdate) => { | |
70 | + let url = isUpdate ? Api.edit : Api.save; | |
71 | + return defHttp.post({url: url, params}); | |
72 | +} | |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types' | |
6 | +//列表数据 | |
7 | +export const columns: BasicColumn[] = [ | |
8 | + <#list columns as po> | |
9 | + <#if po.fieldName !='id'> | |
10 | + { | |
11 | + title: '${po.filedComment}', | |
12 | + align:"center", | |
13 | + <#if po.classType=='date'> | |
14 | + dataIndex: '${po.fieldName}', | |
15 | + customRender:({text}) =>{ | |
16 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
17 | + }, | |
18 | + <#else> | |
19 | + dataIndex: '${po.fieldName}' | |
20 | + </#if> | |
21 | + }, | |
22 | + </#if> | |
23 | + </#list> | |
24 | +]; | |
25 | +//查询数据 | |
26 | +export const searchFormSchema: FormSchema[] = [ | |
27 | +<#list columns as po> | |
28 | +<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum> | |
29 | + { | |
30 | + label: '${po.filedComment}', | |
31 | + field: '${po.fieldName}', | |
32 | + <#if po.fieldType =='date'> | |
33 | + component: 'DatePicker' | |
34 | + <#elseif po.fieldType =='datetime'> | |
35 | + component: 'TimePicker' | |
36 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
37 | + component: 'InputNumber' | |
38 | + <#else> | |
39 | + component: 'Input' | |
40 | + </#if> | |
41 | + }, | |
42 | +</#if> | |
43 | +</#list> | |
44 | +]; | |
45 | +export const formSchema: FormSchema[] = [ | |
46 | +<#list columns as po><#rt/> | |
47 | + { | |
48 | + label: '${po.filedComment}', | |
49 | + field: '${po.fieldName}', | |
50 | + <#if po.fieldType =='date'> | |
51 | + component: 'DatePicker' | |
52 | + <#elseif po.fieldType =='datetime'> | |
53 | + component: 'TimePicker' | |
54 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
55 | + component: 'InputNumber' | |
56 | + <#else> | |
57 | + component: 'Input' | |
58 | + </#if> | |
59 | + <#if po.fieldName =='id'><#rt/> | |
60 | + show:false | |
61 | + </#if> | |
62 | + }, | |
63 | +</#list> | |
64 | +]; | |
65 | +//子表表格配置 | |
66 | +<#list subTables as sub> | |
67 | +export const ${sub.entityName?uncap_first}Columns: JVxeColumn[] = [ | |
68 | +<#-- 循环子表的列 开始 --> | |
69 | +<#list sub.colums as col><#rt/> | |
70 | +<#if col.filedComment !='外键' > | |
71 | + { | |
72 | + title: '${col.filedComment}', | |
73 | + key: '${col.fieldName}', | |
74 | +<#if col.classType =='date'> | |
75 | + type: JVxeTypes.date, | |
76 | +<#elseif col.classType =='datetime'> | |
77 | + type: JVxeTypes.datetime, | |
78 | +<#elseif "int,decimal,double,"?contains(col.classType)> | |
79 | + type: JVxeTypes.inputNumber, | |
80 | +<#else> | |
81 | + type: JVxeTypes.input, | |
82 | +</#if> | |
83 | + width:"200px", | |
84 | + placeholder: '请输入${'$'}{title}', | |
85 | + defaultValue: '', | |
86 | +<#-- 子表的校验 --> | |
87 | +<#if col.nullable =='N'> | |
88 | + validateRules: [{ required: true, message: '${'$'}{title}不能为空' }], | |
89 | +</#if> | |
90 | + }, | |
91 | +</#if> | |
92 | +</#list> | |
93 | +<#-- 循环子表的列 结束 --> | |
94 | + ] | |
95 | +</#list> | |
0 | 96 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="1000px"> | |
3 | + <BasicForm @register="registerForm" ref="formRef"/> | |
4 | + <!-- 子表单区域 --> | |
5 | + <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs"> | |
6 | +<#list subTables as sub><#rt/> | |
7 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true"> | |
8 | + <JVxeTable | |
9 | + keep-source | |
10 | + resizable | |
11 | + :ref="refKeys[${sub_index}]" | |
12 | + :loading="${sub.entityName?uncap_first}Table.loading" | |
13 | + :columns="${sub.entityName?uncap_first}Table.columns" | |
14 | + :dataSource="${sub.entityName?uncap_first}Table.dataSource" | |
15 | + :maxHeight="300" | |
16 | + :rowNumber="true" | |
17 | + :rowSelection="true" | |
18 | + :toolbar="true" | |
19 | + /> | |
20 | + </a-tab-pane> | |
21 | +</#list> | |
22 | + </a-tabs> | |
23 | + </BasicModal> | |
24 | +</template> | |
25 | + | |
26 | +<script lang="ts" setup> | |
27 | + import {ref, computed, unref,reactive} from 'vue'; | |
28 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
29 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
30 | + import { JVxeTable } from '/@/components/jeecg/JVxeTable' | |
31 | + import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts' | |
32 | + import {formSchema<#list subTables as sub>,${sub.entityName?uncap_first}Columns</#list>} from '../${entityName?uncap_first}.data'; | |
33 | + import {saveOrUpdate<#list subTables as sub>,${sub.entityName?uncap_first}List</#list>} from '../${entityName?uncap_first}.api'; | |
34 | + import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils' | |
35 | + // Emits声明 | |
36 | + const emit = defineEmits(['register','success']); | |
37 | + const isUpdate = ref(true); | |
38 | + const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]); | |
39 | + <#assign hasOne2Many = false> | |
40 | + const activeKey = ref('${subTables[0].entityName?uncap_first}'); | |
41 | +<#list subTables as sub> | |
42 | + const ${sub.entityName?uncap_first} = ref(); | |
43 | +</#list> | |
44 | + const tableRefs = {<#list subTables as sub>${sub.entityName?uncap_first},</#list>}; | |
45 | + <#list subTables as sub> | |
46 | + const ${sub.entityName?uncap_first}Table = reactive({ | |
47 | + loading: false, | |
48 | + dataSource: [], | |
49 | + columns:${sub.entityName?uncap_first}Columns | |
50 | + }) | |
51 | + </#list> | |
52 | + //表单配置 | |
53 | + const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({ | |
54 | + labelWidth: 150, | |
55 | + schemas: formSchema, | |
56 | + showActionButtonGroup: false, | |
57 | + }); | |
58 | + //表单赋值 | |
59 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
60 | + //重置表单 | |
61 | + await reset(); | |
62 | + setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter}); | |
63 | + isUpdate.value = !!data?.isUpdate; | |
64 | + if (unref(isUpdate)) { | |
65 | + //表单赋值 | |
66 | + await setFieldsValue({ | |
67 | + ...data.record, | |
68 | + }); | |
69 | + <#list subTables as sub><#rt/> | |
70 | + requestSubTableData(${sub.entityName?uncap_first}List, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table) | |
71 | + </#list> | |
72 | + } | |
73 | + // 隐藏底部时禁用整个表单 | |
74 | + setProps({ disabled: !data?.showFooter }) | |
75 | + }); | |
76 | + //方法配置 | |
77 | + const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys); | |
78 | + | |
79 | + //设置标题 | |
80 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
81 | + | |
82 | + async function reset(){ | |
83 | + await resetFields(); | |
84 | + activeKey.value = ref('${subTables[0].entityName?uncap_first}'); | |
85 | + <#list subTables as sub> | |
86 | + ${sub.entityName?uncap_first}Table.dataSource = []; | |
87 | + </#list> | |
88 | + } | |
89 | + function classifyIntoFormData(allValues) { | |
90 | + let main = Object.assign({}, allValues.formValue) | |
91 | + return { | |
92 | + ...main, // 展开 | |
93 | + <#assign subManyIndex = 0> | |
94 | + <#list subTables as sub><#rt/> | |
95 | + ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData, | |
96 | + <#assign subManyIndex = subManyIndex+1> | |
97 | + </#list> | |
98 | + } | |
99 | + } | |
100 | + | |
101 | + //表单提交事件 | |
102 | + async function requestAddOrEdit(values) { | |
103 | + try { | |
104 | + setModalProps({confirmLoading: true}); | |
105 | + //提交表单 | |
106 | + await saveOrUpdate(values, isUpdate.value); | |
107 | + //关闭弹窗 | |
108 | + closeModal(); | |
109 | + //刷新列表 | |
110 | + emit('success'); | |
111 | + } finally { | |
112 | + setModalProps({confirmLoading: false}); | |
113 | + } | |
114 | + } | |
115 | +</script> | |
116 | + | |
117 | +<style lang="less" scoped> | |
118 | + | |
119 | +</style> | |
0 | 120 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
... | ... | @@ -108,7 +108,7 @@ public class ${entityName}Controller { |
108 | 108 | */ |
109 | 109 | @AutoLog(value = "${tableVo.ftlDescription}-编辑") |
110 | 110 | @ApiOperation(value="${tableVo.ftlDescription}-", notes="${tableVo.ftlDescription}-编辑") |
111 | - @PutMapping(value = "/edit") | |
111 | + @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) | |
112 | 112 | public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) { |
113 | 113 | ${entityName} ${entityName?uncap_first} = new ${entityName}(); |
114 | 114 | BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first}); |
... | ... | @@ -223,7 +223,7 @@ ${sub.entityName?uncap_first}.get${key}()!=null<#rt/> |
223 | 223 | */ |
224 | 224 | @AutoLog(value = "${sub.ftlDescription}-编辑") |
225 | 225 | @ApiOperation(value="${sub.ftlDescription}-编辑", notes="${sub.ftlDescription}-编辑") |
226 | - @PutMapping("/edit${sub.entityName}") | |
226 | + @RequestMapping(value = "/edit${sub.entityName}", method = {RequestMethod.PUT,RequestMethod.POST}) | |
227 | 227 | public Result<?> edit${sub.entityName}(@RequestBody ${sub.entityName} ${sub.entityName?uncap_first}) { |
228 | 228 | ${sub.entityName?uncap_first}Service.updateById(${sub.entityName?uncap_first}); |
229 | 229 | return Result.OK("编辑${sub.ftlDescription}成功!"); |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
0 → 100644
1 | +<template> | |
2 | + <div> | |
3 | + <!--引用表格--> | |
4 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
5 | + <!--插槽:table标题--> | |
6 | + <template #tableTitle> | |
7 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
8 | + <a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button> | |
9 | + <j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button> | |
10 | + <a-dropdown v-if="checkedKeys.length > 0"> | |
11 | + <template #overlay> | |
12 | + <a-menu> | |
13 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
14 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
15 | + 删除 | |
16 | + </a-menu-item> | |
17 | + </a-menu> | |
18 | + </template> | |
19 | + <a-button>批量操作 | |
20 | + <Icon icon="mdi:chevron-down"></Icon> | |
21 | + </a-button> | |
22 | + </a-dropdown> | |
23 | + </template> | |
24 | + <!--操作栏--> | |
25 | + <template #action="{ record }"> | |
26 | + <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/> | |
27 | + </template> | |
28 | + </BasicTable> | |
29 | + <a-tabs :defaultActiveKey="refKeys[0]" style="margin: 10px"> | |
30 | + <#list subTables as sub><#rt/> | |
31 | + <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true"> | |
32 | + <${sub.entityName}List></${sub.entityName}List> | |
33 | + </a-tab-pane> | |
34 | + </#list> | |
35 | + </a-tabs> | |
36 | + | |
37 | + <!-- 表单区域 --> | |
38 | + <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal> | |
39 | + </div> | |
40 | +</template> | |
41 | + | |
42 | +<script lang="ts" setup> | |
43 | + import {ref, computed, unref,provide} from 'vue'; | |
44 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
45 | +<#list subTables as sub><#rt/> | |
46 | + import ${sub.entityName}List from './${sub.entityName}List.vue' | |
47 | +</#list> | |
48 | + import { useListPage } from '/@/hooks/system/useListPage' | |
49 | + import {useModal} from '/@/components/Modal'; | |
50 | + import ${entityName}Modal from './modules/${entityName}Modal.vue' | |
51 | + import {columns, searchFormSchema} from './${entityName?uncap_first}.data'; | |
52 | + import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api'; | |
53 | + | |
54 | + const checkedKeys = ref<Array<string | number>>([]); | |
55 | + const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]); | |
56 | + //注册model | |
57 | + const [registerModal, {openModal}] = useModal(); | |
58 | + //注册table数据 | |
59 | + const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({ | |
60 | + tableProps:{ | |
61 | + title: '${tableVo.ftlDescription}', | |
62 | + api: list, | |
63 | + columns, | |
64 | + canResize: false, | |
65 | + rowSelection: {type: 'radio'}, | |
66 | + formConfig: { | |
67 | + labelWidth: 120, | |
68 | + schemas: searchFormSchema, | |
69 | + autoSubmitOnEnter:true, | |
70 | + showAdvancedButton:true, | |
71 | + }, | |
72 | + actionColumn: { | |
73 | + width: 120, | |
74 | + }, | |
75 | + }, | |
76 | + exportConfig: { | |
77 | + name:"${tableVo.ftlDescription}", | |
78 | + url: getExportUrl, | |
79 | + }, | |
80 | + importConfig: { | |
81 | + url: getImportUrl | |
82 | + }, | |
83 | + }) | |
84 | + | |
85 | + const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext | |
86 | + | |
87 | + const mainId = computed(() => (unref(selectedRowKeys).length > 0 ? unref(selectedRowKeys)[0] : '')); | |
88 | + | |
89 | + //下发 orderId,子组件接收 | |
90 | + provide('mainId', mainId); | |
91 | + | |
92 | + /** | |
93 | + * 新增事件 | |
94 | + */ | |
95 | + function handleAdd() { | |
96 | + openModal(true, { | |
97 | + isUpdate: false, | |
98 | + showFooter: true, | |
99 | + }); | |
100 | + } | |
101 | + /** | |
102 | + * 编辑事件 | |
103 | + */ | |
104 | + function handleEdit(record: Recordable) { | |
105 | + openModal(true, { | |
106 | + record, | |
107 | + isUpdate: true, | |
108 | + showFooter: true, | |
109 | + }); | |
110 | + } | |
111 | + /** | |
112 | + * 详情 | |
113 | + */ | |
114 | + function handleDetail(record: Recordable) { | |
115 | + openModal(true, { | |
116 | + record, | |
117 | + isUpdate: true, | |
118 | + showFooter: false, | |
119 | + }); | |
120 | + } | |
121 | + /** | |
122 | + * 删除事件 | |
123 | + */ | |
124 | + async function handleDelete(record) { | |
125 | + await deleteOne({id: record.id}, reload); | |
126 | + } | |
127 | + /** | |
128 | + * 批量删除事件 | |
129 | + */ | |
130 | + async function batchHandleDelete() { | |
131 | + await batchDelete({ids: checkedKeys.value}, reload); | |
132 | + } | |
133 | + /** | |
134 | + * 成功回调 | |
135 | + */ | |
136 | + function handleSuccess() { | |
137 | + reload(); | |
138 | + } | |
139 | + /** | |
140 | + * 操作栏 | |
141 | + */ | |
142 | + function getTableAction(record){ | |
143 | + return [ | |
144 | + { | |
145 | + label: '编辑', | |
146 | + onClick: handleEdit.bind(null, record), | |
147 | + } | |
148 | + ] | |
149 | + } | |
150 | + /** | |
151 | + * 下拉操作栏 | |
152 | + */ | |
153 | + function getDropDownAction(record){ | |
154 | + return [ | |
155 | + { | |
156 | + label: '详情', | |
157 | + onClick: handleDetail.bind(null, record), | |
158 | + }, { | |
159 | + label: '删除', | |
160 | + popConfirm: { | |
161 | + title: '是否确认删除', | |
162 | + confirm: handleDelete.bind(null, record), | |
163 | + } | |
164 | + } | |
165 | + ] | |
166 | + } | |
167 | +</script> | |
168 | + | |
169 | +<style scoped> | |
170 | + | |
171 | +</style> | |
0 | 172 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
0 → 100644
1 | +import {defHttp} from '/@/utils/http/axios'; | |
2 | +import {Modal} from 'ant-design-vue'; | |
3 | + | |
4 | +enum Api { | |
5 | + list = '/${entityPackage}/${entityName?uncap_first}/list', | |
6 | + save='/${entityPackage}/${entityName?uncap_first}/add', | |
7 | + edit='/${entityPackage}/${entityName?uncap_first}/edit', | |
8 | + deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete', | |
9 | + deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch', | |
10 | + importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel', | |
11 | + exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls', | |
12 | +<#list subTables as sub><#rt/> | |
13 | + ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/list${sub.entityName}ByMainId', | |
14 | + ${sub.entityName?uncap_first}Save='/${entityPackage}/${entityName?uncap_first}/add${sub.entityName}', | |
15 | + ${sub.entityName?uncap_first}Edit='/${entityPackage}/${entityName?uncap_first}/edit${sub.entityName}', | |
16 | + ${sub.entityName?uncap_first}Delete = '/${entityPackage}/${entityName?uncap_first}/delete${sub.entityName}', | |
17 | + ${sub.entityName?uncap_first}DeleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch${sub.entityName}', | |
18 | +</#list> | |
19 | +} | |
20 | +/** | |
21 | + * 导出api | |
22 | + * @param params | |
23 | + */ | |
24 | +export const getExportUrl = Api.exportXls; | |
25 | + | |
26 | +/** | |
27 | + * 导入api | |
28 | + */ | |
29 | +export const getImportUrl = Api.importExcel; | |
30 | + | |
31 | +/** | |
32 | + * 列表接口 | |
33 | + * @param params | |
34 | + */ | |
35 | +export const list = (params) => | |
36 | + defHttp.get({url: Api.list, params}); | |
37 | + | |
38 | +/** | |
39 | + * 删除单个 | |
40 | + */ | |
41 | +export const deleteOne = (params,handleSuccess) => { | |
42 | + return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => { | |
43 | + handleSuccess(); | |
44 | + }); | |
45 | +} | |
46 | +/** | |
47 | + * 批量删除 | |
48 | + * @param params | |
49 | + */ | |
50 | +export const batchDelete = (params, handleSuccess) => { | |
51 | + Modal.confirm({ | |
52 | + title: '确认删除', | |
53 | + content: '是否删除选中数据', | |
54 | + okText: '确认', | |
55 | + cancelText: '取消', | |
56 | + onOk: () => { | |
57 | + return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
58 | + handleSuccess(); | |
59 | + }); | |
60 | + } | |
61 | + }); | |
62 | +} | |
63 | +/** | |
64 | + * 保存或者更新 | |
65 | + * @param params | |
66 | + */ | |
67 | +export const saveOrUpdate = (params, isUpdate) => { | |
68 | + let url = isUpdate ? Api.edit : Api.save; | |
69 | + return defHttp.post({url: url, params}); | |
70 | +} | |
71 | + | |
72 | +<#list subTables as sub><#rt/> | |
73 | +/** | |
74 | + * 列表接口 | |
75 | + * @param params | |
76 | + */ | |
77 | +export const ${sub.entityName?uncap_first}List = (params) => | |
78 | + defHttp.get({url: Api.${sub.entityName?uncap_first}List, params}); | |
79 | + | |
80 | +/** | |
81 | + * 删除单个 | |
82 | + */ | |
83 | +export const ${sub.entityName?uncap_first}Delete = (params,handleSuccess) => { | |
84 | + return defHttp.delete({url: Api.${sub.entityName?uncap_first}Delete, params}, {joinParamsToUrl: true}).then(() => { | |
85 | + handleSuccess(); | |
86 | + }); | |
87 | +} | |
88 | +/** | |
89 | + * 批量删除 | |
90 | + * @param params | |
91 | + */ | |
92 | +export const ${sub.entityName?uncap_first}DeleteBatch = (params, handleSuccess) => { | |
93 | + Modal.confirm({ | |
94 | + title: '确认删除', | |
95 | + content: '是否删除选中数据', | |
96 | + okText: '确认', | |
97 | + cancelText: '取消', | |
98 | + onOk: () => { | |
99 | + return defHttp.delete({url: Api. ${sub.entityName?uncap_first}DeleteBatch, data: params}, {joinParamsToUrl: true}).then(() => { | |
100 | + handleSuccess(); | |
101 | + }); | |
102 | + } | |
103 | + }); | |
104 | +} | |
105 | +/** | |
106 | + * 保存或者更新 | |
107 | + * @param params | |
108 | + */ | |
109 | +export const ${sub.entityName?uncap_first}Save = (params, isUpdate) => { | |
110 | + let url = isUpdate ? Api.${sub.entityName?uncap_first}Edit : Api.${sub.entityName?uncap_first}Save; | |
111 | + return defHttp.post({url: url, params}); | |
112 | +} | |
113 | +</#list> | |
0 | 114 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
0 → 100644
1 | +import {BasicColumn} from '/@/components/Table'; | |
2 | +import {FormSchema} from '/@/components/Table'; | |
3 | +import { rules} from '/@/utils/helper/validator'; | |
4 | +import { render } from '/@/utils/common/renderUtils'; | |
5 | +//列表数据 | |
6 | +export const columns: BasicColumn[] = [ | |
7 | + <#list columns as po> | |
8 | + <#if po.fieldName !='id'> | |
9 | + { | |
10 | + title: '${po.filedComment}', | |
11 | + align:"center", | |
12 | + <#if po.classType=='date'> | |
13 | + dataIndex: '${po.fieldName}', | |
14 | + customRender:({text}) =>{ | |
15 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
16 | + }, | |
17 | + <#else> | |
18 | + dataIndex: '${po.fieldName}' | |
19 | + </#if> | |
20 | + }, | |
21 | + </#if> | |
22 | + </#list> | |
23 | +]; | |
24 | +//查询数据 | |
25 | +export const searchFormSchema: FormSchema[] = [ | |
26 | +<#list columns as po> | |
27 | +<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum> | |
28 | + { | |
29 | + label: '${po.filedComment}', | |
30 | + field: '${po.fieldName}', | |
31 | + <#if po.fieldType =='date'> | |
32 | + component: 'DatePicker' | |
33 | + <#elseif po.fieldType =='datetime'> | |
34 | + component: 'TimePicker' | |
35 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
36 | + component: 'InputNumber' | |
37 | + <#else> | |
38 | + component: 'Input' | |
39 | + </#if> | |
40 | + }, | |
41 | +</#if> | |
42 | +</#list> | |
43 | +]; | |
44 | + | |
45 | +export const formSchema: FormSchema[] = [ | |
46 | +<#list columns as po><#rt/> | |
47 | + { | |
48 | + label: '${po.filedComment}', | |
49 | + field: '${po.fieldName}', | |
50 | + <#if po.fieldType =='date'> | |
51 | + component: 'DatePicker' | |
52 | + <#elseif po.fieldType =='datetime'> | |
53 | + component: 'TimePicker' | |
54 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
55 | + component: 'InputNumber' | |
56 | + <#else> | |
57 | + component: 'Input' | |
58 | + </#if> | |
59 | + <#if po.fieldName =='id'><#rt/> | |
60 | + show:false | |
61 | + </#if> | |
62 | + }, | |
63 | +</#list> | |
64 | +]; | |
65 | + | |
66 | +//子表表格配置 | |
67 | +<#list subTables as sub> | |
68 | +//列表数据 | |
69 | +export const ${sub.entityName?uncap_first}Columns: BasicColumn[] = [ | |
70 | + <#list sub.colums as po><#rt/> | |
71 | + <#if po.fieldName !='id' && sub.foreignKeys[0]?uncap_first != po.fieldName> | |
72 | + { | |
73 | + title: '${po.filedComment}', | |
74 | + align:"center", | |
75 | + <#if po.classType=='date'> | |
76 | + dataIndex: '${po.fieldName}', | |
77 | + customRender:({text}) =>{ | |
78 | + return !text?"":(text.length>10?text.substr(0,10):text) | |
79 | + }, | |
80 | + <#else> | |
81 | + dataIndex: '${po.fieldName}' | |
82 | + </#if> | |
83 | + }, | |
84 | + </#if> | |
85 | + </#list> | |
86 | +]; | |
87 | + | |
88 | +export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [ | |
89 | +<#-- 循环子表的列 开始 --> | |
90 | +<#list sub.colums as po><#rt/> | |
91 | + { | |
92 | + label: '${po.filedComment}', | |
93 | + field: '${po.fieldName}', | |
94 | + <#if po.fieldType =='date'> | |
95 | + component: 'DatePicker' | |
96 | + <#elseif po.fieldType =='datetime'> | |
97 | + component: 'TimePicker' | |
98 | + <#elseif "int,decimal,double,"?contains(po.fieldType)> | |
99 | + component: 'InputNumber' | |
100 | + <#else> | |
101 | + component: 'Input' | |
102 | + </#if> | |
103 | + <#if po.fieldName =='id'><#rt/> | |
104 | + show:false | |
105 | + </#if> | |
106 | + }, | |
107 | +</#list> | |
108 | +<#-- 循环子表的列 结束 --> | |
109 | + ] | |
110 | +</#list> | |
0 | 111 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
0 → 100644
1 | +<#list subTables as subTab> | |
2 | +#segment#${subTab.entityName}List.vue | |
3 | +<template> | |
4 | + <div> | |
5 | + <!--table区域-begin--> | |
6 | + <BasicTable @register="registerTable" :rowSelection="rowSelection"> | |
7 | + <!--插槽:table标题--> | |
8 | + <template #tableTitle> | |
9 | + <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button> | |
10 | + <a-dropdown v-if="selectedRowKeys.length > 0"> | |
11 | + <template #overlay> | |
12 | + <a-menu> | |
13 | + <a-menu-item key="1" @click="batchHandleDelete"> | |
14 | + <Icon icon="ant-design:delete-outlined"></Icon> | |
15 | + 删除 | |
16 | + </a-menu-item> | |
17 | + </a-menu> | |
18 | + </template> | |
19 | + <a-button>批量操作 | |
20 | + <Icon icon="mdi:chevron-down"></Icon> | |
21 | + </a-button> | |
22 | + </a-dropdown> | |
23 | + </template> | |
24 | + <!--操作栏--> | |
25 | + <template #action="{ record }"> | |
26 | + <TableAction :actions="getTableAction(record)"/> | |
27 | + </template> | |
28 | + </BasicTable> | |
29 | + <!-- table区域-end --> | |
30 | + | |
31 | + <!-- 表单区域 --> | |
32 | + <${subTab.entityName}Modal @register="registerModal" @success="handleSuccess"/> | |
33 | + </div> | |
34 | +</template> | |
35 | + | |
36 | +<script lang="ts" setup> | |
37 | + import {ref, computed, unref, watch, inject} from 'vue'; | |
38 | + import ${subTab.entityName}Modal from './modules/${subTab.entityName}Modal.vue' | |
39 | + import {BasicTable, useTable, TableAction} from '/@/components/Table'; | |
40 | + import { useListPage } from '/@/hooks/system/useListPage' | |
41 | + import {useModal} from '/@/components/Modal'; | |
42 | + import {isEmpty} from "/@/utils/is"; | |
43 | + import {useMessage} from '/@/hooks/web/useMessage'; | |
44 | + import {${subTab.entityName?uncap_first}Columns} from './${entityName?uncap_first}.data'; | |
45 | + import {${subTab.entityName?uncap_first}List, ${subTab.entityName?uncap_first}Delete, ${subTab.entityName?uncap_first}DeleteBatch} from './${entityName?uncap_first}.api'; | |
46 | + //提示弹窗 | |
47 | + const $message = useMessage() | |
48 | + //接收主表id | |
49 | + const mainId = inject('mainId') || ''; | |
50 | + //查询参数 | |
51 | + const searchInfo = ref({}); | |
52 | + //注册model | |
53 | + const [registerModal, {openModal}] = useModal(); | |
54 | + // 列表页面公共参数、方法 | |
55 | + const {prefixCls, tableContext} = useListPage({ | |
56 | + tableProps: { | |
57 | + api: ${subTab.entityName?uncap_first}List, | |
58 | + columns: ${subTab.entityName?uncap_first}Columns, | |
59 | + canResize: false, | |
60 | + useSearchForm: false, | |
61 | + searchInfo, | |
62 | + actionColumn: { | |
63 | + width: 180, | |
64 | + } | |
65 | + }, | |
66 | + }); | |
67 | + | |
68 | + //注册table数据 | |
69 | + const [registerTable, {reload}, {rowSelection, selectedRowKeys}] = tableContext; | |
70 | + | |
71 | + watch(mainId, () => { | |
72 | + searchInfo.value['${subTab.foreignKeys[0]?uncap_first}'] = unref(mainId); | |
73 | + reload(); | |
74 | + } | |
75 | + ); | |
76 | + | |
77 | + /** | |
78 | + * 新增事件 | |
79 | + */ | |
80 | + function handleAdd() { | |
81 | + if (isEmpty(unref(mainId))) { | |
82 | + $message.createMessage.warning('请选择一个主表信息') | |
83 | + return; | |
84 | + } | |
85 | + openModal(true, { | |
86 | + isUpdate: false, | |
87 | + showFooter: true, | |
88 | + }); | |
89 | + } | |
90 | + | |
91 | + /** | |
92 | + * 编辑事件 | |
93 | + */ | |
94 | + async function handleEdit(record: Recordable) { | |
95 | + openModal(true, { | |
96 | + record, | |
97 | + isUpdate: true, | |
98 | + showFooter: true, | |
99 | + }); | |
100 | + } | |
101 | + | |
102 | + /** | |
103 | + * 删除事件 | |
104 | + */ | |
105 | + async function handleDelete(record) { | |
106 | + await ${subTab.entityName?uncap_first}Delete({id: record.id}, reload); | |
107 | + } | |
108 | + | |
109 | + /** | |
110 | + * 批量删除事件 | |
111 | + */ | |
112 | + async function batchHandleDelete() { | |
113 | + await ${subTab.entityName?uncap_first}DeleteBatch({ids: selectedRowKeys.value}, () => { | |
114 | + selectedRowKeys.value = [] | |
115 | + reload() | |
116 | + }) | |
117 | + } | |
118 | + | |
119 | + /** | |
120 | + * 成功回调 | |
121 | + */ | |
122 | + function handleSuccess() { | |
123 | + reload(); | |
124 | + } | |
125 | + | |
126 | + /** | |
127 | + * 操作栏 | |
128 | + */ | |
129 | + function getTableAction(record) { | |
130 | + return [ | |
131 | + { | |
132 | + label: '编辑', | |
133 | + onClick: handleEdit.bind(null, record), | |
134 | + }, { | |
135 | + label: '删除', | |
136 | + popConfirm: { | |
137 | + title: '是否确认删除', | |
138 | + confirm: handleDelete.bind(null, record), | |
139 | + }, | |
140 | + } | |
141 | + ] | |
142 | + } | |
143 | +</script> | |
144 | +<style scoped> | |
145 | + | |
146 | +</style> | |
147 | +</#list> | |
0 | 148 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
0 → 100644
1 | +<template> | |
2 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%"> | |
3 | + <BasicForm @register="registerForm"/> | |
4 | + </BasicModal> | |
5 | +</template> | |
6 | + | |
7 | +<script lang="ts" setup> | |
8 | + import {ref, computed, unref} from 'vue'; | |
9 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
10 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
11 | + import {formSchema} from '../${entityName?uncap_first}.data'; | |
12 | + import {saveOrUpdate} from '../${entityName?uncap_first}.api'; | |
13 | + // Emits声明 | |
14 | + const emit = defineEmits(['register','success']); | |
15 | + const isUpdate = ref(true); | |
16 | + //表单配置 | |
17 | + const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({ | |
18 | + labelWidth: 150, | |
19 | + schemas: formSchema, | |
20 | + showActionButtonGroup: false, | |
21 | + }); | |
22 | + //表单赋值 | |
23 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
24 | + //重置表单 | |
25 | + await resetFields(); | |
26 | + setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter}); | |
27 | + isUpdate.value = !!data?.isUpdate; | |
28 | + if (unref(isUpdate)) { | |
29 | + //表单赋值 | |
30 | + await setFieldsValue({ | |
31 | + ...data.record, | |
32 | + }); | |
33 | + } | |
34 | + }); | |
35 | + //设置标题 | |
36 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
37 | + //表单提交事件 | |
38 | + async function handleSubmit(v) { | |
39 | + try { | |
40 | + let values = await validate(); | |
41 | + setModalProps({confirmLoading: true}); | |
42 | + //提交表单 | |
43 | + await saveOrUpdate(values, isUpdate.value); | |
44 | + //关闭弹窗 | |
45 | + closeModal(); | |
46 | + //刷新列表 | |
47 | + emit('success'); | |
48 | + } finally { | |
49 | + setModalProps({confirmLoading: false}); | |
50 | + } | |
51 | + } | |
52 | +</script> | |
53 | + | |
54 | +<style lang="less" scoped> | |
55 | + | |
56 | +</style> | |
0 | 57 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/[1-n]Modal.vuei
0 → 100644
1 | +<#list subTables as subTab> | |
2 | +#segment#${subTab.entityName}Modal.vue | |
3 | +<template> | |
4 | + <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%"> | |
5 | + <BasicForm @register="registerForm"/> | |
6 | + </BasicModal> | |
7 | +</template> | |
8 | + | |
9 | +<script lang="ts" setup> | |
10 | + import {ref, computed, unref,inject} from 'vue'; | |
11 | + import {BasicModal, useModalInner} from '/@/components/Modal'; | |
12 | + import {BasicForm, useForm} from '/@/components/Form/index'; | |
13 | + import {${subTab.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data'; | |
14 | + import {${subTab.entityName?uncap_first}Save} from '../${entityName?uncap_first}.api'; | |
15 | + // Emits声明 | |
16 | + const emit = defineEmits(['register','success']); | |
17 | + //接收主表id | |
18 | + const mainId = inject('mainId'); | |
19 | + const isUpdate = ref(true); | |
20 | + //表单配置 | |
21 | + const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({ | |
22 | + labelWidth: 150, | |
23 | + schemas: ${subTab.entityName?uncap_first}FormSchema, | |
24 | + showActionButtonGroup: false, | |
25 | + }); | |
26 | + //表单赋值 | |
27 | + const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => { | |
28 | + //重置表单 | |
29 | + await resetFields(); | |
30 | + setModalProps({confirmLoading: false}); | |
31 | + isUpdate.value = !!data?.isUpdate; | |
32 | + if (unref(isUpdate)) { | |
33 | + //表单赋值 | |
34 | + await setFieldsValue({ | |
35 | + ...data.record, | |
36 | + }); | |
37 | + } | |
38 | + }); | |
39 | + //设置标题 | |
40 | + const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑')); | |
41 | + //表单提交事件 | |
42 | + async function handleSubmit(v) { | |
43 | + try { | |
44 | + let values = await validate(); | |
45 | + setModalProps({confirmLoading: true}); | |
46 | + if (unref(mainId)) { | |
47 | + values['${subTab.foreignKeys[0]?uncap_first}'] = unref(mainId); | |
48 | + } | |
49 | + //提交表单 | |
50 | + await ${subTab.entityName?uncap_first}Save(values, isUpdate.value); | |
51 | + //关闭弹窗 | |
52 | + closeModal(); | |
53 | + //刷新列表 | |
54 | + emit('success'); | |
55 | + } finally { | |
56 | + setModalProps({confirmLoading: false}); | |
57 | + } | |
58 | + } | |
59 | +</script> | |
60 | + | |
61 | +<style scoped> | |
62 | + | |
63 | +</style> | |
64 | +</#list> | |
0 | 65 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-module-system/src/main/resources/templates/announcement/showContent.ftl
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-boot-starter</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <modelVersion>4.0.0</modelVersion> |
11 | 11 | <artifactId>jeecg-boot-starter-cloud</artifactId> |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/resources/bootstrap.yml
... | ... | @@ -9,9 +9,9 @@ spring: |
9 | 9 | nacos: |
10 | 10 | config: |
11 | 11 | # Nacos 认证用户 |
12 | - username: nacos | |
12 | + username: @config.username@ | |
13 | 13 | # Nacos 认证密码 |
14 | - password: nacos | |
14 | + password: @config.password@ | |
15 | 15 | # 命名空间 常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等 |
16 | 16 | namespace: @config.namespace@ |
17 | 17 | # 配置中心地址 |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-boot-starter</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <modelVersion>4.0.0</modelVersion> |
11 | 11 | <artifactId>jeecg-boot-starter-job</artifactId> |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-boot-starter</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <modelVersion>4.0.0</modelVersion> |
11 | 11 | <artifactId>jeecg-boot-starter-lock</artifactId> |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/src/main/java/org/jeecg/boot/starter/lock/aspect/DistributedLockHandler.java
... | ... | @@ -94,9 +94,6 @@ public class DistributedLockHandler extends BaseAspect{ |
94 | 94 | Object[] args = joinPoint.getArgs(); |
95 | 95 | |
96 | 96 | LockModel lockModel = jLock.lockModel(); |
97 | - if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) { | |
98 | - throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定"); | |
99 | - } | |
100 | 97 | RLock rLock = null; |
101 | 98 | String keyConstant = jLock.keyConstant(); |
102 | 99 | if (lockModel.equals(LockModel.AUTO)) { |
... | ... | @@ -106,6 +103,9 @@ public class DistributedLockHandler extends BaseAspect{ |
106 | 103 | lockModel = LockModel.REENTRANT; |
107 | 104 | } |
108 | 105 | } |
106 | + if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) { | |
107 | + throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定"); | |
108 | + } | |
109 | 109 | switch (lockModel) { |
110 | 110 | case FAIR: |
111 | 111 | rLock = redissonClient.getFairLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0)); |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-boot-starter</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <modelVersion>4.0.0</modelVersion> |
11 | 11 | <artifactId>jeecg-boot-starter-rabbitmq</artifactId> |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-seata/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
5 | + <parent> | |
6 | + <artifactId>jeecg-boot-starter</artifactId> | |
7 | + <groupId>org.jeecgframework.boot</groupId> | |
8 | + <version>3.1.0</version> | |
9 | + </parent> | |
10 | + <modelVersion>4.0.0</modelVersion> | |
11 | + <artifactId>jeecg-boot-starter-seata</artifactId> | |
12 | + <description>分布式事务</description> | |
13 | + <dependencies> | |
14 | + <!-- seata依赖 --> | |
15 | + <dependency> | |
16 | + <groupId>io.seata</groupId> | |
17 | + <artifactId>seata-spring-boot-starter</artifactId> | |
18 | + <version>1.4.2</version> | |
19 | + </dependency> | |
20 | + <dependency> | |
21 | + <groupId>com.alibaba.nacos</groupId> | |
22 | + <artifactId>nacos-client</artifactId> | |
23 | + <version>1.3.3</version> | |
24 | + </dependency> | |
25 | + | |
26 | + </dependencies> | |
27 | +</project> | |
0 | 28 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
5 | + <parent> | |
6 | + <artifactId>jeecg-boot-starter</artifactId> | |
7 | + <groupId>org.jeecgframework.boot</groupId> | |
8 | + <version>3.1.0</version> | |
9 | + </parent> | |
10 | + <modelVersion>4.0.0</modelVersion> | |
11 | + <artifactId>jeecg-boot-starter-shardingsphere</artifactId> | |
12 | + <description>分库分表</description> | |
13 | + <dependencies> | |
14 | + <!-- 动态数据源 --> | |
15 | + <dependency> | |
16 | + <groupId>com.baomidou</groupId> | |
17 | + <artifactId>dynamic-datasource-spring-boot-starter</artifactId> | |
18 | + <version>${dynamic-datasource-spring-boot-starter.version}</version> | |
19 | + </dependency> | |
20 | + <!-- 分库分表 --> | |
21 | + <dependency> | |
22 | + <groupId>org.apache.shardingsphere</groupId> | |
23 | + <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> | |
24 | + <version>5.0.0</version> | |
25 | + </dependency> | |
26 | + </dependencies> | |
27 | + | |
28 | +</project> | |
0 | 29 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/java/org/jeecg/boot/shardingsphere/config/DataSourceConfiguration.java
0 → 100644
1 | +package org.jeecg.boot.shardingsphere.config; | |
2 | + | |
3 | +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; | |
4 | +import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider; | |
5 | +import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; | |
6 | +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; | |
7 | +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; | |
8 | +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties; | |
9 | +import org.springframework.boot.SpringBootConfiguration; | |
10 | +import org.springframework.boot.autoconfigure.AutoConfigureBefore; | |
11 | +import org.springframework.context.annotation.Bean; | |
12 | +import org.springframework.context.annotation.Configuration; | |
13 | +import org.springframework.context.annotation.Lazy; | |
14 | +import org.springframework.context.annotation.Primary; | |
15 | + | |
16 | +import javax.annotation.Resource; | |
17 | +import javax.sql.DataSource; | |
18 | +import java.util.Map; | |
19 | + | |
20 | +/** | |
21 | + * 分库分表数据源配置 | |
22 | + * @author zyf | |
23 | + */ | |
24 | +@Configuration | |
25 | +@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class}) | |
26 | +public class DataSourceConfiguration { | |
27 | + /** | |
28 | + * 分表数据源名称 | |
29 | + */ | |
30 | + public static final String SHARDING_DATA_SOURCE_NAME = "sharding"; | |
31 | + /** | |
32 | + * 动态数据源配置项 | |
33 | + */ | |
34 | + @Resource | |
35 | + private DynamicDataSourceProperties dynamicDataSourceProperties; | |
36 | + | |
37 | + @Lazy | |
38 | + @Resource | |
39 | + DataSource shardingDataSource; | |
40 | + | |
41 | + /** | |
42 | + * 将shardingDataSource放到了多数据源(dataSourceMap)中 | |
43 | + * 注意有个版本的bug,3.1.1版本 不会进入loadDataSources 方法,这样就一直造成数据源注册失败 | |
44 | + */ | |
45 | + @Bean | |
46 | + public DynamicDataSourceProvider dynamicDataSourceProvider() { | |
47 | + Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource(); | |
48 | + return new AbstractDataSourceProvider() { | |
49 | + @Override | |
50 | + public Map<String, DataSource> loadDataSources() { | |
51 | + Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap); | |
52 | + // 将 shardingjdbc 管理的数据源也交给动态数据源管理 | |
53 | + dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource); | |
54 | + return dataSourceMap; | |
55 | + } | |
56 | + }; | |
57 | + } | |
58 | + | |
59 | + /** | |
60 | + * 将动态数据源设置为首选的 | |
61 | + * 当spring存在多个数据源时, 自动注入的是首选的对象 | |
62 | + * 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了 | |
63 | + * | |
64 | + * @return | |
65 | + */ | |
66 | + @Primary | |
67 | + @Bean | |
68 | + public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) { | |
69 | + DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); | |
70 | + dataSource.setPrimary(dynamicDataSourceProperties.getPrimary()); | |
71 | + dataSource.setStrict(dynamicDataSourceProperties.getStrict()); | |
72 | + dataSource.setStrategy(dynamicDataSourceProperties.getStrategy()); | |
73 | + dataSource.setProvider(dynamicDataSourceProvider); | |
74 | + dataSource.setP6spy(dynamicDataSourceProperties.getP6spy()); | |
75 | + dataSource.setSeata(dynamicDataSourceProperties.getSeata()); | |
76 | + return dataSource; | |
77 | + } | |
78 | +} | |
... | ... |
jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/resources/application.yml
0 → 100644
jeecg-boot/jeecg-boot-starter/pom.xml
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | <parent> |
5 | 5 | <groupId>org.jeecgframework.boot</groupId> |
6 | 6 | <artifactId>jeecg-boot-parent</artifactId> |
7 | - <version>3.0</version> | |
7 | + <version>3.1.0</version> | |
8 | 8 | </parent> |
9 | 9 | <modelVersion>4.0.0</modelVersion> |
10 | 10 | <artifactId>jeecg-boot-starter</artifactId> |
... | ... | @@ -20,6 +20,8 @@ |
20 | 20 | <module>jeecg-boot-starter-job</module> |
21 | 21 | <module>jeecg-boot-starter-lock</module> |
22 | 22 | <module>jeecg-boot-starter-rabbitmq</module> |
23 | + <module>jeecg-boot-starter-shardingsphere</module> | |
24 | + <module>jeecg-boot-starter-seata</module> | |
23 | 25 | </modules> |
24 | 26 | <dependencies> |
25 | 27 | <!--jeecg-tools--> |
... | ... | @@ -38,4 +40,93 @@ |
38 | 40 | <optional>true</optional> |
39 | 41 | </dependency> |
40 | 42 | </dependencies> |
43 | + | |
44 | + | |
45 | + <build> | |
46 | + <plugins> | |
47 | + <plugin> | |
48 | + <artifactId>maven-compiler-plugin</artifactId> | |
49 | + <configuration> | |
50 | + <source>1.8</source> | |
51 | + <target>1.8</target> | |
52 | + <encoding>UTF-8</encoding> | |
53 | + </configuration> | |
54 | + </plugin> | |
55 | + <plugin> | |
56 | + <groupId>org.apache.maven.plugins</groupId> | |
57 | + <artifactId>maven-surefire-plugin</artifactId> | |
58 | + <configuration> | |
59 | + <testFailureIgnore>true</testFailureIgnore> | |
60 | + </configuration> | |
61 | + </plugin> | |
62 | + <!--生成Source jar文件--> | |
63 | + <plugin> | |
64 | + <groupId>org.apache.maven.plugins</groupId> | |
65 | + <artifactId>maven-source-plugin</artifactId> | |
66 | + <version>2.2.1</version> | |
67 | + <executions> | |
68 | + <execution> | |
69 | + <id>attach-sources</id> | |
70 | + <goals> | |
71 | + <goal>jar-no-fork</goal> | |
72 | + </goals> | |
73 | + </execution> | |
74 | + </executions> | |
75 | + </plugin> | |
76 | + <!--生成Javadoc,关闭doclint,避免注解检查不通过--> | |
77 | + <plugin> | |
78 | + <groupId>org.apache.maven.plugins</groupId> | |
79 | + <artifactId>maven-javadoc-plugin</artifactId> | |
80 | + <version>2.9.1</version> | |
81 | + <executions> | |
82 | + <execution> | |
83 | + <id>attach-javadocs</id> | |
84 | + <goals> | |
85 | + <goal>jar</goal> | |
86 | + </goals> | |
87 | + <configuration> | |
88 | + <additionalparam>-Xdoclint:none</additionalparam> | |
89 | + </configuration> | |
90 | + </execution> | |
91 | + </executions> | |
92 | + </plugin> | |
93 | + <!--Maven GPG插件用于使用以下配置对组件进行签名--> | |
94 | + <plugin> | |
95 | + <groupId>org.apache.maven.plugins</groupId> | |
96 | + <artifactId>maven-gpg-plugin</artifactId> | |
97 | + <version>1.6</version> | |
98 | + <executions> | |
99 | + <execution> | |
100 | + <id>sign-artifacts</id> | |
101 | + <phase>verify</phase> | |
102 | + <goals> | |
103 | + <goal>sign</goal> | |
104 | + </goals> | |
105 | + </execution> | |
106 | + </executions> | |
107 | + </plugin> | |
108 | + <!--Nexus Staging Maven插件是将组件部署到OSS并将其发布到Central Repository的推荐方法--> | |
109 | + <plugin> | |
110 | + <groupId>org.sonatype.plugins</groupId> | |
111 | + <artifactId>nexus-staging-maven-plugin</artifactId> | |
112 | + <version>1.6.7</version> | |
113 | + <extensions>true</extensions> | |
114 | + <configuration> | |
115 | + <serverId>oss</serverId> | |
116 | + <nexusUrl>https://oss.sonatype.org/</nexusUrl> | |
117 | + <autoReleaseAfterClose>true</autoReleaseAfterClose> | |
118 | + </configuration> | |
119 | + </plugin> | |
120 | + </plugins> | |
121 | + </build> | |
122 | + <distributionManagement> | |
123 | + <snapshotRepository> | |
124 | + <id>oss</id> | |
125 | + <url>https://oss.sonatype.org/content/repositories/snapshots/</url> | |
126 | + </snapshotRepository> | |
127 | + <repository> | |
128 | + <id>oss</id> | |
129 | + <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> | |
130 | + </repository> | |
131 | + </distributionManagement> | |
41 | 132 | </project> |
42 | 133 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile
... | ... | @@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-gateway |
10 | 10 | |
11 | 11 | EXPOSE 9999 |
12 | 12 | |
13 | -ADD ./target/jeecg-cloud-gateway-3.0.jar ./ | |
13 | +ADD ./target/jeecg-cloud-gateway-3.1.0.jar ./ | |
14 | 14 | |
15 | -CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-gateway-3.0.jar | |
16 | 15 | \ No newline at end of file |
16 | +CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-gateway-3.1.0.jar | |
17 | 17 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml
jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml
jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-cloud-module</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <modelVersion>4.0.0</modelVersion> |
11 | 11 | <artifactId>jeecg-cloud-monitor</artifactId> |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile
... | ... | @@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-nacos |
10 | 10 | |
11 | 11 | EXPOSE 8848 |
12 | 12 | |
13 | -ADD ./target/jeecg-cloud-nacos-3.0.jar ./ | |
13 | +ADD ./target/jeecg-cloud-nacos-3.1.0.jar ./ | |
14 | 14 | |
15 | -CMD sleep 5;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-nacos-3.0.jar | |
16 | 15 | \ No newline at end of file |
16 | +CMD sleep 5;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-nacos-3.1.0.jar | |
17 | 17 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml
jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-cloud-module</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <artifactId>jeecg-cloud-sentinel</artifactId> |
11 | 11 | <name>jeecg-cloud-sentinel</name> |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile
... | ... | @@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-system |
10 | 10 | |
11 | 11 | EXPOSE 7001 |
12 | 12 | |
13 | -ADD ./target/jeecg-cloud-system-start-3.0.jar ./ | |
13 | +ADD ./target/jeecg-cloud-system-start-3.1.0.jar ./ | |
14 | 14 | |
15 | -CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-system-start-3.0.jar | |
16 | 15 | \ No newline at end of file |
16 | +CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-system-start-3.1.0.jar | |
17 | 17 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-cloud-module</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <modelVersion>4.0.0</modelVersion> |
11 | 11 | <artifactId>jeecg-cloud-system-start</artifactId> |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
5 | + <parent> | |
6 | + <artifactId>jeecg-cloud-test</artifactId> | |
7 | + <groupId>org.jeecgframework.boot</groupId> | |
8 | + <version>3.1.0</version> | |
9 | + </parent> | |
10 | + <modelVersion>4.0.0</modelVersion> | |
11 | + <description>分布式事务测试模块</description> | |
12 | + <artifactId>jeecg-cloud-test-seata</artifactId> | |
13 | + | |
14 | + <dependencies> | |
15 | + <dependency> | |
16 | + <groupId>org.jeecgframework.boot</groupId> | |
17 | + <artifactId>jeecg-boot-starter-seata</artifactId> | |
18 | + <version>3.1.0</version> | |
19 | + </dependency> | |
20 | + </dependencies> | |
21 | + | |
22 | +</project> | |
0 | 23 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/controller/SeataOrderController.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.controller; | |
2 | + | |
3 | +/** | |
4 | + * @Description: TODO | |
5 | + * @author: zyf | |
6 | + * @date: 2022/01/24 | |
7 | + * @version: V1.0 | |
8 | + */ | |
9 | +import io.swagger.annotations.Api; | |
10 | +import io.swagger.annotations.ApiOperation; | |
11 | +import org.jeecg.modules.test.seata.dto.PlaceOrderRequest; | |
12 | +import org.jeecg.modules.test.seata.service.SeataOrderService; | |
13 | +import org.springframework.beans.factory.annotation.Autowired; | |
14 | +import org.springframework.validation.annotation.Validated; | |
15 | +import org.springframework.web.bind.annotation.PostMapping; | |
16 | +import org.springframework.web.bind.annotation.RequestBody; | |
17 | +import org.springframework.web.bind.annotation.RequestMapping; | |
18 | +import org.springframework.web.bind.annotation.RestController; | |
19 | + | |
20 | +@RestController | |
21 | +@RequestMapping("/order") | |
22 | +@Api(tags = "seata测试") | |
23 | +public class SeataOrderController { | |
24 | + | |
25 | + @Autowired | |
26 | + private SeataOrderService orderService; | |
27 | + | |
28 | + /** | |
29 | + * 自由下单 | |
30 | + */ | |
31 | + @PostMapping("/placeOrder") | |
32 | + @ApiOperation(value = "自由下单", notes = "自由下单") | |
33 | + public String placeOrder(@Validated @RequestBody PlaceOrderRequest request) { | |
34 | + orderService.placeOrder(request); | |
35 | + return "下单成功"; | |
36 | + } | |
37 | + | |
38 | + /** | |
39 | + * 测试商品库存不足-异常回滚 | |
40 | + */ | |
41 | + @PostMapping("/test1") | |
42 | + @ApiOperation(value = "测试商品库存不足", notes = "测试商品库存不足") | |
43 | + public String test1() { | |
44 | + //商品单价10元,库存20个,用户余额50元,模拟一次性购买22个。 期望异常回滚 | |
45 | + orderService.placeOrder(new PlaceOrderRequest(1L, 1L, 22)); | |
46 | + return "下单成功"; | |
47 | + } | |
48 | + | |
49 | + /** | |
50 | + * 测试用户账户余额不足-异常回滚 | |
51 | + */ | |
52 | + @PostMapping("/test2") | |
53 | + @ApiOperation(value = "测试用户账户余额不足", notes = "测试用户账户余额不足") | |
54 | + public String test2() { | |
55 | + //商品单价10元,库存20个,用户余额50元,模拟一次性购买6个。 期望异常回滚 | |
56 | + orderService.placeOrder(new PlaceOrderRequest(1L, 1L, 6)); | |
57 | + return "下单成功"; | |
58 | + } | |
59 | +} | |
0 | 60 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/PlaceOrderRequest.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.dto; | |
2 | +import lombok.AllArgsConstructor; | |
3 | +import lombok.Builder; | |
4 | +import lombok.Data; | |
5 | +import lombok.NoArgsConstructor; | |
6 | + | |
7 | +import javax.validation.constraints.NotNull; | |
8 | +/** | |
9 | + * @Description: 订单请求对象 | |
10 | + * @author: zyf | |
11 | + * @date: 2022/01/24 | |
12 | + * @version: V1.0 | |
13 | + */ | |
14 | +@Data | |
15 | +@Builder | |
16 | +@AllArgsConstructor | |
17 | +@NoArgsConstructor | |
18 | +public class PlaceOrderRequest { | |
19 | + | |
20 | + @NotNull | |
21 | + private Long userId; | |
22 | + | |
23 | + @NotNull | |
24 | + private Long productId; | |
25 | + | |
26 | + @NotNull | |
27 | + private Integer amount; | |
28 | +} | |
0 | 29 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceBalanceRequest.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.dto; | |
2 | +import lombok.AllArgsConstructor; | |
3 | +import lombok.Builder; | |
4 | +import lombok.Data; | |
5 | +import lombok.NoArgsConstructor; | |
6 | + | |
7 | +/** | |
8 | + * @Description: 余额请求对象 | |
9 | + * @author: zyf | |
10 | + * @date: 2022/01/24 | |
11 | + * @version: V1.0 | |
12 | + */ | |
13 | +@Data | |
14 | +@Builder | |
15 | +@AllArgsConstructor | |
16 | +@NoArgsConstructor | |
17 | +public class ReduceBalanceRequest { | |
18 | + | |
19 | + private Long userId; | |
20 | + private Integer price; | |
21 | +} | |
0 | 22 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceStockRequest.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.dto; | |
2 | + | |
3 | +import lombok.AllArgsConstructor; | |
4 | +import lombok.Builder; | |
5 | +import lombok.Data; | |
6 | +import lombok.NoArgsConstructor; | |
7 | +/** | |
8 | + * @Description: 库存请求对象 | |
9 | + * @author: zyf | |
10 | + * @date: 2022/01/24 | |
11 | + * @version: V1.0 | |
12 | + */ | |
13 | +@Data | |
14 | +@Builder | |
15 | +@AllArgsConstructor | |
16 | +@NoArgsConstructor | |
17 | +public class ReduceStockRequest { | |
18 | + | |
19 | + private Long productId; | |
20 | + private Integer amount; | |
21 | +} | |
0 | 22 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataAccount.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.entity; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.annotation.IdType; | |
4 | +import com.baomidou.mybatisplus.annotation.TableId; | |
5 | +import com.baomidou.mybatisplus.annotation.TableName; | |
6 | +import lombok.Builder; | |
7 | +import lombok.Data; | |
8 | + | |
9 | +import java.util.Date; | |
10 | + | |
11 | +/** | |
12 | + * @Description: 账户 | |
13 | + * @author: zyf | |
14 | + * @date: 2022/01/24 | |
15 | + * @version: V1.0 | |
16 | + */ | |
17 | +@Data | |
18 | +@Builder | |
19 | +@TableName("account") | |
20 | +public class SeataAccount { | |
21 | + @TableId(type = IdType.AUTO) | |
22 | + private Long id; | |
23 | + | |
24 | + /** | |
25 | + * 余额 | |
26 | + */ | |
27 | + private Double balance; | |
28 | + | |
29 | + private Date lastUpdateTime; | |
30 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataOrder.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.entity; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.annotation.IdType; | |
4 | +import com.baomidou.mybatisplus.annotation.TableId; | |
5 | +import com.baomidou.mybatisplus.annotation.TableName; | |
6 | +import lombok.Builder; | |
7 | +import lombok.Data; | |
8 | +import org.jeecg.modules.test.seata.enums.OrderStatus; | |
9 | + | |
10 | +/** | |
11 | + * @Description: 订单 | |
12 | + * @author: zyf | |
13 | + * @date: 2022/01/24 | |
14 | + * @version: V1.0 | |
15 | + */ | |
16 | +@Builder | |
17 | +@Data | |
18 | +@TableName("p_order") | |
19 | +public class SeataOrder { | |
20 | + | |
21 | + @TableId(type = IdType.AUTO) | |
22 | + private Integer id; | |
23 | + | |
24 | + /** | |
25 | + * 用户ID | |
26 | + */ | |
27 | + private Long userId; | |
28 | + /** | |
29 | + * 商品ID | |
30 | + */ | |
31 | + private Long productId; | |
32 | + /** | |
33 | + * 订单状态 | |
34 | + */ | |
35 | + private OrderStatus status; | |
36 | + /** | |
37 | + * 数量 | |
38 | + */ | |
39 | + private Integer amount; | |
40 | + /** | |
41 | + * 总金额 | |
42 | + */ | |
43 | + private Double totalPrice; | |
44 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataProduct.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.entity; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.annotation.IdType; | |
4 | +import com.baomidou.mybatisplus.annotation.TableId; | |
5 | +import com.baomidou.mybatisplus.annotation.TableName; | |
6 | +import lombok.Builder; | |
7 | +import lombok.Data; | |
8 | + | |
9 | +import java.util.Date; | |
10 | +/** | |
11 | + * @Description: 产品 | |
12 | + * @author: zyf | |
13 | + * @date: 2022/01/24 | |
14 | + * @version: V1.0 | |
15 | + */ | |
16 | +@Data | |
17 | +@Builder | |
18 | +@TableName("product") | |
19 | +public class SeataProduct { | |
20 | + | |
21 | + @TableId(type = IdType.AUTO) | |
22 | + private Integer id; | |
23 | + /** | |
24 | + * 价格 | |
25 | + */ | |
26 | + private Double price; | |
27 | + /** | |
28 | + * 库存 | |
29 | + */ | |
30 | + private Integer stock; | |
31 | + | |
32 | + private Date lastUpdateTime; | |
33 | +} | |
0 | 34 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/enums/OrderStatus.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.enums; | |
2 | + | |
3 | +/** | |
4 | + * @Description: 订单状态 | |
5 | + * @author: zyf | |
6 | + * @date: 2022/01/24 | |
7 | + * @version: V1.0 | |
8 | + */ | |
9 | +public enum OrderStatus { | |
10 | + /** | |
11 | + * INIT | |
12 | + */ | |
13 | + INIT, | |
14 | + /** | |
15 | + * SUCCESS | |
16 | + */ | |
17 | + SUCCESS, | |
18 | + /** | |
19 | + * FAIL | |
20 | + */ | |
21 | + FAIL | |
22 | +} | |
0 | 23 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataAccountMapper.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.mapper; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
4 | +import org.apache.ibatis.annotations.Mapper; | |
5 | +import org.jeecg.modules.test.seata.entity.SeataAccount; | |
6 | + | |
7 | +/** | |
8 | + * @Description: TODO | |
9 | + * @author: zyf | |
10 | + * @date: 2022/01/24 | |
11 | + * @version: V1.0 | |
12 | + */ | |
13 | +@Mapper | |
14 | +public interface SeataAccountMapper extends BaseMapper<SeataAccount> { | |
15 | + | |
16 | +} | |
0 | 17 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataOrderMapper.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.mapper; | |
2 | + | |
3 | +/** | |
4 | + * @Description: TODO | |
5 | + * @author: zyf | |
6 | + * @date: 2022/01/24 | |
7 | + * @version: V1.0 | |
8 | + */ | |
9 | + | |
10 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
11 | +import org.apache.ibatis.annotations.Mapper; | |
12 | +import org.jeecg.modules.test.seata.entity.SeataOrder; | |
13 | + | |
14 | +@Mapper | |
15 | +public interface SeataOrderMapper extends BaseMapper<SeataOrder> { | |
16 | + | |
17 | +} | |
0 | 18 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataProductMapper.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.mapper; | |
2 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
3 | +import org.apache.ibatis.annotations.Mapper; | |
4 | +import org.jeecg.modules.test.seata.entity.SeataProduct; | |
5 | + | |
6 | +/** | |
7 | + * @Description: TODO | |
8 | + * @author: zyf | |
9 | + * @date: 2022/01/24 | |
10 | + * @version: V1.0 | |
11 | + */ | |
12 | +@Mapper | |
13 | +public interface SeataProductMapper extends BaseMapper<SeataProduct> { | |
14 | + | |
15 | +} | |
0 | 16 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataAccountService.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.service; | |
2 | + | |
3 | +/** | |
4 | + * @Description: 账户接口 | |
5 | + * @author: zyf | |
6 | + * @date: 2022/01/24 | |
7 | + * @version: V1.0 | |
8 | + */ | |
9 | +public interface SeataAccountService { | |
10 | + /** | |
11 | + * @param userId 用户 ID | |
12 | + * @param price 扣减金额 | |
13 | + */ | |
14 | + void reduceBalance(Long userId, Double price); | |
15 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataOrderService.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.service; | |
2 | + | |
3 | +import org.jeecg.modules.test.seata.dto.PlaceOrderRequest; | |
4 | + | |
5 | +/** | |
6 | + * @Description: 订单接口 | |
7 | + * @author: zyf | |
8 | + * @date: 2022/01/24 | |
9 | + * @version: V1.0 | |
10 | + */ | |
11 | +public interface SeataOrderService { | |
12 | + /** | |
13 | + * 下单 | |
14 | + * | |
15 | + * @param placeOrderRequest 订单请求参数 | |
16 | + */ | |
17 | + void placeOrder(PlaceOrderRequest placeOrderRequest); | |
18 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataProductService.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.service; | |
2 | + | |
3 | +/** | |
4 | + * @Description: 产品接口 | |
5 | + * @author: zyf | |
6 | + * @date: 2022/01/24 | |
7 | + * @version: V1.0 | |
8 | + */ | |
9 | +public interface SeataProductService { | |
10 | + /** | |
11 | + * 扣减库存 | |
12 | + * | |
13 | + * @param productId 商品 ID | |
14 | + * @param amount 扣减数量 | |
15 | + * @return 商品总价 | |
16 | + */ | |
17 | + Double reduceStock(Long productId, Integer amount); | |
18 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataAccountServiceImpl.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.service.impl; | |
2 | + | |
3 | + | |
4 | +import com.baomidou.dynamic.datasource.annotation.DS; | |
5 | +import lombok.extern.slf4j.Slf4j; | |
6 | +import org.jeecg.modules.test.seata.entity.SeataAccount; | |
7 | +import org.jeecg.modules.test.seata.mapper.SeataAccountMapper; | |
8 | +import org.jeecg.modules.test.seata.service.SeataAccountService; | |
9 | +import org.springframework.stereotype.Service; | |
10 | +import org.springframework.transaction.annotation.Propagation; | |
11 | +import org.springframework.transaction.annotation.Transactional; | |
12 | +import org.springframework.util.Assert; | |
13 | + | |
14 | +import javax.annotation.Resource; | |
15 | + | |
16 | +/** | |
17 | + * @Description: TODO | |
18 | + * @author: zyf | |
19 | + * @date: 2022/01/24 | |
20 | + * @version: V1.0 | |
21 | + */ | |
22 | +@Slf4j | |
23 | +@Service | |
24 | +public class SeataAccountServiceImpl implements SeataAccountService { | |
25 | + @Resource | |
26 | + private SeataAccountMapper accountMapper; | |
27 | + | |
28 | + /** | |
29 | + * 事务传播特性设置为 REQUIRES_NEW 开启新的事务 | |
30 | + */ | |
31 | + @DS("account") | |
32 | + @Override | |
33 | + @Transactional(propagation = Propagation.REQUIRES_NEW) | |
34 | + public void reduceBalance(Long userId, Double price) { | |
35 | + log.info("=============ACCOUNT START================="); | |
36 | + SeataAccount account = accountMapper.selectById(userId); | |
37 | + Assert.notNull(account, "用户不存在"); | |
38 | + Double balance = account.getBalance(); | |
39 | + log.info("下单用户{}余额为 {},商品总价为{}", userId, balance, price); | |
40 | + | |
41 | + if (balance < price) { | |
42 | + log.warn("用户 {} 余额不足,当前余额:{}", userId, balance); | |
43 | + throw new RuntimeException("余额不足"); | |
44 | + } | |
45 | + log.info("开始扣减用户 {} 余额", userId); | |
46 | + double currentBalance = account.getBalance() - price; | |
47 | + account.setBalance(currentBalance); | |
48 | + accountMapper.updateById(account); | |
49 | + log.info("扣减用户 {} 余额成功,扣减后用户账户余额为{}", userId, currentBalance); | |
50 | + log.info("=============ACCOUNT END================="); | |
51 | + } | |
52 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataOrderServiceImpl.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.service.impl; | |
2 | +import com.baomidou.dynamic.datasource.annotation.DS; | |
3 | + | |
4 | +import io.seata.spring.annotation.GlobalTransactional; | |
5 | +import lombok.extern.slf4j.Slf4j; | |
6 | +import org.jeecg.modules.test.seata.dto.PlaceOrderRequest; | |
7 | +import org.jeecg.modules.test.seata.entity.SeataOrder; | |
8 | +import org.jeecg.modules.test.seata.enums.OrderStatus; | |
9 | +import org.jeecg.modules.test.seata.mapper.SeataOrderMapper; | |
10 | +import org.jeecg.modules.test.seata.service.SeataAccountService; | |
11 | +import org.jeecg.modules.test.seata.service.SeataOrderService; | |
12 | +import org.jeecg.modules.test.seata.service.SeataProductService; | |
13 | +import org.springframework.beans.factory.annotation.Autowired; | |
14 | +import org.springframework.stereotype.Service; | |
15 | +import org.springframework.transaction.annotation.Transactional; | |
16 | + | |
17 | +import javax.annotation.Resource; | |
18 | +/** | |
19 | + * @Description: 订单服务类 | |
20 | + * @author: zyf | |
21 | + * @date: 2022/01/24 | |
22 | + * @version: V1.0 | |
23 | + */ | |
24 | +@Slf4j | |
25 | +@Service | |
26 | +public class SeataOrderServiceImpl implements SeataOrderService { | |
27 | + | |
28 | + @Resource | |
29 | + private SeataOrderMapper orderMapper; | |
30 | + @Autowired | |
31 | + private SeataAccountService accountService; | |
32 | + @Autowired | |
33 | + private SeataProductService productService; | |
34 | + | |
35 | + @DS("order") | |
36 | + @Override | |
37 | + @Transactional | |
38 | + @GlobalTransactional | |
39 | + public void placeOrder(PlaceOrderRequest request) { | |
40 | + log.info("=============ORDER START================="); | |
41 | + Long userId = request.getUserId(); | |
42 | + Long productId = request.getProductId(); | |
43 | + Integer amount = request.getAmount(); | |
44 | + log.info("收到下单请求,用户:{}, 商品:{},数量:{}", userId, productId, amount); | |
45 | + | |
46 | + | |
47 | + SeataOrder order = SeataOrder.builder() | |
48 | + .userId(userId) | |
49 | + .productId(productId) | |
50 | + .status(OrderStatus.INIT) | |
51 | + .amount(amount) | |
52 | + .build(); | |
53 | + | |
54 | + orderMapper.insert(order); | |
55 | + log.info("订单一阶段生成,等待扣库存付款中"); | |
56 | + // 扣减库存并计算总价 | |
57 | + Double totalPrice = productService.reduceStock(productId, amount); | |
58 | + // 扣减余额 | |
59 | + accountService.reduceBalance(userId, totalPrice); | |
60 | + | |
61 | + order.setStatus(OrderStatus.SUCCESS); | |
62 | + order.setTotalPrice(totalPrice); | |
63 | + orderMapper.updateById(order); | |
64 | + log.info("订单已成功下单"); | |
65 | + log.info("=============ORDER END================="); | |
66 | + } | |
67 | +} | |
0 | 68 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataProductServiceImpl.java
0 → 100644
1 | +package org.jeecg.modules.test.seata.service.impl; | |
2 | + | |
3 | +import com.baomidou.dynamic.datasource.annotation.DS; | |
4 | +import lombok.extern.slf4j.Slf4j; | |
5 | + | |
6 | +import org.jeecg.modules.test.seata.entity.SeataProduct; | |
7 | +import org.jeecg.modules.test.seata.mapper.SeataProductMapper; | |
8 | +import org.jeecg.modules.test.seata.service.SeataProductService; | |
9 | +import org.springframework.stereotype.Service; | |
10 | +import org.springframework.transaction.annotation.Propagation; | |
11 | +import org.springframework.transaction.annotation.Transactional; | |
12 | +import org.springframework.util.Assert; | |
13 | + | |
14 | +import javax.annotation.Resource; | |
15 | + | |
16 | +/** | |
17 | + * @Description: 产品服务类 | |
18 | + * @author: zyf | |
19 | + * @date: 2022/01/24 | |
20 | + * @version: V1.0 | |
21 | + */ | |
22 | +@Slf4j | |
23 | +@Service | |
24 | +public class SeataProductServiceImpl implements SeataProductService { | |
25 | + | |
26 | + @Resource | |
27 | + private SeataProductMapper productMapper; | |
28 | + | |
29 | + /** | |
30 | + * 事务传播特性设置为 REQUIRES_NEW 开启新的事务 | |
31 | + */ | |
32 | + @DS("product") | |
33 | + @Transactional(propagation = Propagation.REQUIRES_NEW) | |
34 | + @Override | |
35 | + public Double reduceStock(Long productId, Integer amount) { | |
36 | + log.info("=============PRODUCT START================="); | |
37 | + // 检查库存 | |
38 | + SeataProduct product = productMapper.selectById(productId); | |
39 | + Assert.notNull(product, "商品不存在"); | |
40 | + Integer stock = product.getStock(); | |
41 | + log.info("商品编号为 {} 的库存为{},订单商品数量为{}", productId, stock, amount); | |
42 | + | |
43 | + if (stock < amount) { | |
44 | + log.warn("商品编号为{} 库存不足,当前库存:{}", productId, stock); | |
45 | + throw new RuntimeException("库存不足"); | |
46 | + } | |
47 | + log.info("开始扣减商品编号为 {} 库存,单价商品价格为{}", productId, product.getPrice()); | |
48 | + // 扣减库存 | |
49 | + int currentStock = stock - amount; | |
50 | + product.setStock(currentStock); | |
51 | + productMapper.updateById(product); | |
52 | + double totalPrice = product.getPrice() * amount; | |
53 | + log.info("扣减商品编号为 {} 库存成功,扣减后库存为{}, {} 件商品总价为 {} ", productId, currentStock, amount, totalPrice); | |
54 | + log.info("=============PRODUCT END================="); | |
55 | + return totalPrice; | |
56 | + } | |
57 | +} | |
0 | 58 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/application-seata.yml
0 → 100644
1 | +seata: | |
2 | + enable-auto-data-source-proxy: false | |
3 | + service: | |
4 | + grouplist: | |
5 | + default: 127.0.0.1:8091 | |
6 | + vgroup-mapping: | |
7 | + springboot-seata-group: default | |
8 | + # seata 事务组编号 用于TC集群名 | |
9 | + tx-service-group: springboot-seata-group | |
10 | + transport: | |
11 | + heartbeat: false | |
12 | +spring: | |
13 | + datasource: | |
14 | + dynamic: | |
15 | + seata: true # 开启对 seata的支持 | |
16 | + seata-mode: AT #支持XA及AT模式,默认AT | |
17 | + datasource: | |
18 | + # 设置 账号数据源配置 | |
19 | + account: | |
20 | + driver-class-name: com.mysql.cj.jdbc.Driver | |
21 | + url: jdbc:mysql://127.0.0.1:3306/jeecg-account?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false | |
22 | + username: root | |
23 | + password: root | |
24 | + schema: classpath:sql/schema-account.sql | |
25 | + # 设置 订单数据源配置 | |
26 | + order: | |
27 | + driver-class-name: com.mysql.cj.jdbc.Driver | |
28 | + url: jdbc:mysql://127.0.0.1:3306/jeecg-order?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false | |
29 | + username: root | |
30 | + password: root | |
31 | + schema: classpath:sql/schema-order.sql | |
32 | + # 设置商品 数据源配置 | |
33 | + product: | |
34 | + driver-class-name: com.mysql.cj.jdbc.Driver | |
35 | + url: jdbc:mysql://127.0.0.1:3306/jeecg-product?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false | |
36 | + username: root | |
37 | + password: root | |
38 | + schema: classpath:sql/schema-product.sql | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-account.sql
0 → 100644
1 | +DROP TABLE IF EXISTS account; | |
2 | +CREATE TABLE account | |
3 | +( | |
4 | + id INT(11) NOT NULL AUTO_INCREMENT, | |
5 | + balance DOUBLE DEFAULT NULL, | |
6 | + last_update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | |
7 | + PRIMARY KEY (id) | |
8 | +) ENGINE = InnoDB | |
9 | + AUTO_INCREMENT = 1 | |
10 | + DEFAULT CHARSET = utf8; | |
11 | + | |
12 | +DROP TABLE IF EXISTS undo_log; | |
13 | +CREATE TABLE undo_log | |
14 | +( | |
15 | + id BIGINT(20) NOT NULL AUTO_INCREMENT, | |
16 | + branch_id BIGINT(20) NOT NULL, | |
17 | + xid VARCHAR(100) NOT NULL, | |
18 | + context VARCHAR(128) NOT NULL, | |
19 | + rollback_info LONGBLOB NOT NULL, | |
20 | + log_status INT(11) NOT NULL, | |
21 | + log_created DATETIME NOT NULL, | |
22 | + log_modified DATETIME NOT NULL, | |
23 | + PRIMARY KEY (id), | |
24 | + UNIQUE KEY ux_undo_log (xid, branch_id) | |
25 | +) ENGINE = InnoDB | |
26 | + AUTO_INCREMENT = 1 | |
27 | + DEFAULT CHARSET = utf8; | |
28 | +INSERT INTO account (id, balance) | |
29 | +VALUES (1, 50); | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-order.sql
0 → 100644
1 | +DROP TABLE IF EXISTS p_order; | |
2 | +CREATE TABLE p_order | |
3 | +( | |
4 | + id INT(11) NOT NULL AUTO_INCREMENT, | |
5 | + user_id INT(11) DEFAULT NULL, | |
6 | + product_id INT(11) DEFAULT NULL, | |
7 | + amount INT(11) DEFAULT NULL, | |
8 | + total_price DOUBLE DEFAULT NULL, | |
9 | + status VARCHAR(100) DEFAULT NULL, | |
10 | + add_time DATETIME DEFAULT CURRENT_TIMESTAMP, | |
11 | + last_update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | |
12 | + PRIMARY KEY (id) | |
13 | +) ENGINE = InnoDB | |
14 | + AUTO_INCREMENT = 1 | |
15 | + DEFAULT CHARSET = utf8; | |
16 | + | |
17 | +DROP TABLE IF EXISTS undo_log; | |
18 | +CREATE TABLE undo_log | |
19 | +( | |
20 | + id BIGINT(20) NOT NULL AUTO_INCREMENT, | |
21 | + branch_id BIGINT(20) NOT NULL, | |
22 | + xid VARCHAR(100) NOT NULL, | |
23 | + context VARCHAR(128) NOT NULL, | |
24 | + rollback_info LONGBLOB NOT NULL, | |
25 | + log_status INT(11) NOT NULL, | |
26 | + log_created DATETIME NOT NULL, | |
27 | + log_modified DATETIME NOT NULL, | |
28 | + PRIMARY KEY (id), | |
29 | + UNIQUE KEY ux_undo_log (xid, branch_id) | |
30 | +) ENGINE = InnoDB | |
31 | + AUTO_INCREMENT = 1 | |
32 | + DEFAULT CHARSET = utf8; | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-product.sql
0 → 100644
1 | +DROP TABLE IF EXISTS product; | |
2 | +CREATE TABLE product | |
3 | +( | |
4 | + id INT(11) NOT NULL AUTO_INCREMENT, | |
5 | + price DOUBLE DEFAULT NULL, | |
6 | + stock INT(11) DEFAULT NULL, | |
7 | + last_update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | |
8 | + PRIMARY KEY (id) | |
9 | +) ENGINE = InnoDB | |
10 | + AUTO_INCREMENT = 1 | |
11 | + DEFAULT CHARSET = utf8; | |
12 | + | |
13 | +DROP TABLE IF EXISTS undo_log; | |
14 | +CREATE TABLE undo_log | |
15 | +( | |
16 | + id BIGINT(20) NOT NULL AUTO_INCREMENT, | |
17 | + branch_id BIGINT(20) NOT NULL, | |
18 | + xid VARCHAR(100) NOT NULL, | |
19 | + context VARCHAR(128) NOT NULL, | |
20 | + rollback_info LONGBLOB NOT NULL, | |
21 | + log_status INT(11) NOT NULL, | |
22 | + log_created DATETIME NOT NULL, | |
23 | + log_modified DATETIME NOT NULL, | |
24 | + PRIMARY KEY (id), | |
25 | + UNIQUE KEY ux_undo_log (xid, branch_id) | |
26 | +) ENGINE = InnoDB | |
27 | + AUTO_INCREMENT = 1 | |
28 | + DEFAULT CHARSET = utf8; | |
29 | + | |
30 | +INSERT INTO product (id, price, stock) | |
31 | +VALUES (1, 10, 20); | |
0 | 32 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/seata.sql
0 → 100644
1 | +/* | |
2 | + Navicat Premium Data Transfer | |
3 | + | |
4 | + Source Server : localhost | |
5 | + Source Server Type : MariaDB | |
6 | + Source Server Version : 100316 | |
7 | + Source Host : localhost:3300 | |
8 | + Source Schema : seata | |
9 | + | |
10 | + Target Server Type : MariaDB | |
11 | + Target Server Version : 100316 | |
12 | + File Encoding : 65001 | |
13 | + | |
14 | + Date: 05/01/2022 20:25:07 | |
15 | +*/ | |
16 | + | |
17 | +SET NAMES utf8mb4; | |
18 | +SET FOREIGN_KEY_CHECKS = 0; | |
19 | + | |
20 | +-- ---------------------------- | |
21 | +-- Table structure for branch_table | |
22 | +-- ---------------------------- | |
23 | +DROP TABLE IF EXISTS `branch_table`; | |
24 | +CREATE TABLE `branch_table` ( | |
25 | + `branch_id` bigint(20) NOT NULL, | |
26 | + `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, | |
27 | + `transaction_id` bigint(20) NULL DEFAULT NULL, | |
28 | + `resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
29 | + `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
30 | + `branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
31 | + `status` tinyint(4) NULL DEFAULT NULL, | |
32 | + `client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
33 | + `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
34 | + `gmt_create` datetime(6) NULL DEFAULT NULL, | |
35 | + `gmt_modified` datetime(6) NULL DEFAULT NULL, | |
36 | + PRIMARY KEY (`branch_id`) USING BTREE, | |
37 | + INDEX `idx_xid`(`xid`) USING BTREE | |
38 | +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; | |
39 | + | |
40 | +-- ---------------------------- | |
41 | +-- Table structure for global_table | |
42 | +-- ---------------------------- | |
43 | +DROP TABLE IF EXISTS `global_table`; | |
44 | +CREATE TABLE `global_table` ( | |
45 | + `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, | |
46 | + `transaction_id` bigint(20) NULL DEFAULT NULL, | |
47 | + `status` tinyint(4) NOT NULL, | |
48 | + `application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
49 | + `transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
50 | + `transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
51 | + `timeout` int(11) NULL DEFAULT NULL, | |
52 | + `begin_time` bigint(20) NULL DEFAULT NULL, | |
53 | + `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
54 | + `gmt_create` datetime(0) NULL DEFAULT NULL, | |
55 | + `gmt_modified` datetime(0) NULL DEFAULT NULL, | |
56 | + PRIMARY KEY (`xid`) USING BTREE, | |
57 | + INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE, | |
58 | + INDEX `idx_transaction_id`(`transaction_id`) USING BTREE | |
59 | +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; | |
60 | + | |
61 | +-- ---------------------------- | |
62 | +-- Table structure for lock_table | |
63 | +-- ---------------------------- | |
64 | +DROP TABLE IF EXISTS `lock_table`; | |
65 | +CREATE TABLE `lock_table` ( | |
66 | + `row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, | |
67 | + `xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
68 | + `transaction_id` bigint(20) NULL DEFAULT NULL, | |
69 | + `branch_id` bigint(20) NOT NULL, | |
70 | + `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
71 | + `table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
72 | + `pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, | |
73 | + `gmt_create` datetime(0) NULL DEFAULT NULL, | |
74 | + `gmt_modified` datetime(0) NULL DEFAULT NULL, | |
75 | + PRIMARY KEY (`row_key`) USING BTREE, | |
76 | + INDEX `idx_branch_id`(`branch_id`) USING BTREE | |
77 | +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; | |
78 | + | |
79 | +SET FOREIGN_KEY_CHECKS = 1; | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/undo_log.sql
0 → 100644
1 | +CREATE TABLE `undo_log` ( | |
2 | + `id` bigint(20) NOT NULL AUTO_INCREMENT, | |
3 | + `branch_id` bigint(20) NOT NULL, | |
4 | + `xid` varchar(100) NOT NULL, | |
5 | + `context` varchar(128) NOT NULL, | |
6 | + `rollback_info` longblob NOT NULL, | |
7 | + `log_status` int(11) NOT NULL, | |
8 | + `log_created` datetime NOT NULL, | |
9 | + `log_modified` datetime NOT NULL, | |
10 | + PRIMARY KEY (`id`), | |
11 | + UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) | |
12 | +) ENGINE=InnoDB AUTO_INCREMENT=137 DEFAULT CHARSET=utf8; | |
0 | 13 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/doc/db.sql
0 → 100644
1 | +CREATE TABLE `sys_log0` ( | |
2 | + `id` varchar(32) NOT NULL, | |
3 | + `log_type` int(2) DEFAULT NULL COMMENT '日志类型(1登录日志,2操作日志)', | |
4 | + `log_content` varchar(1000) DEFAULT NULL COMMENT '日志内容', | |
5 | + `operate_type` int(2) DEFAULT NULL COMMENT '操作类型', | |
6 | + `userid` varchar(32) DEFAULT NULL COMMENT '操作用户账号', | |
7 | + `username` varchar(100) DEFAULT NULL COMMENT '操作用户名称', | |
8 | + `ip` varchar(100) DEFAULT NULL COMMENT 'IP', | |
9 | + `method` varchar(500) DEFAULT NULL COMMENT '请求java方法', | |
10 | + `request_url` varchar(255) DEFAULT NULL COMMENT '请求路径', | |
11 | + `request_param` longtext DEFAULT NULL COMMENT '请求参数', | |
12 | + `request_type` varchar(10) DEFAULT NULL COMMENT '请求类型', | |
13 | + `cost_time` bigint(20) DEFAULT NULL COMMENT '耗时', | |
14 | + `create_by` varchar(32) DEFAULT NULL COMMENT '创建人', | |
15 | + `create_time` datetime DEFAULT NULL COMMENT '创建时间', | |
16 | + `update_by` varchar(32) DEFAULT NULL COMMENT '更新人', | |
17 | + `update_time` datetime DEFAULT NULL COMMENT '更新时间', | |
18 | + PRIMARY KEY (`id`) USING BTREE, | |
19 | + KEY `index_table_userid` (`userid`) USING BTREE, | |
20 | + KEY `index_logt_ype` (`log_type`) USING BTREE, | |
21 | + KEY `index_operate_type` (`operate_type`) USING BTREE, | |
22 | + KEY `index_createtime` (`create_time`) USING BTREE | |
23 | +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统日志表'; | |
24 | +CREATE TABLE `sys_log1` ( | |
25 | + `id` varchar(32) NOT NULL, | |
26 | + `log_type` int(2) DEFAULT NULL COMMENT '日志类型(1登录日志,2操作日志)', | |
27 | + `log_content` varchar(1000) DEFAULT NULL COMMENT '日志内容', | |
28 | + `operate_type` int(2) DEFAULT NULL COMMENT '操作类型', | |
29 | + `userid` varchar(32) DEFAULT NULL COMMENT '操作用户账号', | |
30 | + `username` varchar(100) DEFAULT NULL COMMENT '操作用户名称', | |
31 | + `ip` varchar(100) DEFAULT NULL COMMENT 'IP', | |
32 | + `method` varchar(500) DEFAULT NULL COMMENT '请求java方法', | |
33 | + `request_url` varchar(255) DEFAULT NULL COMMENT '请求路径', | |
34 | + `request_param` longtext DEFAULT NULL COMMENT '请求参数', | |
35 | + `request_type` varchar(10) DEFAULT NULL COMMENT '请求类型', | |
36 | + `cost_time` bigint(20) DEFAULT NULL COMMENT '耗时', | |
37 | + `create_by` varchar(32) DEFAULT NULL COMMENT '创建人', | |
38 | + `create_time` datetime DEFAULT NULL COMMENT '创建时间', | |
39 | + `update_by` varchar(32) DEFAULT NULL COMMENT '更新人', | |
40 | + `update_time` datetime DEFAULT NULL COMMENT '更新时间', | |
41 | + PRIMARY KEY (`id`) USING BTREE, | |
42 | + KEY `index_table_userid` (`userid`) USING BTREE, | |
43 | + KEY `index_logt_ype` (`log_type`) USING BTREE, | |
44 | + KEY `index_operate_type` (`operate_type`) USING BTREE, | |
45 | + KEY `index_createtime` (`create_time`) USING BTREE | |
46 | +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统日志表'; | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
5 | + <parent> | |
6 | + <artifactId>jeecg-cloud-test</artifactId> | |
7 | + <groupId>org.jeecgframework.boot</groupId> | |
8 | + <version>3.1.0</version> | |
9 | + </parent> | |
10 | + <modelVersion>4.0.0</modelVersion> | |
11 | + | |
12 | + <artifactId>jeecg-cloud-test-shardingsphere</artifactId> | |
13 | + | |
14 | + <dependencies> | |
15 | + <dependency> | |
16 | + <groupId>org.jeecgframework.boot</groupId> | |
17 | + <artifactId>jeecg-boot-starter-shardingsphere</artifactId> | |
18 | + <version>3.1.0</version> | |
19 | + </dependency> | |
20 | + </dependencies> | |
21 | + | |
22 | +</project> | |
0 | 23 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/algorithm/StandardModTableShardAlgorithm.java
0 → 100644
1 | +package org.jeecg.modules.test.sharding.algorithm; | |
2 | + | |
3 | + | |
4 | +import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue; | |
5 | +import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue; | |
6 | +import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm; | |
7 | + | |
8 | +import java.util.Collection; | |
9 | +import java.util.Properties; | |
10 | + | |
11 | +/** | |
12 | + * 用于处理使用单一键 | |
13 | + * 根据分片字段的值和sharding-count进行取模运算 | |
14 | + * SQL 语句中有>,>=, <=,<,=,IN 和 BETWEEN AND 操作符,都可以应用此分片策略。 | |
15 | + * | |
16 | + * @author zyf | |
17 | + */ | |
18 | +public class StandardModTableShardAlgorithm implements StandardShardingAlgorithm<Integer> { | |
19 | + private Properties props = new Properties(); | |
20 | + | |
21 | + | |
22 | + /** | |
23 | + * 用于处理=和IN的分片 | |
24 | + * | |
25 | + * @param collection 目标分片的集合(表名) | |
26 | + * @param preciseShardingValue 逻辑表相关信息 | |
27 | + * @return | |
28 | + */ | |
29 | + @Override | |
30 | + public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) { | |
31 | + | |
32 | + for (String name : collection) { | |
33 | + Integer value = preciseShardingValue.getValue(); | |
34 | + //根据值进行取模,得到一个目标值 | |
35 | + if (name.indexOf(value % 2+"") > -1) { | |
36 | + return name; | |
37 | + } | |
38 | + } | |
39 | + throw new UnsupportedOperationException(); | |
40 | + } | |
41 | + | |
42 | + /** | |
43 | + * 用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理 | |
44 | + * | |
45 | + * @param collection | |
46 | + * @param rangeShardingValue | |
47 | + * @return | |
48 | + */ | |
49 | + @Override | |
50 | + public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Integer> rangeShardingValue) { | |
51 | + | |
52 | + return collection; | |
53 | + } | |
54 | + | |
55 | + /** | |
56 | + * 初始化对象的时候调用的方法 | |
57 | + */ | |
58 | + @Override | |
59 | + public void init() { | |
60 | + } | |
61 | + | |
62 | + /** | |
63 | + * 对应分片算法(sharding-algorithms)的类型 | |
64 | + * | |
65 | + * @return | |
66 | + */ | |
67 | + @Override | |
68 | + public String getType() { | |
69 | + return "STANDARD_MOD"; | |
70 | + } | |
71 | + | |
72 | + @Override | |
73 | + public Properties getProps() { | |
74 | + return this.props; | |
75 | + } | |
76 | + | |
77 | + /** | |
78 | + * 获取分片相关属性 | |
79 | + * | |
80 | + * @param properties | |
81 | + */ | |
82 | + @Override | |
83 | + public void setProps(Properties properties) { | |
84 | + this.props = properties; | |
85 | + } | |
86 | +} | |
0 | 87 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/controller/JeecgShardingDemoController.java
0 → 100644
1 | +package org.jeecg.modules.test.sharding.controller; | |
2 | + | |
3 | +import org.jeecg.common.api.vo.Result; | |
4 | +import org.jeecg.common.aspect.annotation.AutoLog; | |
5 | +import org.jeecg.common.system.base.controller.JeecgController; | |
6 | +import org.jeecg.modules.test.sharding.entity.ShardingSysLog; | |
7 | +import org.jeecg.modules.test.sharding.service.IShardingSysLogService; | |
8 | +import org.springframework.beans.factory.annotation.Autowired; | |
9 | +import org.springframework.web.bind.annotation.PostMapping; | |
10 | +import org.springframework.web.bind.annotation.RequestMapping; | |
11 | +import org.springframework.web.bind.annotation.RestController; | |
12 | + | |
13 | +import io.swagger.annotations.Api; | |
14 | +import io.swagger.annotations.ApiOperation; | |
15 | +import lombok.extern.slf4j.Slf4j; | |
16 | + | |
17 | +/** | |
18 | + * @Description: 分库分表测试 | |
19 | + * @author: zyf | |
20 | + * @date: 2022/01/24 | |
21 | + * @version: V1.0 | |
22 | + */ | |
23 | +@Slf4j | |
24 | +@Api(tags = "分库分表测试") | |
25 | +@RestController | |
26 | +@RequestMapping("/sharding/") | |
27 | +public class JeecgShardingDemoController extends JeecgController<ShardingSysLog, IShardingSysLogService> { | |
28 | + @Autowired | |
29 | + private IShardingSysLogService shardingSysLogService; | |
30 | + | |
31 | + /** | |
32 | + * 添加 | |
33 | + * @return | |
34 | + */ | |
35 | + @PostMapping(value = "/add") | |
36 | + @AutoLog(value = "分库分表添加") | |
37 | + @ApiOperation(value = "分库分表添加", notes = "分库分表添加") | |
38 | + public Result<?> add() { | |
39 | + for (int i = 0; i < 10; i++) { | |
40 | + ShardingSysLog shardingSysLog = new ShardingSysLog(); | |
41 | + shardingSysLog.setLogContent("jeecg"); | |
42 | + shardingSysLog.setLogType(i); | |
43 | + shardingSysLog.setOperateType(i); | |
44 | + shardingSysLogService.save(shardingSysLog); | |
45 | + } | |
46 | + return Result.OK(); | |
47 | + } | |
48 | + | |
49 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/entity/ShardingSysLog.java
0 → 100644
1 | +package org.jeecg.modules.test.sharding.entity; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.annotation.IdType; | |
4 | +import com.baomidou.mybatisplus.annotation.TableId; | |
5 | +import com.baomidou.mybatisplus.annotation.TableName; | |
6 | +import com.fasterxml.jackson.annotation.JsonFormat; | |
7 | +import lombok.Data; | |
8 | +import lombok.EqualsAndHashCode; | |
9 | +import lombok.experimental.Accessors; | |
10 | +import org.jeecg.common.aspect.annotation.Dict; | |
11 | +import org.springframework.format.annotation.DateTimeFormat; | |
12 | + | |
13 | +import java.io.Serializable; | |
14 | +import java.util.Date; | |
15 | + | |
16 | +/** | |
17 | + * <p> | |
18 | + * 系统日志表 | |
19 | + * </p> | |
20 | + */ | |
21 | +@Data | |
22 | +@TableName("sys_log") | |
23 | +public class ShardingSysLog implements Serializable { | |
24 | + | |
25 | + private static final long serialVersionUID = 1L; | |
26 | + | |
27 | + /** | |
28 | + * id | |
29 | + */ | |
30 | + @TableId(type = IdType.ASSIGN_ID) | |
31 | + private String id; | |
32 | + | |
33 | + /** | |
34 | + * 创建人 | |
35 | + */ | |
36 | + private String createBy; | |
37 | + | |
38 | + /** | |
39 | + * 创建时间 | |
40 | + */ | |
41 | + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") | |
42 | + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") | |
43 | + private Date createTime; | |
44 | + | |
45 | + /** | |
46 | + * 更新人 | |
47 | + */ | |
48 | + private String updateBy; | |
49 | + | |
50 | + /** | |
51 | + * 更新时间 | |
52 | + */ | |
53 | + private Date updateTime; | |
54 | + | |
55 | + /** | |
56 | + * 耗时 | |
57 | + */ | |
58 | + private Long costTime; | |
59 | + | |
60 | + /** | |
61 | + * IP | |
62 | + */ | |
63 | + private String ip; | |
64 | + | |
65 | + /** | |
66 | + * 请求参数 | |
67 | + */ | |
68 | + private String requestParam; | |
69 | + | |
70 | + /** | |
71 | + * 请求类型 | |
72 | + */ | |
73 | + private String requestType; | |
74 | + | |
75 | + /** | |
76 | + * 请求路径 | |
77 | + */ | |
78 | + private String requestUrl; | |
79 | + /** | |
80 | + * 请求方法 | |
81 | + */ | |
82 | + private String method; | |
83 | + | |
84 | + /** | |
85 | + * 操作人用户名称 | |
86 | + */ | |
87 | + private String username; | |
88 | + /** | |
89 | + * 操作人用户账户 | |
90 | + */ | |
91 | + private String userid; | |
92 | + /** | |
93 | + * 操作详细日志 | |
94 | + */ | |
95 | + private String logContent; | |
96 | + | |
97 | + /** | |
98 | + * 日志类型(1登录日志,2操作日志) | |
99 | + */ | |
100 | + @Dict(dicCode = "log_type") | |
101 | + private Integer logType; | |
102 | + | |
103 | + /** | |
104 | + * 操作类型(1查询,2添加,3修改,4删除,5导入,6导出) | |
105 | + */ | |
106 | + @Dict(dicCode = "operate_type") | |
107 | + private Integer operateType; | |
108 | + | |
109 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/ShardingSysLogMapper.java
0 → 100644
1 | +package org.jeecg.modules.test.sharding.mapper; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.core.mapper.BaseMapper; | |
4 | +import org.jeecg.modules.test.sharding.entity.ShardingSysLog; | |
5 | + | |
6 | + | |
7 | +/** | |
8 | + * @Description: 系统日志表 Mapper 接口 | |
9 | + * @author: zyf | |
10 | + * @date: 2022/01/24 | |
11 | + * @version: V1.0 | |
12 | + */ | |
13 | +public interface ShardingSysLogMapper extends BaseMapper<ShardingSysLog> { | |
14 | + | |
15 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/xml/ShardingSysLogMapper.xml
0 → 100644
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/IShardingSysLogService.java
0 → 100644
1 | +package org.jeecg.modules.test.sharding.service; | |
2 | + | |
3 | +import com.baomidou.mybatisplus.extension.service.IService; | |
4 | +import org.jeecg.modules.test.sharding.entity.ShardingSysLog; | |
5 | + | |
6 | +/** | |
7 | + * @Description: 系统日志表 服务类 | |
8 | + * @author: zyf | |
9 | + * @date: 2022/01/24 | |
10 | + * @version: V1.0 | |
11 | + */ | |
12 | +public interface IShardingSysLogService extends IService<ShardingSysLog> { | |
13 | + | |
14 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/impl/ShardingSysLogServiceImpl.java
0 → 100644
1 | +package org.jeecg.modules.test.sharding.service.impl; | |
2 | + | |
3 | +import com.baomidou.dynamic.datasource.annotation.DS; | |
4 | +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; | |
5 | +import org.jeecg.modules.test.sharding.entity.ShardingSysLog; | |
6 | +import org.jeecg.modules.test.sharding.mapper.ShardingSysLogMapper; | |
7 | +import org.jeecg.modules.test.sharding.service.IShardingSysLogService; | |
8 | +import org.springframework.stereotype.Service; | |
9 | + | |
10 | +/** | |
11 | + * <p> | |
12 | + * 系统日志表 服务实现类 | |
13 | + * </p> | |
14 | + */ | |
15 | +@Service | |
16 | +@DS("sharding") | |
17 | +public class ShardingSysLogServiceImpl extends ServiceImpl<ShardingSysLogMapper, ShardingSysLog> implements IShardingSysLogService { | |
18 | + | |
19 | +} | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/resources/application-sharding.yml
0 → 100644
1 | +spring: | |
2 | + shardingsphere: | |
3 | + props: | |
4 | + sql-show: true | |
5 | + datasource: | |
6 | + ds0: | |
7 | + driverClassName: com.mysql.cj.jdbc.Driver | |
8 | + url: jdbc:mysql://localhost:3306/jeecg-boot?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai | |
9 | + username: root | |
10 | + type: com.alibaba.druid.pool.DruidDataSource | |
11 | + password: root | |
12 | + names: ds0 | |
13 | + # 规则配置 | |
14 | + rules: | |
15 | + sharding: | |
16 | + # 配置绑定表,每一行为一组 | |
17 | + binding-tables: sys_log | |
18 | + # 分布式序列算法配置 | |
19 | + key-generators: | |
20 | + snowflake: | |
21 | + type: SNOWFLAKE | |
22 | + props: | |
23 | + worker-id: 123 | |
24 | + # 分片算法配置 | |
25 | + sharding-algorithms: | |
26 | + table-classbased: | |
27 | + props: | |
28 | + strategy: standard | |
29 | + algorithmClassName: org.jeecg.modules.test.sharding.algorithm.StandardModTableShardAlgorithm | |
30 | + type: CLASS_BASED | |
31 | + tables: | |
32 | + # 逻辑表名称 | |
33 | + sys_log: | |
34 | + #配置具体表的数据节点 | |
35 | + actual-data-nodes: ds0.sys_log$->{0..1} | |
36 | + # 分表策略 | |
37 | + table-strategy: | |
38 | + standard: | |
39 | + # 分片算法名称 | |
40 | + sharding-algorithm-name: table-classbased | |
41 | + # 分片列名称 | |
42 | + sharding-column: log_type | |
0 | 43 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | |
2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | |
3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |
5 | + <parent> | |
6 | + <artifactId>jeecg-cloud-module</artifactId> | |
7 | + <groupId>org.jeecgframework.boot</groupId> | |
8 | + <version>3.1.0</version> | |
9 | + </parent> | |
10 | + | |
11 | + <modelVersion>4.0.0</modelVersion> | |
12 | + <packaging>pom</packaging> | |
13 | + <artifactId>jeecg-cloud-test</artifactId> | |
14 | + | |
15 | + <dependencies> | |
16 | + <dependency> | |
17 | + <groupId>org.jeecgframework.boot</groupId> | |
18 | + <artifactId>jeecg-boot-base-core</artifactId> | |
19 | + </dependency> | |
20 | + </dependencies> | |
21 | + | |
22 | + <modules> | |
23 | + <module>jeecg-cloud-test-seata</module> | |
24 | + <module>jeecg-cloud-test-shardingsphere</module> | |
25 | + </modules> | |
26 | +</project> | |
0 | 27 | \ No newline at end of file |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile
... | ... | @@ -10,7 +10,7 @@ WORKDIR /jeecg-cloud-xxljob |
10 | 10 | |
11 | 11 | EXPOSE 9080 |
12 | 12 | |
13 | -ADD ./target/jeecg-cloud-xxljob-3.0.jar ./ | |
13 | +ADD ./target/jeecg-cloud-xxljob-3.1.0.jar ./ | |
14 | 14 | |
15 | -CMD java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-xxljob-3.0.jar | |
15 | +CMD java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-xxljob-3.1.0.jar | |
16 | 16 | |
... | ... |
jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml
jeecg-boot/jeecg-cloud-module/pom.xml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <parent> |
6 | 6 | <artifactId>jeecg-boot-parent</artifactId> |
7 | 7 | <groupId>org.jeecgframework.boot</groupId> |
8 | - <version>3.0</version> | |
8 | + <version>3.1.0</version> | |
9 | 9 | </parent> |
10 | 10 | <modelVersion>4.0.0</modelVersion> |
11 | 11 | |
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | <module>jeecg-cloud-monitor</module> |
19 | 19 | <module>jeecg-cloud-system-start</module> |
20 | 20 | <module>jeecg-cloud-xxljob</module> |
21 | + <module>jeecg-cloud-test</module> | |
21 | 22 | </modules> |
22 | 23 | |
23 | 24 | |
... | ... |
jeecg-boot/pom.xml
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | <modelVersion>4.0.0</modelVersion> |
3 | 3 | <groupId>org.jeecgframework.boot</groupId> |
4 | 4 | <artifactId>jeecg-boot-parent</artifactId> |
5 | - <version>3.0</version> | |
5 | + <version>3.1.0</version> | |
6 | 6 | <packaging>pom</packaging> |
7 | 7 | |
8 | 8 | <parent> |
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | </parent> |
14 | 14 | |
15 | 15 | <properties> |
16 | - <jeecgboot.version>3.0</jeecgboot.version> | |
16 | + <jeecgboot.version>3.1.0</jeecgboot.version> | |
17 | 17 | <java.version>1.8</java.version> |
18 | 18 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
19 | 19 | <spring-cloud.version>Hoxton.SR8</spring-cloud.version> |
... | ... | @@ -42,12 +42,12 @@ |
42 | 42 | <java-jwt.version>3.11.0</java-jwt.version> |
43 | 43 | <shiro-redis.version>3.1.0</shiro-redis.version> |
44 | 44 | <codegenerate.version>1.3.7</codegenerate.version> |
45 | - <autopoi-web.version>1.3.6</autopoi-web.version> | |
45 | + <autopoi-web.version>1.3.9</autopoi-web.version> | |
46 | 46 | <minio.version>8.0.3</minio.version> |
47 | 47 | <justauth-spring-boot-starter.version>1.3.4</justauth-spring-boot-starter.version> |
48 | 48 | <dom4j.version>1.6.1</dom4j.version> |
49 | 49 | <qiniu-java-sdk.version>7.4.0</qiniu-java-sdk.version> |
50 | - <!-- Log4j2惊爆0Day漏洞--> | |
50 | + <!-- Log4j2爆雷漏洞 --> | |
51 | 51 | <log4j2.version>2.17.0</log4j2.version> |
52 | 52 | <logback.version>1.2.9</logback.version> |
53 | 53 | </properties> |
... | ... | @@ -366,6 +366,10 @@ |
366 | 366 | <config.server-addr>127.0.0.1:8848</config.server-addr> |
367 | 367 | <!--Nacos配置中心命名空间,用于支持多环境.这里必须使用ID,不能使用名称,默认为空--> |
368 | 368 | <config.namespace></config.namespace> |
369 | + <!--Nacos用户名--> | |
370 | + <config.username>nacos</config.username> | |
371 | + <!--Nacos密码--> | |
372 | + <config.password>nacos</config.password> | |
369 | 373 | <!--Nacos配置分组名称--> |
370 | 374 | <config.group>DEFAULT_GROUP</config.group> |
371 | 375 | <!--Nacos服务发现地址--> |
... | ... | @@ -384,6 +388,10 @@ |
384 | 388 | <config.server-addr>127.0.0.1:8848</config.server-addr> |
385 | 389 | <!--Nacos配置中心命名空间,用于支持多环境.这里必须使用ID,不能使用名称,默认为空--> |
386 | 390 | <config.namespace></config.namespace> |
391 | + <!--Nacos用户名--> | |
392 | + <config.username>nacos</config.username> | |
393 | + <!--Nacos密码--> | |
394 | + <config.password>nacos</config.password> | |
387 | 395 | <!--Nacos配置分组名称--> |
388 | 396 | <config.group>DEFAULT_GROUP</config.group> |
389 | 397 | <!--Nacos服务发现地址--> |
... | ... | @@ -402,6 +410,10 @@ |
402 | 410 | <config.server-addr>127.0.0.1:8848</config.server-addr> |
403 | 411 | <!--Nacos配置中心命名空间,用于支持多环境.这里必须使用ID,不能使用名称,默认为空--> |
404 | 412 | <config.namespace></config.namespace> |
413 | + <!--Nacos用户名--> | |
414 | + <config.username>nacos</config.username> | |
415 | + <!--Nacos密码--> | |
416 | + <config.password>nacos</config.password> | |
405 | 417 | <!--Nacos配置分组名称--> |
406 | 418 | <config.group>DEFAULT_GROUP</config.group> |
407 | 419 | <!--Nacos服务发现地址--> |
... | ... |