diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e5eba51 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.run/ +/ruoyi-admin/logs/ +/ruoyi-admin/target/ +/ruoyi-common/*/target/ +/ruoyi-extend/*/target/ +/ruoyi-modules/*/target/ +/logs/ +.idea diff --git a/file/log/centerBooksAdd_1922120835237036033_179.txt b/file/log/centerBooksAdd_1922120835237036033_179.txt new file mode 100644 index 0000000..9ea35cf --- /dev/null +++ b/file/log/centerBooksAdd_1922120835237036033_179.txt @@ -0,0 +1,83 @@ + +【2025-09-12 16:42:03】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-12 16:42:03】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1966422039778070530","taskType":"1","shopIds":"1950426101074288642","shopNames":"古威音像专营店","fileName":"excel表格上传:发布商品.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1950426101074288642","data":{"total":5,"fileName":"发布商品.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a49d39cd-f586-48db-bcd2-f39954aedadb_发布商品.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-12 16:42:03】【系统异常】【异常方法】addGoods +【2025-09-12 16:42:03】【系统异常】【异常内容】org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request on POST request for "http://localhost:16001/huidiao/pdd/addGoods": "{"code":400,"msg":"taskId参数不能为空","data":null}" + at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:103) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:186) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:147) + at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:953) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:902) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:162) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:219) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) + +【2025-09-12 16:42:03】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-12 16:44:17】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-12 16:44:17】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1966422601206657025","taskType":"1","shopIds":"1950426101074288642","shopNames":"古威音像专营店","fileName":"excel表格上传:发布商品.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1950426101074288642","data":{"total":5,"fileName":"发布商品.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/e9850515-b6d0-4edd-a0df-47597e0e1679_发布商品.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-12 16:45:02】【系统异常】【异常方法】addGoods +【2025-09-12 16:45:02】【系统异常】【异常内容】org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request on POST request for "http://localhost:16001/huidiao/pdd/addGoods": "{"code":400,"msg":"taskId参数不能为空","data":null}" + at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:103) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:186) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:147) + at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:953) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:902) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:162) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:219) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) + +【2025-09-12 16:45:02】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-12 16:46:53】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-12 16:46:53】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1966423256906452994","taskType":"1","shopIds":"1950426101074288642","shopNames":"古威音像专营店","fileName":"excel表格上传:发布商品.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1950426101074288642","data":{"total":5,"fileName":"发布商品.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/938cddf9-3fe6-4e69-ac9d-08d0d465fe2b_发布商品.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-12 16:46:59】【返回参数】null +【2025-09-12 16:46:59】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods \ No newline at end of file diff --git a/file/log/centerBooksAdd_1922120835237036033_412.txt b/file/log/centerBooksAdd_1922120835237036033_412.txt new file mode 100644 index 0000000..d97a1fe --- /dev/null +++ b/file/log/centerBooksAdd_1922120835237036033_412.txt @@ -0,0 +1,9 @@ + +【2025-09-24 10:19:26】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-24 10:19:26】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1970674404790181890","taskType":"1","shopIds":"1969343852652916737","shopNames":"测试咸鱼B","fileName":"excel表格上传:task_template_1758680286171.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1969343852652916737","data":{"total":2,"fileName":"task_template_1758680286171.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4846c4c8-b5e4-4bad-b774-70c782989cdc_task_template_1758680286171.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-24 10:19:26】【返回参数】null +【2025-09-24 10:19:26】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-24 10:49:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-24 10:49:40】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1970682012628492289","taskType":"1","shopIds":"1969343852652916737","shopNames":"测试咸鱼B","fileName":"excel表格上传:task_template_1758680286171.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1969343852652916737","data":{"total":2,"fileName":"task_template_1758680286171.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ade02a9e-1b3f-47b5-8cd0-de6d58ce15e9_task_template_1758680286171.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-24 10:49:40】【返回参数】null +【2025-09-24 10:49:40】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods \ No newline at end of file diff --git a/file/log/centerBooksAdd_1922120835237036033_426.txt b/file/log/centerBooksAdd_1922120835237036033_426.txt new file mode 100644 index 0000000..7d43b74 --- /dev/null +++ b/file/log/centerBooksAdd_1922120835237036033_426.txt @@ -0,0 +1,9 @@ + +【2025-09-26 14:34:54】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-26 14:34:54】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1971463472444612609","taskType":"1","shopIds":"1950426101074288642","shopNames":"古威音像专营店","fileName":"excel表格上传:task_template_1758680286171.xlsx","dataNum":6,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"1","bookCategory":"0","shopIds":"1950426101074288642","data":{"total":6,"fileName":"task_template_1758680286171.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f21d67f0-4f18-4262-a8dc-581a9585075a_task_template_1758680286171.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-26 14:36:57】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-26 14:36:57】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1971463986884431874","taskType":"1","shopIds":"1950426101074288642","shopNames":"古威音像专营店","fileName":"excel表格上传:task_template_1758680286171.xlsx","dataNum":6,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1950426101074288642","data":{"total":6,"fileName":"task_template_1758680286171.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/fff1d06c-2ae0-41b4-91db-436acd3f4514_task_template_1758680286171.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-30 09:35:42】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-30 09:35:42】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1972837725932933122","taskType":"1","shopIds":"1972584272471408642","shopNames":"咸鱼-与书","fileName":"excel表格上传:task_template_1759135960072.xlsx","dataNum":3,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1972584272471408642","data":{"total":3,"fileName":"task_template_1759135960072.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/117f4be8-f6c5-42b6-aa4d-0efbe85156f5_task_template_1759135960072.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1922120835237036033"} +【2025-09-30 09:35:45】【返回参数】null +【2025-09-30 09:35:45】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods \ No newline at end of file diff --git a/file/log/centerBooksAdd_1922120835237036033_528.txt b/file/log/centerBooksAdd_1922120835237036033_528.txt new file mode 100644 index 0000000..3e03eeb --- /dev/null +++ b/file/log/centerBooksAdd_1922120835237036033_528.txt @@ -0,0 +1,505 @@ + +【2026-03-10 10:41:50】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 10:41:50】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":5,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/edc618cb-e314-4d78-b42d-a91901cceb56_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031198802537304066\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-10 10:42:04】【返回参数】null +【2026-03-10 10:42:04】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 10:45:13】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 10:45:13】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/9a8dcb84-4208-4182-a8f4-8be5d5f63fc1_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031199655822315521\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-10 11:02:45】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 11:02:45】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/2006cdcc-e7b2-477b-bfb2-508ed917c365_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031204066179108866\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-10 11:04:16】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 11:04:16】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/52c54894-830c-44bb-a683-1ae46287e465_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031204449580437506\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-10 15:17:41】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 15:17:41】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/757d04a7-df86-4a9a-959c-3de34bc7459d_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031268236266221570\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-10 15:17:56】【系统异常】【异常方法】addGoods +【2026-03-10 15:17:56】【系统异常】【异常内容】org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request on POST request for "http://36.212.20.113:8182/api/goods/simple": "{"code":400,"message":"shopid和isbn不能为空","success":false}" + at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:103) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:186) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:147) + at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:953) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:902) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:251) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) + +【2026-03-10 15:17:56】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 15:18:14】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 15:18:14】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/54a70299-eb39-43f9-b726-32964f9d1c0d_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031268371826126849\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-10 15:18:53】【系统异常】【异常方法】addGoods +【2026-03-10 15:18:53】【系统异常】【异常内容】org.springframework.web.client.HttpClientErrorException$BadRequest: 400 Bad Request on POST request for "http://36.212.20.113:8182/api/goods/simple": "{"code":400,"message":"shopid和isbn不能为空","success":false}" + at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:103) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:186) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:147) + at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:953) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:902) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:251) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) + +【2026-03-10 15:18:53】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 15:20:10】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 15:20:10】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b4ceb153-1151-498f-9d7c-5c44b686048c_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031268858075983874\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-10 15:23:45】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 15:23:45】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d3c3a434-66d5-4926-b299-697fb57e1b97_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2031269763131289602\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 11:49:23】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 11:49:23】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/3e1aca3d-ee2a-4fcd-8222-741e4976060f_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2031578199664582658\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 11:56:16】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 11:56:16】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b16816c2-6a67-4fb0-8412-d13932127937_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031579932725829634\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 11:57:48】【返回参数】null +【2026-03-11 11:57:48】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:06:06】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:06:06】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/8154c95b-49a7-4abb-ad57-aca463465197_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031597508189184001\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:06:39】【返回参数】null +【2026-03-11 13:06:39】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:11:49】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:11:49】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b3d32db8-f407-4ef5-9cf2-30452fa01b23_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031598944276930561\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:12:16】【返回参数】null +【2026-03-11 13:12:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:13:56】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:13:57】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a93fd262-827b-496b-a101-c859c4055275_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031599480594194433\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:14:08】【返回参数】null +【2026-03-11 13:14:08】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:19:22】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:19:22】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/cba5c4e9-8a3c-4f12-9081-935e558b60c0_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031600837287960578\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:19:42】【返回参数】null +【2026-03-11 13:19:42】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:28:08】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:28:08】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/44748e83-c690-412b-bc69-32c2a99236f8_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2031603053692411906\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:28:58】【返回参数】null +【2026-03-11 13:28:58】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:30:17】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:30:17】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/8988633a-a17d-492e-9d84-216922f317b9_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031603593130237954\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:37:13】【返回参数】null +【2026-03-11 13:37:13】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:38:31】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:38:31】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c306572e-806c-400b-b74c-bf10918af179_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031605666571837441\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:39:03】【返回参数】null +【2026-03-11 13:39:03】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:45:07】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:45:07】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b0b22d40-0786-48d6-88f2-100c56de4dbc_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031607327323283457\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:47:02】【返回参数】null +【2026-03-11 13:47:02】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:48:18】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:48:18】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b5ccee78-9fdc-43b2-befd-6024e88c1cb6_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031608125490946049\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:51:14】【返回参数】null +【2026-03-11 13:51:14】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:52:48】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:52:48】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/6567e176-543b-443f-ad1b-de074fd6ed4e_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2031609259815297026\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:54:39】【返回参数】null +【2026-03-11 13:54:39】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:55:54】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:55:54】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a13d29e6-07ed-44de-a288-89f0d141c385_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031610038005489665\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 13:56:08】【返回参数】null +【2026-03-11 13:56:08】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:56:54】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 13:56:54】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/1f88128b-844a-4338-b72a-de3752797227_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2031610292738154498\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 14:01:07】【返回参数】null +【2026-03-11 14:01:07】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 14:02:45】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 14:02:45】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a25752e5-d676-49f0-a886-5676fa417800_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2031611765333123073\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 14:02:59】【返回参数】null +【2026-03-11 14:02:59】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 14:10:55】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-11 14:10:55】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ca7e431b-db89-42f9-9fce-a118e24777f5_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2031613817295691777\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-11 14:10:55】【返回参数】null +【2026-03-11 14:10:55】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:28:20】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:28:20】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0078d6dc-0376-4923-870a-30dc1895cee6_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2032040987478331394\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-12 18:28:23】【系统异常】【异常方法】addGoods +【2026-03-12 18:28:23】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://36.212.20.113:8182/api/goods/simple": Connection refused: no further information + at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:926) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:906) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) +Caused by: java.net.ConnectException: Connection refused: no further information + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) + at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:554) + at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) + at java.base/java.net.Socket.connect(Socket.java:633) + at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:534) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:639) + at java.base/sun.net.www.http.HttpClient.(HttpClient.java:282) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:387) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:409) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1308) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1241) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1127) + at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1056) + at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79) + at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:71) + at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900) + ... 28 more + +【2026-03-12 18:28:23】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:31:42】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:31:42】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/deb13d5a-0421-422f-944d-744da141a4e7_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2032041836002807810\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-12 18:31:45】【系统异常】【异常方法】addGoods +【2026-03-12 18:31:45】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://36.212.20.113:8182/api/goods/simple": Connection refused: no further information + at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:926) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:906) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) +Caused by: java.net.ConnectException: Connection refused: no further information + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) + at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:554) + at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) + at java.base/java.net.Socket.connect(Socket.java:633) + at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:534) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:639) + at java.base/sun.net.www.http.HttpClient.(HttpClient.java:282) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:387) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:409) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1308) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1241) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1127) + at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1056) + at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79) + at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:71) + at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900) + ... 28 more + +【2026-03-12 18:31:45】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:33:04】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:33:04】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d50eaeb5-592d-4412-8230-902ba2adfa5b_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2032042179696660482\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-12 18:33:07】【系统异常】【异常方法】addGoods +【2026-03-12 18:33:07】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://36.212.20.113:8182/api/goods/simple": Connection refused: no further information + at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:926) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:906) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) +Caused by: java.net.ConnectException: Connection refused: no further information + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) + at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:554) + at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) + at java.base/java.net.Socket.connect(Socket.java:633) + at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:534) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:639) + at java.base/sun.net.www.http.HttpClient.(HttpClient.java:282) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:387) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:409) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1308) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1241) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1127) + at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1056) + at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79) + at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:71) + at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900) + ... 28 more + +【2026-03-12 18:33:07】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:35:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:35:30】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":99,"fileName":"测试.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/96a41f23-a8e2-4c4d-9348-4eea95a1217f_测试.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2032042728559087617\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-12 18:35:42】【系统异常】【异常方法】addGoods +【2026-03-12 18:35:42】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://36.212.20.113:8182/api/goods/simple": Connection refused: no further information + at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:926) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:906) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) +Caused by: java.net.ConnectException: Connection refused: no further information + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) + at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:554) + at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) + at java.base/java.net.Socket.connect(Socket.java:633) + at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:534) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:639) + at java.base/sun.net.www.http.HttpClient.(HttpClient.java:282) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:387) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:409) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1308) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1241) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1127) + at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1056) + at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79) + at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:71) + at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900) + ... 28 more + +【2026-03-12 18:35:42】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:41:23】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:41:23】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":99,"fileName":"测试.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/71b0a7dd-63b4-4d02-b8e9-18ff5bb565b5_测试.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2032043516362625025\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-12 18:43:28】【系统异常】【异常方法】addGoods +【2026-03-12 18:43:28】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://36.212.20.113:8182/api/goods/simple": Connection refused: no further information + at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:926) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:906) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) +Caused by: java.net.ConnectException: Connection refused: no further information + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) + at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:554) + at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) + at java.base/java.net.Socket.connect(Socket.java:633) + at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:534) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:639) + at java.base/sun.net.www.http.HttpClient.(HttpClient.java:282) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:387) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:409) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1308) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1241) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1127) + at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1056) + at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79) + at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:71) + at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900) + ... 28 more + +【2026-03-12 18:43:28】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:45:36】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:45:36】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/45f786a2-c38a-4683-b531-f0efd0fb3f5d_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2032045336577314818\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-12 18:54:07】【系统异常】【异常方法】addGoods +【2026-03-12 18:54:07】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://36.212.20.113:8182/api/goods/simple": Connection refused: no further information + at org.springframework.web.client.RestTemplate.createResourceAccessException(RestTemplate.java:926) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:906) + at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:801) + at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:549) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:249) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:257) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:89) + at org.dromara.zhishu.util.RunningLogUtils.runningLog(RunningLogUtils.java:42) + at org.dromara.zhishu.aspect.CenterAspect.addGoods(CenterAspect.java:88) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) + at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + at java.base/java.lang.reflect.Method.invoke(Method.java:568) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:638) + at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:628) + at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:71) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727) + at org.dromara.zhishu.service.impl.TaskServiceImpl$$SpringCGLIB$$0.addGoods() + at org.dromara.zhishu.util.TaskRunnable.run(TaskRunnable.java:39) + at java.base/java.lang.Thread.run(Thread.java:842) +Caused by: java.net.ConnectException: Connection refused: no further information + at java.base/sun.nio.ch.Net.pollConnect(Native Method) + at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) + at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:554) + at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:602) + at java.base/java.net.Socket.connect(Socket.java:633) + at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:178) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:534) + at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:639) + at java.base/sun.net.www.http.HttpClient.(HttpClient.java:282) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:387) + at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:409) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1308) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1241) + at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1127) + at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1056) + at org.springframework.http.client.SimpleClientHttpRequest.executeInternal(SimpleClientHttpRequest.java:79) + at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:71) + at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:81) + at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:900) + ... 28 more + +【2026-03-12 18:54:07】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:54:32】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-12 18:54:32】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d9d2150a-fd73-437d-8e0f-3fa7575c8c1c_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031193954362281985","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2032047582354477058\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-03-12 18:54:49】【返回参数】null +【2026-03-12 18:54:49】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-09 10:06:42】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-09 10:06:42】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":null,"taskType":null,"shopIds":null,"shopNames":null,"fileName":null,"dataNum":null,"taskStatus":null,"status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1922120835237036033","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/be0b550a-666f-4226-be61-2a7301a586b3_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2037060396836171778","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2042061610371973122\",\"msg\":\"成功\"}\n"},"userId":"1922120835237036033"} +【2026-04-09 10:06:56】【返回参数】null +【2026-04-09 10:06:56】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods \ No newline at end of file diff --git a/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java new file mode 100644 index 0000000..e8f0ff8 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java @@ -0,0 +1,26 @@ +package org.dromara; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +/** + * 启动程序 + * + * @author Lion Li + */ + +@SpringBootApplication +@EntityScan("org.dromara.zhishu.domain.bo") // 添加这行 +@EnableJpaRepositories("org.dromara.zhishu.util") // 确保扫描到Repository +public class DromaraApplication { + public static void main(String[] args) { + SpringApplication application = new SpringApplication(DromaraApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println("(♥◠‿◠)ノ゙ RuoYi-Vue-Plus启动成功 ლ(´ڡ`ლ)゙"); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java new file mode 100644 index 0000000..c444f28 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java @@ -0,0 +1,32 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import org.dromara.common.core.config.RuoYiConfig; +import org.dromara.common.core.utils.StringUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 首页 + * + * @author Lion Li + */ +@SaIgnore +@RequiredArgsConstructor +@RestController +public class IndexController { + + /** + * 系统基础配置 + */ + private final RuoYiConfig ruoyiConfig; + + /** + * 访问首页,提示语 + */ + @GetMapping("/") + public String index() { + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); + } +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java new file mode 100644 index 0000000..664df1e --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java @@ -0,0 +1,25 @@ +package org.dromara.web.domain.vo; + +import lombok.Data; + +/** + * 验证码信息 + * + * @author Michelle.Chung + */ +@Data +public class CaptchaVo { + + /** + * 是否开启验证码 + */ + private Boolean captchaEnabled = true; + + private String uuid; + + /** + * 验证码图片 + */ + private String img; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java new file mode 100644 index 0000000..b944d24 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java @@ -0,0 +1,58 @@ +package org.dromara.web.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 登录验证信息 + * + * @author Michelle.Chung + */ +@Data +public class LoginVo { + + /** + * 授权令牌 + */ + @JsonProperty("access_token") + private String accessToken; + + /** + * 刷新令牌 + */ + @JsonProperty("refresh_token") + private String refreshToken; + + /** + * 授权令牌 access_token 的有效期 + */ + @JsonProperty("expire_in") + private Long expireIn; + + /** + * 刷新令牌 refresh_token 的有效期 + */ + @JsonProperty("refresh_expire_in") + private Long refreshExpireIn; + + /** + * 应用id + */ + @JsonProperty("client_id") + private String clientId; + + /** + * 令牌权限 + */ + private String scope; + + /** + * 用户 openid + */ + private String openid; + + private String phoneNumber; + private String nickName; + private Long userId; + private String userName; +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/dto/UserLoginDTO.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/dto/UserLoginDTO.java new file mode 100644 index 0000000..43b32e1 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/dto/UserLoginDTO.java @@ -0,0 +1,11 @@ +package org.dromara.web.domain.vo.dto; + +import lombok.Data; + +import java.io.Serializable; +@Data +public class UserLoginDTO implements Serializable { + + private String code; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java new file mode 100644 index 0000000..5fc1b8b --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java @@ -0,0 +1,376 @@ +package org.dromara.web.service; + +import cn.dev33.satoken.secure.BCrypt; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.domain.model.RegisterBody; +import org.dromara.common.core.enums.UserType; +import org.dromara.common.core.exception.user.CaptchaException; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.mapper.SysUserRoleMapper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.ISysUserService; +import org.dromara.web.domain.vo.dto.WxRegisterDTO; +import org.dromara.zhishu.domain.TInviteCode; +import org.dromara.zhishu.domain.TUserPlatform; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.zhishu.domain.bo.ShopDetailBo; +import org.dromara.zhishu.domain.bo.SpecBo; +import org.dromara.zhishu.domain.vo.MessageSubscribeVo; +import org.dromara.zhishu.mapper.TUserPlatformMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.MapUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.dromara.zhishu.util.InterfaceUtils.getInterface; + +/** + * 注册校验方法 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysRegisterService { + + private final ISysUserService userService; + private final SysUserMapper userMapper; + private final CaptchaProperties captchaProperties; + private final ITInviteCodeService inviteCodeService; + private final SysRoleMapper sysRoleMapper; + private final SysUserRoleMapper sysUserRoleMapper; + private final TUserPlatformMapper userPlatformMapper; + private final IShopService shopService; + private final IShopDetailService shopDetailService; + private final ISpecService specService; + private final TShopMessageSubscribeService tShopMessageSubscribeService; + private final ISysConfigService configService; + + + /** + * 注册 + */ + public void register(RegisterBody registerBody) { + String tenantId = registerBody.getTenantId(); + String username = registerBody.getUsername(); + String password = registerBody.getPassword(); + String phoneNumber = registerBody.getPhoneNumber(); + String inviteCode = registerBody.getInviteCode(); + + // 校验用户类型是否存在 + String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); + } + + // 如果设置了邀请码必填,则校验邀请码 + if (StringUtils.isNotBlank(inviteCode)) { + TInviteCode code = inviteCodeService.validateInviteCode(inviteCode); + if (code == null) { + throw new UserException("邀请码无效或已过期"); + } + } + + SysUserBo sysUser = new SysUserBo(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPhonenumber(phoneNumber); + sysUser.setPassword(BCrypt.hashpw(password)); + sysUser.setUserType(userType); + + boolean exist = TenantHelper.dynamic(tenantId, () -> { + return userMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getUserName, sysUser.getUserName())); + }); + if (exist) { + throw new UserException("user.register.save.error", username); + } + + boolean exist1 = TenantHelper.dynamic(tenantId, () -> { + return userMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getPhonenumber, sysUser.getPhonenumber())); + }); + + if (exist1) { + throw new UserException("手机号已存在", phoneNumber); + } + + boolean regFlag = userService.registerUser(sysUser, tenantId); + if (!regFlag) { + throw new UserException("user.register.error"); + } + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); + Long userId = userMapper.selectName(sysUser.getUserName()); + + // 处理拼多多相关参数 + String pddMallId = registerBody.getPddMallId(); + String pddMallName = registerBody.getPddMallName(); + String pddType = registerBody.getPddType(); + String token = registerBody.getAccessToken(); + String skuSpec = registerBody.getSkuSpec(); + + // 检查是否是拼多多授权注册 + if (StringUtils.isNotBlank(pddType) && "2".equals(pddType)) { + // 设置特定角色 + String roleKey = "OnlineStore"; + SysRole role = sysRoleMapper.selectRoleByRoleKey(roleKey); + if (role != null && role.getRoleId() != null) { + sysUserRoleMapper.insertUserRole(userId, role.getRoleId()); + } else { + // 如果特定角色不存在,使用默认角色 + Long defaultRole = 1906216348137664514L; + userMapper.insertRole(userId, defaultRole); + } + + if (StringUtils.isNotBlank(pddMallId) && StringUtils.isNotBlank(pddMallName)) { + // 添加用户平台关联 + createUserPlatform(userId, pddMallId, pddMallName); + + // 创建店铺 + createShop(userId, pddMallId, pddMallName, token, phoneNumber, skuSpec); + +// System.out.println("拼多多店铺创建成功 - 用户ID: " + userId + ", 店铺ID: " + pddMallId + ", 店铺名称: " + pddMallName); + } + } else { + // 设置普通用户角色 + String roleKey = "OnlineStore"; + SysRole role = sysRoleMapper.selectRoleByRoleKey(roleKey); + sysUserRoleMapper.insertUserRole(userId, role.getRoleId()); + } + + try{ + Map regMap = new HashMap(); + regMap.put("username",username); + regMap.put("password",password); + regMap.put("about_id",userId+""); + regMap.put("fid","0"); + regMap.put("name",username); + regMap.put("phone",phoneNumber); + regMap.put("from","ERP"); + // 调用接口 + String res = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/employee/reg",regMap); + System.out.println(res); + }catch (Exception e){ + System.out.println("调用租户注册接口异常"); + } + + + // 处理邀请码 + if (StringUtils.isNotBlank(inviteCode)) { + inviteCodeService.useInviteCode(inviteCode, userId); + } + } + + /** + * 创建店铺 + */ + private void createShop(Long userId, String pddMallId, String pddMallName, String token, String phoneNumber, String skuSpec) { + String pddIp = configService.selectConfigByKey("pdd.ip"); +// System.out.println("获取拼多多IP配置: " + pddIp); + Date expirationTime; + //获取店铺订阅服务 + String vasData = getInterface(pddIp, "/api/pdd/auth/getVasOrder?mallId=" + pddMallId); + Map vasMap = JsonUtil.transferToObj(vasData, Map.class); + //成功 调用新后台 + Map vas = (Map) vasMap.get("data"); +// System.out.println("获取订阅服务数据:" + JsonUtil.transferToJson(vas)); + vas = MapUtils.convertKeys(vas); +// System.out.println("转变格式:" + JsonUtil.transferToJson(vas)); + //计算到期时间 + long payTime = Long.parseLong(vas.get("payTime").toString()); + long timeLength = Long.parseLong(vas.get("timeLength").toString()); + long newTimestamp = payTime + (timeLength * 1000); + expirationTime = new Date(newTimestamp); + + + ShopBo bo = new ShopBo(); + bo.setShopType("1"); + bo.setShopGroup("默认分组"); + bo.setShopName(pddMallName); + bo.setPassword("123456"); + bo.setShopAliasName(pddMallName); + bo.setCreateBy(userId); + bo.setUpdateBy(userId); + bo.setAccount(phoneNumber); + bo.setSkuSpec(skuSpec); +// bo.setToken(token); + bo.setTenant_id("000000"); + bo.setAddTime(DateUtils.parseDate(DateUtils.getTime())); + bo.setUserId(userId); + bo.setShopAuthorize("1"); + bo.setExpirationTime(expirationTime); + bo.setMallId(Long.valueOf(pddMallId)); + bo.setUserId(userId); + + // 如果有token,则设置为已授权 + if (StringUtils.isNotBlank(token)) { + bo.setToken(token); + bo.setShopAuthorize("1"); // 已授权 + } else { + bo.setShopAuthorize("0"); // 未授权 + } + + shopService.insertByBo(bo); + + +// ShopBo shopBo = new ShopBo(); +// shopBo.setId(id); +// shopBo.setMallId(Long.valueOf(pddMallId)); +// shopBo.setToken(token); +// shopBo.setShopAliasName(pddMallName); +// shopBo.setShopAuthorize("1"); +// shopBo.setExpirationTime(DateUtils.getNextDay()); + + // 绑定店铺 + System.out.println("开始绑定店铺"); + int mark = shopService.selectShopAssociationMall(bo); + System.out.println("店铺绑定结果: " + mark); +// +// // 处理订阅消息 +// System.out.println("开始处理订阅消息"); +// MessageSubscribeVo messageSubscribeVo = accessTokenVo.getMessageSubscribeVo(); +// tShopMessageSubscribeService.insertOrUpdate(List.of(messageSubscribeVo), id); +// System.out.println("订阅消息处理完成"); + } + + /** + * 添加用户平台关联 + */ + private void createUserPlatform(Long userId, String pddMallId, String pddMallName) { + TUserPlatform userPlatform = new TUserPlatform(); + userPlatform.setType("1"); // 拼多多 + userPlatform.setUserId(userId); + userPlatform.setPlatformId(pddMallId); + userPlatform.setPlatformName(pddMallName); + userPlatform.setStatus("0"); + userPlatform.setDelFlag("0"); + userPlatformMapper.insertTUserPlatform(userPlatform); + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + public void validateCaptcha(String tenantId, String username, String code, String uuid) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + /** + * 记录登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + * @return + */ + private void recordLogininfor(String tenantId, String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + + /** + * 微信注册 + */ + public void WxRegister(WxRegisterDTO wxRegisterDTO) { + String tenantId = "000000"; + String username = wxRegisterDTO.getUsername(); + String phoneNumber = wxRegisterDTO.getPhoneNumber(); + String password = wxRegisterDTO.getPassword(); + String clientId = wxRegisterDTO.getClientId(); + String inviteCode = wxRegisterDTO.getInviteCode(); + + if (StringUtils.isBlank(clientId)) { + throw new UserException("auth.clientid.not.blank"); + } + + // 如果设置了邀请码必填,则校验邀请码 + if (StringUtils.isNotBlank(inviteCode)) { + TInviteCode code = inviteCodeService.validateInviteCode(inviteCode); + if (code == null) { + throw new UserException("邀请码无效或已过期"); + } + } + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, wxRegisterDTO.getCode(), wxRegisterDTO.getUuid()); + } + String checkUserName = userMapper.CheckUserName(username); + if (StringUtils.isNotBlank(checkUserName)) { + throw new UserException("用户名已存在,请更换用户名重新注册", username); + } + String checkPhoneNumber = userMapper.selectPhoneNumber(phoneNumber); + if (StringUtils.isNotBlank(checkPhoneNumber)) { + throw new UserException("手机号已存在,请更换手机号重新注册", phoneNumber); + } + SysUserBo sysUser = new SysUserBo(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPhonenumber(phoneNumber); + sysUser.setPassword(BCrypt.hashpw(password)); + sysUser.setUserType("sys_user"); + boolean regFlag = userService.registerUser(sysUser, tenantId); + if (!regFlag) { + throw new UserException("user.register.error"); + } + + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); + Long userId = userMapper.selectName(sysUser.getUserName()); + Long role = 1906216348137664514L; + userMapper.insertRole(userId, role); + + // 处理邀请码 + if (StringUtils.isNotBlank(inviteCode)) { + inviteCodeService.useInviteCode(inviteCode, userId); + } + } +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/AndroidAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/AndroidAuthStrategy.java new file mode 100644 index 0000000..5c64ba1 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/AndroidAuthStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.AndroidLoginBody; +import org.dromara.common.core.domain.model.AndroidLoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 安卓认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("android" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class AndroidAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final ISysUserService userService; + + @Override + public LoginVo login(String body, SysClientVo client) { + AndroidLoginBody loginBody = JsonUtils.parseObject(body, AndroidLoginBody.class); + ValidatorUtils.validate(loginBody); + + String phoneNumber = loginBody.getPhoneNumber(); + String password = loginBody.getPassword(); + + // 参数校验 + if (StringUtils.isBlank(phoneNumber) || StringUtils.isBlank(password)) { + throw new ServiceException("手机号或密码不能为空"); + } + + // 根据手机号查询用户 + SysUserVo user = userService.selectUserByPhonenumber(phoneNumber); + if (ObjectUtil.isNull(user)) { + log.info("登录用户手机号:{} 不存在.", phoneNumber); + throw new ServiceException("用户不存在"); + } + + // 验证密码是否正确 + if (!BCrypt.checkpw(password, user.getPassword())) { + log.info("登录用户:{} 密码错误.", phoneNumber); + throw new ServiceException("手机号或密码错误"); + } + + // 检查用户状态 + if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", phoneNumber); + throw new ServiceException("账号已被停用"); + } + + // 构建登录用户信息 + AndroidLoginUser loginUser = new AndroidLoginUser(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(user.getUserId()); + loginUser.setUserName(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setPhoneNumber(user.getPhonenumber()); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + + // 配置登录模型 + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + + // 执行登录 + LoginHelper.login(loginUser, model); + + // 返回登录信息 + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + loginVo.setPhoneNumber(user.getPhonenumber()); + loginVo.setNickName(user.getNickName()); + loginVo.setUserId(user.getUserId()); + + return loginVo; + } +} \ No newline at end of file diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java new file mode 100644 index 0000000..1bed4f3 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.EmailLoginBody; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 邮件认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("email" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class EmailAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String email = loginBody.getEmail(); + String emailCode = loginBody.getEmailCode(); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByEmail(email); + loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验邮箱验证码 + */ + private boolean validateEmailCode(String tenantId, String email, String emailCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(emailCode); + } + + private SysUserVo loadUserByEmail(String email) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getEmail, email)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", email); + throw new UserException("user.not.exists", email); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", email); + throw new UserException("user.blocked", email); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java new file mode 100644 index 0000000..2ffda35 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.SmsLoginBody; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 短信认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("sms" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SmsAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String phonenumber = loginBody.getPhonenumber(); + String smsCode = loginBody.getSmsCode(); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByPhonenumber(phonenumber); + loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginModel model = new SaLoginModel(); + model.setDevice(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验短信验证码 + */ + private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(smsCode); + } + + private SysUserVo loadUserByPhonenumber(String phonenumber) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getPhonenumber, phonenumber)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", phonenumber); + throw new UserException("user.not.exists", phonenumber); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", phonenumber); + throw new UserException("user.blocked", phonenumber); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..a09a0c3 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -0,0 +1,292 @@ +--- # 临时文件存储位置 避免临时文件被系统清理报错 +spring.servlet.multipart.location: /ruoyi/server/temp + +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: false + url: http://localhost:9090/admin + instance: + service-host-type: IP + metadata: + username: ${spring.boot.admin.client.username} + userpassword: ${spring.boot.admin.client.password} + username: @monitor.username@ + password: @monitor.password@ + +--- # snail-job 配置 +snail-job: + enabled: false + # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group: "ruoyi_group" + # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表 + token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 127.0.0.1 + port: 17888 + # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 + namespace: ${spring.profiles.active} + # 随主应用端口漂移 + port: 2${server.port} + # 客户端ip指定 + host: + # RPC类型: netty, grpc + rpc-type: grpc + +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: false + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://146.56.227.42:3306/zhishu?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true +# url: jdbc:mysql://111.229.25.150:3306/zhishu?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: zhishu + password: XsRR4K3ATizyc5BK +# # 腾讯云数据库 + slave: + lazy: true + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://nj-cynosdbmysql-grp-1v6vxn5f.sql.tencentcdb.com:26247/task?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: root + password: Long6166@@ + taskSlave: + lazy: true + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://36.212.12.247:3306/zhishu_slave?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: zhishu_slave + password: 7DpixiEdCs5p3PEr + psi: + lazy: true + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://175.27.224.66:3306/psi?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: root + password: 5e07c0eec1770c94 +# oracle: +# type: ${spring.datasource.type} +# driverClassName: oracle.jdbc.OracleDriver +# url: jdbc:oracle:thin:@//localhost:1521/XE +# username: ROOT +# password: root +# postgres: +# type: ${spring.datasource.type} +# driverClassName: org.postgresql.Driver +# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true +# username: root +# password: root +# sqlserver: +# type: ${spring.datasource.type} +# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver +# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true +# username: SA +# password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 多久检查一次连接的活性 + keepaliveTime: 30000 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: 146.56.227.42 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # redis 密码必须配置 + password: Qq123123 + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: false + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true + # 发送方,遵循RFC-822标准 + from: xxx@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: xxx@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxxxxxxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 + +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 +sms: + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [ openid, email, phone, profile ] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab + +# zhishu业务配置 +zhishu: + url: ./file/ + filterUrl: ./file/fiter/ + kfz-service-url: http://146.56.227.42:8095 + history-shop-god-s-excel-file-path: ./ShopGoodsData/HistoryGoodsData + new-shop-god-s-excel-file-path: ./ShopGoodsData/NewShopGoodsData + changed-shop-god-s-excel-file-path: ./ShopGoodsData/ChangedShopGoodsData + error-shop-god-s-excel-file-path: ./ShopGoodsData/ErrorShopGoodsData diff --git a/ruoyi-admin/src/main/resources/banner.txt b/ruoyi-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..21b1126 --- /dev/null +++ b/ruoyi-admin/src/main/resources/banner.txt @@ -0,0 +1,8 @@ +Application Version: ${revision} +Spring Boot Version: ${spring-boot.version} +__________ _____.___.__ ____ ____ __________.__ +\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______ + | _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/ + | | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \ + |____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ > + \/ \/ \/ \/ diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..f948c4a --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,61 @@ +#错误消息 +not.null=* Required fill in +user.jcaptcha.error=Captcha error +user.jcaptcha.expire=Captcha invalid +user.not.exists=Sorry, your account: {0} does not exist +user.password.not.match=User does not exist/Password error +user.password.retry.limit.count=Password input error {0} times +user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes +user.password.delete=Sorry, your account:{0} has been deleted +user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator +role.blocked=Role disabled,please contact administrators +user.logout.success=Exit successful +length.not.valid=The length must be between {min} and {max} characters +user.username.not.blank=Username cannot be blank +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number +user.username.length.valid=Account length must be between {min} and {max} characters +user.password.not.blank=Password cannot be empty +user.password.length.valid=Password length must be between {min} and {max} characters +user.password.not.valid=* 5-50 characters +user.email.not.valid=Mailbox format error +user.email.not.blank=Mailbox cannot be blank +user.phonenumber.not.blank=Phone number cannot be blank +user.mobile.phone.number.not.valid=Phone number format error +user.login.success=Login successful +user.register.success=Register successful +user.register.save.error=Failed to save user {0}, The registered account already exists +user.register.error=Register failed, please contact system administrator +user.notfound=Please login again +user.forcelogout=The administrator is forced to exit,please login again +user.unknown.error=Unknown error, please login again +auth.grant.type.error=Auth grant type error +auth.grant.type.blocked=Auth grant type disabled +auth.grant.type.not.blank=Auth grant type cannot be blank +auth.clientid.not.blank=Auth clientid cannot be blank +##文件上传消息 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!
the maximum allowed file size is:{0}MB! +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters +##权限 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] +repeat.submit.message=Repeat submit is not allowed, please try again later +rate.limiter.message=Visit too frequently, please try again later +sms.code.not.blank=Sms code cannot be blank +sms.code.retry.limit.count=Sms code input error {0} times +sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes +email.code.not.blank=Email code cannot be blank +email.code.retry.limit.count=Email code input error {0} times +email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes +xcx.code.not.blank=Mini program [code] cannot be blank +social.source.not.blank=Social login platform [source] cannot be blank +social.code.not.blank=Social login platform [code] cannot be blank +social.state.not.blank=Social login platform [state] cannot be blank +##租户 +tenant.number.not.blank=Tenant number cannot be blank +tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator +tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator +tenant.expired=Sorry, your tenant has expired. Please contact the administrator. diff --git a/ruoyi-admin/src/main/resources/ip2region.xdb b/ruoyi-admin/src/main/resources/ip2region.xdb new file mode 100644 index 0000000..7052c05 Binary files /dev/null and b/ruoyi-admin/src/main/resources/ip2region.xdb differ diff --git a/ruoyi-admin/src/main/resources/logback-plus.xml b/ruoyi-admin/src/main/resources/logback-plus.xml new file mode 100644 index 0000000..b74289e --- /dev/null +++ b/ruoyi-admin/src/main/resources/logback-plus.xml @@ -0,0 +1,129 @@ + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + ${log.path}/sys-console.log + + + ${log.path}/sys-console.%d{yyyy-MM-dd}.log + + 1 + + + ${log.pattern} + utf-8 + + + + INFO + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + 0 + + 512 + + + + + + + + 0 + + 512 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java new file mode 100644 index 0000000..b18729e --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java @@ -0,0 +1,100 @@ +package org.dromara.test; + +import org.dromara.common.core.config.RuoYiConfig; +import org.dromara.zhishu.util.CnumberUtils; +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.concurrent.TimeUnit; + +/** + * 单元测试案例 + * + * @author Lion Li + */ +@SpringBootTest // 此注解只能在 springboot 主包下使用 需包含 main 方法与 yml 配置文件 +@DisplayName("单元测试案例") +public class DemoUnitTest { + + @Autowired + private RuoYiConfig ruoYiConfig; + + @Autowired + private CnumberUtils cnumberUtils; + + + + + @DisplayName("测试 @SpringBootTest @Test @DisplayName 注解") + @Test + public void testTest() { + + String number= cnumberUtils.getArtNo(8.5, 1914486937581867009L,"1451236547842", 1916429009234714626L, null, null, null); +// String number7= cnumberUtils.getArtNo(8.5, 1L, null, 1906189381131055106L, null, null); +// String number1= cnumberUtils.getArtNo(8.5, 1L, null, 1906189381131055106L, 1906190045781438466L, null); +// String number2= cnumberUtils.getArtNo(8.5, 1L, null, 1906189381131055106L, 1906190045781438466L, 1759L); +// String number3= cnumberUtils.getArtNo(8.5, 1L, "7507301079", null, null, null); +// String number4= cnumberUtils.getArtNo(8.5, 1L, "1234567819", 1906189381131055106L, null, null); +// String number5= cnumberUtils.getArtNo(8.5, 1L, "1234567811", 1906189381131055106L, 1906190045781438466L, null); +// String number6= cnumberUtils.getArtNo(8.5, 1L, "1234567811", 1906189381131055106L, 1906190045781438466L, 1759L); + System.out.println(number); +// System.out.println(number6); +// System.out.println(number1); +// System.out.println(number2); +// System.out.println(number3); +// System.out.println(number4); +// System.out.println(number5); +// System.out.println(number6); +// System.out.println(number7); + System.out.println(ruoYiConfig); + } + + @Disabled + @DisplayName("测试 @Disabled 注解") + @Test + public void testDisabled() { + System.out.println(ruoYiConfig); + } + + // 设置测试方法的最大执行时间为2秒,如果超过这个时间,测试将被视为失败 + @Timeout(value = 2L, unit = TimeUnit.SECONDS) + // 为测试方法设置显示名称,提高测试报告的可读性 + @DisplayName("测试 @Timeout 注解") + // 标识这是一个JUnit测试方法 + @Test + public void testTimeout() throws InterruptedException { + // 模拟一个长时间的任务,以测试@Timeout注解的效果 + Thread.sleep(3000); + // 打印配置信息,这里假设ruoYiConfig是一个已经初始化的配置对象 + System.out.println(ruoYiConfig); + } + + + @DisplayName("测试 @RepeatedTest 注解") + @RepeatedTest(3) + public void testRepeatedTest() { + System.out.println(666); + } + + @BeforeAll + public static void testBeforeAll() { + System.out.println("@BeforeAll =================="); + } + + @BeforeEach + public void testBeforeEach() { + System.out.println("@BeforeEach =================="); + } + + @AfterEach + public void testAfterEach() { + System.out.println("@AfterEach =================="); + } + + @AfterAll + public static void testAfterAll() { + System.out.println("@AfterAll =================="); + } + +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java new file mode 100644 index 0000000..b50afa6 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java @@ -0,0 +1,54 @@ +package org.dromara.test; + +import org.junit.jupiter.api.*; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * 标签单元测试案例 + * + * @author Lion Li + */ +@SpringBootTest +@DisplayName("标签单元测试案例") +public class TagUnitTest { + + @Tag("dev") + @DisplayName("测试 @Tag dev") + @Test + public void testTagDev() { + System.out.println("dev"); + } + + @Tag("prod") + @DisplayName("测试 @Tag prod") + @Test + public void testTagProd() { + System.out.println("prod"); + } + + @Tag("local") + @DisplayName("测试 @Tag local") + @Test + public void testTagLocal() { + System.out.println("local"); + } + + @Tag("exclude") + @DisplayName("测试 @Tag exclude") + @Test + public void testTagExclude() { + System.out.println("exclude"); + } + + @BeforeEach + public void testBeforeEach() { + System.out.println("@BeforeEach =================="); + } + + @AfterEach + public void testAfterEach() { + System.out.println("@AfterEach =================="); + } + + +} diff --git a/ruoyi-admin/zhFonts/SIMSUN.TTC b/ruoyi-admin/zhFonts/SIMSUN.TTC new file mode 100644 index 0000000..6ca8de3 Binary files /dev/null and b/ruoyi-admin/zhFonts/SIMSUN.TTC differ diff --git a/ruoyi-admin/zhFonts/fonts.scale b/ruoyi-admin/zhFonts/fonts.scale new file mode 100644 index 0000000..fed9544 --- /dev/null +++ b/ruoyi-admin/zhFonts/fonts.scale @@ -0,0 +1,4 @@ +3 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1 +SIMSUN.TTC -misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java new file mode 100644 index 0000000..cd01e33 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java @@ -0,0 +1,52 @@ +package org.dromara.common.core.config; + +import cn.hutool.core.util.ArrayUtil; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.core.task.VirtualThreadTaskExecutor; +import org.springframework.scheduling.annotation.AsyncConfigurer; + +import java.util.Arrays; +import java.util.concurrent.Executor; + +/** + * 异步配置 + *

+ * 如果未使用虚拟线程则生效 + * + * @author Lion Li + */ +@AutoConfiguration +public class AsyncConfig implements AsyncConfigurer { + + /** + * 自定义 @Async 注解使用系统线程池 + */ + @Override + public Executor getAsyncExecutor() { + if(SpringUtils.isVirtual()) { + return new VirtualThreadTaskExecutor("async-"); + } + return SpringUtils.getBean("scheduledExecutorService"); + } + + /** + * 异步执行异常处理 + */ + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return (throwable, method, objects) -> { + throwable.printStackTrace(); + StringBuilder sb = new StringBuilder(); + sb.append("Exception message - ").append(throwable.getMessage()) + .append(", Method name - ").append(method.getName()); + if (ArrayUtil.isNotEmpty(objects)) { + sb.append(", Parameter value - ").append(Arrays.toString(objects)); + } + throw new ServiceException(sb.toString()); + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java new file mode 100644 index 0000000..bf8efc5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java @@ -0,0 +1,83 @@ +package org.dromara.common.core.constant; + +/** + * 缓存组名称常量 + *

+ * key 格式为 cacheNames#ttl#maxIdleTime#maxSize + *

+ * ttl 过期时间 如果设置为0则不过期 默认为0 + * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 + * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 + *

+ * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500 + * + * @author Lion Li + */ +public interface CacheNames { + + /** + * 演示案例 + */ + String DEMO_CACHE = "demo:cache#60s#10m#20"; + + /** + * 系统配置 + */ + String SYS_CONFIG = "sys_config"; + + /** + * 数据字典 + */ + String SYS_DICT = "sys_dict"; + + /** + * 租户 + */ + String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d"; + + /** + * 客户端 + */ + String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d"; + + /** + * 用户账户 + */ + String SYS_USER_NAME = "sys_user_name#30d"; + + /** + * 用户名称 + */ + String SYS_NICKNAME = "sys_nickname#30d"; + + /** + * 部门 + */ + String SYS_DEPT = "sys_dept#30d"; + + /** + * OSS内容 + */ + String SYS_OSS = "sys_oss#30d"; + + /** + * 角色自定义权限 + */ + String SYS_ROLE_CUSTOM = "sys_role_custom#30d"; + + /** + * 部门及以下权限 + */ + String SYS_DEPT_AND_CHILD = "sys_dept_and_child#30d"; + + /** + * OSS配置 + */ + String SYS_OSS_CONFIG = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss_config"; + + /** + * 在线用户 + */ + String ONLINE_TOKEN = "online_tokens"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java new file mode 100644 index 0000000..5352b11 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java @@ -0,0 +1,34 @@ +package org.dromara.common.core.constant; + +/** + * 全局的key常量 (业务无关的key) + * + * @author Lion Li + */ +public interface GlobalConstants { + + /** + * 全局 redis key (业务无关的key) + */ + String GLOBAL_REDIS_KEY = "global:"; + + /** + * 验证码 redis key + */ + String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:"; + + /** + * 防重提交 redis key + */ + String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:"; + + /** + * 限流 redis key + */ + String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:"; + + /** + * 三方认证 redis key + */ + String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:"; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java new file mode 100644 index 0000000..77eed8c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java @@ -0,0 +1,54 @@ +package org.dromara.common.core.constant; + +import cn.hutool.core.lang.RegexPool; + +/** + * 常用正则表达式字符串 + *

+ * 常用正则表达式集合,更多正则见: https://any86.github.io/any-rule/ + * + * @author Feng + */ +public interface RegexConstants extends RegexPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + String DICTIONARY_TYPE = "^[a-z][a-z0-9_]*$"; + + /** + * 权限标识必须符合 tool:build:list 格式,或者空字符串 + */ + String PERMISSION_STRING = "^(|^[a-zA-Z0-9_]+:[a-zA-Z0-9_]+:[a-zA-Z0-9_]+)$"; + + /** + * 身份证号码(后6位) + */ + String ID_CARD_LAST_6 = "^(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"; + + /** + * QQ号码 + */ + String QQ_NUMBER = "^[1-9][0-9]\\d{4,9}$"; + + /** + * 邮政编码 + */ + String POSTAL_CODE = "^[1-9]\\d{5}$"; + + /** + * 注册账号 + */ + String ACCOUNT = "^[a-zA-Z][a-zA-Z0-9_]{4,15}$"; + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + String PASSWORD = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,}$"; + + /** + * 通用状态(0表示正常,1表示停用) + */ + String STATUS = "^[01]$"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java new file mode 100644 index 0000000..65c012f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 部门 + * + * @author AprilWind + */ + +@Data +@NoArgsConstructor +public class DeptDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 部门名称 + */ + private String deptName; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java new file mode 100644 index 0000000..7536ee3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java @@ -0,0 +1,46 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 岗位 + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class PostDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 岗位ID + */ + private Long postId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 岗位编码 + */ + private String postCode; + + /** + * 岗位名称 + */ + private String postName; + + /** + * 岗位类别编码 + */ + private String postCategory; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java new file mode 100644 index 0000000..3934ada --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java @@ -0,0 +1,45 @@ +package org.dromara.common.core.domain.dto; + + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 启动流程对象 + * + * @author may + */ +@Data +public class StartProcessDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 业务唯一值id + */ + private String businessId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java new file mode 100644 index 0000000..cb5def9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java @@ -0,0 +1,73 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 用户 + * + * @author Michelle.Chung + */ +@Data +@NoArgsConstructor +public class UserDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 用户昵称 + */ + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + private String email; + + /** + * 手机号码 + */ + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java new file mode 100644 index 0000000..d570c31 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java @@ -0,0 +1,34 @@ +package org.dromara.common.core.domain.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 删除流程监听 + * + * @author AprilWind + */ +@Data +public class ProcessDeleteEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 业务id + */ + private String businessId; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java new file mode 100644 index 0000000..6329b9c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java @@ -0,0 +1,50 @@ +package org.dromara.common.core.domain.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; + +/** + * 总体流程监听 + * + * @author may + */ +@Data +public class ProcessEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 业务id + */ + private String businessId; + + /** + * 状态 + */ + private String status; + + /** + * 办理参数 + */ + private Map params; + + /** + * 当为true时为申请人节点办理 + */ + private boolean submit; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/AndroidLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/AndroidLoginBody.java new file mode 100644 index 0000000..1b402f2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/AndroidLoginBody.java @@ -0,0 +1,27 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 安卓登录对象 + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class AndroidLoginBody extends LoginBody { + + /** + * 手机号 + */ + @NotBlank(message = "手机号不能为空") + private String phoneNumber; + + /** + * 用户密码 + */ + @NotBlank(message = "密码不能为空") + private String password; +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/AndroidLoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/AndroidLoginUser.java new file mode 100644 index 0000000..5628b52 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/AndroidLoginUser.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * 安卓登录用户身份权限 + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class AndroidLoginUser extends LoginUser { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 手机号 + */ + private String phoneNumber; + + /** + * 用户名 + */ + private String userName; +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java new file mode 100644 index 0000000..eec9bb3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.validator.constraints.Length; + +/** + * 密码登录对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class PasswordLoginBody extends LoginBody { + +// /** +// * 用户名 +// */ +// @NotBlank(message = "{user.username.not.blank}") +// @Length(min = 2, max = 20, message = "{user.username.length.valid}") +// private String username; + + /** + * 用户密码 + */ + @NotBlank(message = "{user.password.not.blank}") + @Length(min = 5, max = 20, message = "{user.password.length.valid}") + private String password; + + + /** + * 手机号 + */ + @NotBlank(message = "{user.username.not.blank}") + private String phoneNumber; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java new file mode 100644 index 0000000..27bab39 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java @@ -0,0 +1,61 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.validator.constraints.Length; + +/** + * 用户注册对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RegisterBody extends LoginBody { + + /** + * 用户名 + */ + @NotBlank(message = "{user.username.not.blank}") + @Length(min = 2, max = 20, message = "{user.username.length.valid}") + private String username; + + /** + * 用户密码 + */ + @NotBlank(message = "{user.password.not.blank}") + @Length(min = 5, max = 20, message = "{user.password.length.valid}") + private String password; + + private String userType; + + private String phoneNumber; + + /** + * 邀请码 + */ + private String inviteCode; + + /** + * 拼多多店铺ID + */ + private String pddMallId; + + /** + * 拼多多店铺名称 + */ + private String pddMallName; + + /** + * 拼多多类型 + */ + private String pddType; + + /** + * 授权token + */ + private String accessToken; + + private String skuSpec; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java new file mode 100644 index 0000000..5e930d3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 三方登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class XcxLoginBody extends LoginBody { + + /** + * 小程序id(多个小程序时使用) + */ + private String appid; + + /** + * 小程序code + */ + @NotBlank(message = "{xcx.code.not.blank}") + private String xcxCode; + /** + * 用户密码 + */ + private String password; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java new file mode 100644 index 0000000..614bab1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java @@ -0,0 +1,28 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * 小程序登录用户身份权限 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class XcxLoginUser extends LoginUser { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * openid + */ + private String openid; + private String phoneNumber; + private String userName; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java new file mode 100644 index 0000000..c1660ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java @@ -0,0 +1,215 @@ +package org.dromara.common.core.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 业务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum BusinessStatusEnum { + + /** + * 已撤销 + */ + CANCEL("cancel", "已撤销"), + + /** + * 草稿 + */ + DRAFT("draft", "草稿"), + + /** + * 待审核 + */ + WAITING("waiting", "待审核"), + + /** + * 已完成 + */ + FINISH("finish", "已完成"), + + /** + * 已作废 + */ + INVALID("invalid", "已作废"), + + /** + * 已退回 + */ + BACK("back", "已退回"), + + /** + * 已终止 + */ + TERMINATION("termination", "已终止"); + + /** + * 状态 + */ + private final String status; + + /** + * 描述 + */ + private final String desc; + + private static final Map STATUS_MAP = Arrays.stream(BusinessStatusEnum.values()) + .collect(Collectors.toConcurrentMap(BusinessStatusEnum::getStatus, Function.identity())); + + /** + * 根据状态获取对应的 BusinessStatusEnum 枚举 + * + * @param status 业务状态码 + * @return 对应的 BusinessStatusEnum 枚举,如果找不到则返回 null + */ + public static BusinessStatusEnum getByStatus(String status) { + // 使用 STATUS_MAP 获取对应的枚举,若找不到则返回 null + return STATUS_MAP.get(status); + } + + /** + * 根据状态获取对应的业务状态描述信息 + * + * @param status 业务状态码 + * @return 返回业务状态描述,若状态码为空或未找到对应的枚举,返回空字符串 + */ + public static String findByStatus(String status) { + if (StringUtils.isBlank(status)) { + return StrUtil.EMPTY; + } + BusinessStatusEnum statusEnum = STATUS_MAP.get(status); + return (statusEnum != null) ? statusEnum.getDesc() : StrUtil.EMPTY; + } + + /** + * 判断是否为指定的状态之一:草稿、已撤销或已退回 + * + * @param status 要检查的状态 + * @return 如果状态为草稿、已撤销或已退回之一,则返回 true;否则返回 false + */ + public static boolean isDraftOrCancelOrBack(String status) { + return DRAFT.status.equals(status) || CANCEL.status.equals(status) || BACK.status.equals(status); + } + + /** + * 判断是否为撤销,退回,作废,终止 + * + * @param status status + * @return 结果 + */ + public static boolean initialState(String status) { + return CANCEL.status.equals(status) || BACK.status.equals(status) || INVALID.status.equals(status) || TERMINATION.status.equals(status); + } + + /** + * 获取运行中的实例状态列表 + * + * @return 包含运行中实例状态的不可变列表 + * (包含 DRAFT、WAITING、BACK 和 CANCEL 状态) + */ + public static List runningStatus() { + return Arrays.asList(DRAFT.status, WAITING.status, BACK.status, CANCEL.status); + } + + /** + * 获取结束实例的状态列表 + * + * @return 包含结束实例状态的不可变列表 + * (包含 FINISH、INVALID 和 TERMINATION 状态) + */ + public static List finishStatus() { + return Arrays.asList(FINISH.status, INVALID.status, TERMINATION.status); + } + + /** + * 启动流程校验 + * + * @param status 状态 + */ + public static void checkStartStatus(String status) { + if (WAITING.getStatus().equals(status)) { + throw new ServiceException("该单据已提交过申请,正在审批中!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 撤销流程校验 + * + * @param status 状态 + */ + public static void checkCancelStatus(String status) { + if (CANCEL.getStatus().equals(status)) { + throw new ServiceException("该单据已撤销!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (BACK.getStatus().equals(status)) { + throw new ServiceException("该单据已退回!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 驳回流程校验 + * + * @param status 状态 + */ + public static void checkBackStatus(String status) { + if (BACK.getStatus().equals(status)) { + throw new ServiceException("该单据已退回!"); + } else if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (CANCEL.getStatus().equals(status)) { + throw new ServiceException("该单据已撤销!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + + /** + * 作废,终止流程校验 + * + * @param status 状态 + */ + public static void checkInvalidStatus(String status) { + if (FINISH.getStatus().equals(status)) { + throw new ServiceException("该单据已完成申请!"); + } else if (INVALID.getStatus().equals(status)) { + throw new ServiceException("该单据已作废!"); + } else if (TERMINATION.getStatus().equals(status)) { + throw new ServiceException("该单据已终止!"); + } else if (StringUtils.isBlank(status)) { + throw new ServiceException("流程状态为空!"); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java new file mode 100644 index 0000000..8d4b6d9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java @@ -0,0 +1,146 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.utils.StringUtils; + +/* + * 日期格式 + * "yyyy":4位数的年份,例如:2023年表示为"2023"。 + * "yy":2位数的年份,例如:2023年表示为"23"。 + * "MM":2位数的月份,取值范围为01到12,例如:7月表示为"07"。 + * "M":不带前导零的月份,取值范围为1到12,例如:7月表示为"7"。 + * "dd":2位数的日期,取值范围为01到31,例如:22日表示为"22"。 + * "d":不带前导零的日期,取值范围为1到31,例如:22日表示为"22"。 + * "EEEE":星期的全名,例如:星期三表示为"Wednesday"。 + * "E":星期的缩写,例如:星期三表示为"Wed"。 + * "DDD" 或 "D":一年中的第几天,取值范围为001到366,例如:第200天表示为"200"。 + * 时间格式 + * "HH":24小时制的小时数,取值范围为00到23,例如:下午5点表示为"17"。 + * "hh":12小时制的小时数,取值范围为01到12,例如:下午5点表示为"05"。 + * "mm":分钟数,取值范围为00到59,例如:30分钟表示为"30"。 + * "ss":秒数,取值范围为00到59,例如:45秒表示为"45"。 + * "SSS":毫秒数,取值范围为000到999,例如:123毫秒表示为"123"。 + */ + +/** + * 日期格式与时间格式枚举 + */ +@Getter +@AllArgsConstructor +public enum FormatsType { + + /** + * 例如:2023年表示为"23" + */ + YY("yy"), + + /** + * 例如:2023年表示为"2023" + */ + YYYY("yyyy"), + + /** + * 例例如,2023年7月可以表示为 "2023-07" + */ + YYYY_MM("yyyy-MM"), + + /** + * 例如,日期 "2023年7月22日" 可以表示为 "2023-07-22" + */ + YYYY_MM_DD("yyyy-MM-dd"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分",则可以表示为 "2023-07-22 15:30" + */ + YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023-07-22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"), + + /** + * 例如:下午3点30分45秒,表示为 "15:30:45" + */ + HH_MM_SS("HH:mm:ss"), + + /** + * 例例如,2023年7月可以表示为 "2023/07" + */ + YYYY_MM_SLASH("yyyy/MM"), + + /** + * 例如,日期 "2023年7月22日" 可以表示为 "2023/07/22" + */ + YYYY_MM_DD_SLASH("yyyy/MM/dd"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SLASH("yyyy/MM/dd HH:mm"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SS_SLASH("yyyy/MM/dd HH:mm:ss"), + + /** + * 例例如,2023年7月可以表示为 "2023.07" + */ + YYYY_MM_DOT("yyyy.MM"), + + /** + * 例如,日期 "2023年7月22日" 可以表示为 "2023.07.22" + */ + YYYY_MM_DD_DOT("yyyy.MM.dd"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分",则可以表示为 "2023.07.22 15:30" + */ + YYYY_MM_DD_HH_MM_DOT("yyyy.MM.dd HH:mm"), + + /** + * 例如,当前时间如果是 "2023年7月22日下午3点30分45秒",则可以表示为 "2023.07.22 15:30:45" + */ + YYYY_MM_DD_HH_MM_SS_DOT("yyyy.MM.dd HH:mm:ss"), + + /** + * 例如,2023年7月可以表示为 "202307" + */ + YYYYMM("yyyyMM"), + + /** + * 例如,2023年7月22日可以表示为 "20230722" + */ + YYYYMMDD("yyyyMMdd"), + + /** + * 例如,2023年7月22日下午3点可以表示为 "2023072215" + */ + YYYYMMDDHH("yyyyMMddHH"), + + /** + * 例如,2023年7月22日下午3点30分可以表示为 "202307221530" + */ + YYYYMMDDHHMM("yyyyMMddHHmm"), + + /** + * 例如,2023年7月22日下午3点30分45秒可以表示为 "20230722153045" + */ + YYYYMMDDHHMMSS("yyyyMMddHHmmss"); + + /** + * 时间格式 + */ + private final String timeFormat; + + public static FormatsType getFormatsType(String str) { + for (FormatsType value : values()) { + if (StringUtils.contains(str, value.getTimeFormat())) { + return value; + } + } + throw new RuntimeException("'FormatsType' not found By " + str); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java new file mode 100644 index 0000000..40ce01b --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java @@ -0,0 +1,74 @@ +package org.dromara.common.core.exception.base; + +import lombok.AllArgsConstructor; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * 基础异常 + * + * @author ruoyi + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +public class BaseException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 所属模块 + */ + private String module; + + /** + * 错误码 + */ + private String code; + + /** + * 错误码对应的参数 + */ + private Object[] args; + + /** + * 错误消息 + */ + private String defaultMessage; + + public BaseException(String module, String code, Object[] args) { + this(module, code, args, null); + } + + public BaseException(String module, String defaultMessage) { + this(module, null, null, defaultMessage); + } + + public BaseException(String code, Object[] args) { + this(null, code, args, null); + } + + public BaseException(String defaultMessage) { + this(null, null, null, defaultMessage); + } + + @Override + public String getMessage() { + String message = null; + if (!StringUtils.isEmpty(code)) { + message = MessageUtils.message(code, args); + } + if (message == null) { + message = defaultMessage; + } + return message; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java new file mode 100644 index 0000000..d374fc0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java @@ -0,0 +1,21 @@ +package org.dromara.common.core.exception.file; + +import org.dromara.common.core.exception.base.BaseException; + +import java.io.Serial; + +/** + * 文件信息异常类 + * + * @author ruoyi + */ +public class FileException extends BaseException { + + @Serial + private static final long serialVersionUID = 1L; + + public FileException(String code, Object[] args) { + super("file", code, args, null); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java new file mode 100644 index 0000000..fd907d2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java @@ -0,0 +1,52 @@ +package org.dromara.common.core.factory; + +import cn.hutool.core.lang.PatternPool; +import org.dromara.common.core.constant.RegexConstants; + +import java.util.regex.Pattern; + +/** + * 正则表达式模式池工厂 + *

初始化的时候将正则表达式加入缓存池当中

+ *

提高正则表达式的性能,避免重复编译相同的正则表达式

+ * + * @author 21001 + */ +public class RegexPatternPoolFactory extends PatternPool { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + public static final Pattern DICTIONARY_TYPE = get(RegexConstants.DICTIONARY_TYPE); + + /** + * 身份证号码(后6位) + */ + public static final Pattern ID_CARD_LAST_6 = get(RegexConstants.ID_CARD_LAST_6); + + /** + * QQ号码 + */ + public static final Pattern QQ_NUMBER = get(RegexConstants.QQ_NUMBER); + + /** + * 邮政编码 + */ + public static final Pattern POSTAL_CODE = get(RegexConstants.POSTAL_CODE); + + /** + * 注册账号 + */ + public static final Pattern ACCOUNT = get(RegexConstants.ACCOUNT); + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + public static final Pattern PASSWORD = get(RegexConstants.PASSWORD); + + /** + * 通用状态(0表示正常,1表示停用) + */ + public static final Pattern STATUS = get(RegexConstants.STATUS); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java new file mode 100644 index 0000000..af61b90 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.factory; + +import org.dromara.common.core.utils.StringUtils; +import org.springframework.beans.factory.config.YamlPropertiesFactoryBean; +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.support.DefaultPropertySourceFactory; +import org.springframework.core.io.support.EncodedResource; + +import java.io.IOException; + +/** + * yml 配置源工厂 + * + * @author Lion Li + */ +public class YmlPropertySourceFactory extends DefaultPropertySourceFactory { + + @Override + public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException { + String sourceName = resource.getResource().getFilename(); + if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) { + YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); + factory.setResources(resource.getResource()); + factory.afterPropertiesSet(); + return new PropertiesPropertySource(sourceName, factory.getObject()); + } + return super.createPropertySource(name, resource); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java new file mode 100644 index 0000000..b78a7f2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java @@ -0,0 +1,67 @@ +package org.dromara.common.core.service; + +import java.util.Map; + +/** + * 通用 字典服务 + * + * @author Lion Li + */ +public interface DictService { + + /** + * 分隔符 + */ + String SEPARATOR = ","; + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + String getDictLabel(String dictType, String dictValue, String separator); + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + String getDictValue(String dictType, String dictLabel, String separator); + + /** + * 获取字典下所有的字典值与标签 + * + * @param dictType 字典类型 + * @return dictValue为key,dictLabel为值组成的Map + */ + Map getAllDictByDictType(String dictType); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java new file mode 100644 index 0000000..9af6691 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java @@ -0,0 +1,45 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.TaskAssigneeDTO; +import org.dromara.common.core.domain.model.TaskAssigneeBody; + +/** + * 工作流设计器获取任务执行人 + * + * @author Lion Li + */ +public interface TaskAssigneeService { + + /** + * 查询角色并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery); + + /** + * 查询岗位并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery); + + /** + * 查询部门并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery); + + /** + * 查询用户并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java new file mode 100644 index 0000000..67cd54f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java @@ -0,0 +1,94 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.UserDTO; + +import java.util.List; + +/** + * 通用 用户服务 + * + * @author Lion Li + */ +public interface UserService { + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + String selectUserNameById(Long userId); + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户名称 + */ + String selectNicknameById(Long userId); + + /** + * 通过用户ID查询用户账户 + * + * @param userIds 用户ID 多个用逗号隔开 + * @return 用户名称 + */ + String selectNicknameByIds(String userIds); + + /** + * 通过用户ID查询用户手机号 + * + * @param userId 用户id + * @return 用户手机号 + */ + String selectPhonenumberById(Long userId); + + /** + * 通过用户ID查询用户邮箱 + * + * @param userId 用户id + * @return 用户邮箱 + */ + String selectEmailById(Long userId); + + /** + * 通过用户ID查询用户列表 + * + * @param userIds 用户ids + * @return 用户列表 + */ + List selectListByIds(List userIds); + + /** + * 通过角色ID查询用户ID + * + * @param roleIds 角色ids + * @return 用户ids + */ + List selectUserIdsByRoleIds(List roleIds); + + /** + * 通过角色ID查询用户 + * + * @param roleIds 角色ids + * @return 用户 + */ + List selectUsersByRoleIds(List roleIds); + + /** + * 通过部门ID查询用户 + * + * @param deptIds 部门ids + * @return 用户 + */ + List selectUsersByDeptIds(List deptIds); + + /** + * 通过岗位ID查询用户 + * + * @param postIds 岗位ids + * @return 用户 + */ + List selectUsersByPostIds(List postIds); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java new file mode 100644 index 0000000..abbcbff --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java @@ -0,0 +1,86 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.CompleteTaskDTO; +import org.dromara.common.core.domain.dto.StartProcessDTO; +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; + +import java.util.List; +import java.util.Map; + +/** + * 通用 工作流服务 + * + * @author may + */ +public interface WorkflowService { + + /** + * 运行中的实例 删除程实例,删除历史记录,删除业务与流程关联信息 + * + * @param businessIds 业务id + * @return 结果 + */ + boolean deleteInstance(List businessIds); + + /** + * 获取当前流程状态 + * + * @param taskId 任务id + * @return 状态 + */ + String getBusinessStatusByTaskId(Long taskId); + + /** + * 获取当前流程状态 + * + * @param businessId 业务id + * @return 状态 + */ + String getBusinessStatus(String businessId); + + /** + * 设置流程变量 + * + * @param instanceId 流程实例id + * @param variable 流程变量 + */ + void setVariable(Long instanceId, Map variable); + + /** + * 获取流程变量 + * + * @param instanceId 流程实例id + */ + Map instanceVariable(Long instanceId); + + /** + * 按照业务id查询流程实例id + * + * @param businessId 业务id + * @return 结果 + */ + Long getInstanceIdByBusinessId(String businessId); + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + void syncDef(String tenantId); + + /** + * 启动流程 + * + * @param startProcess 参数 + * @return 结果 + */ + StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess); + + /** + * 办理任务 + * + * @param completeTask 参数 + * @return 结果 + */ + boolean completeTask(CompleteTaskDTO completeTask); +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java new file mode 100644 index 0000000..b6acff7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java @@ -0,0 +1,93 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import io.github.linpeilie.Converter; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * Mapstruct 工具类 + *

参考文档:mapstruct-plus

+ * + * + * @author Michelle.Chung + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MapstructUtils { + + private final static Converter CONVERTER = SpringUtils.getBean(Converter.class); + + /** + * 将 T 类型对象,转换为 desc 类型的对象并返回 + * + * @param source 数据来源实体 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static V convert(T source, Class desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + return CONVERTER.convert(source, desc); + } + + /** + * 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象 + * + * @param source 数据来源实体 + * @param desc 转换后的对象 + * @return desc + */ + public static V convert(T source, V desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + return CONVERTER.convert(source, desc); + } + + /** + * 将 T 类型的集合,转换为 desc 类型的集合并返回 + * + * @param sourceList 数据来源实体列表 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static List convert(List sourceList, Class desc) { + if (ObjectUtil.isNull(sourceList)) { + return null; + } + if (CollUtil.isEmpty(sourceList)) { + return CollUtil.newArrayList(); + } + return CONVERTER.convert(sourceList, desc); + } + + /** + * 将 Map 转换为 beanClass 类型的集合并返回 + * + * @param map 数据来源 + * @param beanClass bean类 + * @return bean对象 + */ + public static T convert(Map map, Class beanClass) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(beanClass)) { + return null; + } + return CONVERTER.convert(map, beanClass); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java new file mode 100644 index 0000000..199fd82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java @@ -0,0 +1,60 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.util.ObjectUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.function.Function; + +/** + * 对象工具类 + * + * @author 秋辞未寒 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ObjectUtils extends ObjectUtil { + + /** + * 如果对象不为空,则获取对象中的某个字段 ObjectUtils.notNullGetter(user, User::getName); + * + * @param obj 对象 + * @param func 获取方法 + * @return 对象字段 + */ + public static E notNullGetter(T obj, Function func) { + if (isNotNull(obj) && isNotNull(func)) { + return func.apply(obj); + } + return null; + } + + /** + * 如果对象不为空,则获取对象中的某个字段,否则返回默认值 + * + * @param obj 对象 + * @param func 获取方法 + * @param defaultValue 默认值 + * @return 对象字段 + */ + public static E notNullGetter(T obj, Function func, E defaultValue) { + if (isNotNull(obj) && isNotNull(func)) { + return func.apply(obj); + } + return defaultValue; + } + + /** + * 如果值不为空,则返回值,否则返回默认值 + * + * @param obj 对象 + * @param defaultValue 默认值 + * @return 对象字段 + */ + public static T notNull(T obj, T defaultValue) { + if (isNotNull(obj)) { + return obj; + } + return defaultValue; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/PddUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/PddUtil.java new file mode 100644 index 0000000..10a86fb --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/PddUtil.java @@ -0,0 +1,27 @@ +package org.dromara.common.core.utils; + +import org.springframework.stereotype.Component; + +@Component +public final class PddUtil { + + + private static String accessToken; + + public static String getClientId(){ + return "203c5a7ba8bd4b8488d5e26f93052642"; + } + + public static String getClientSecret(){ + return "892ffaa86e12b7a3d8d2942b669d9aa520ad8179"; + } + + public static String getToken(){ + return accessToken; + } + + public static String setToken(String token){ + accessToken = token; + return accessToken; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java new file mode 100644 index 0000000..82ea5ca --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java @@ -0,0 +1,63 @@ +package org.dromara.common.core.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.*; + +/** + * 线程相关工具类. + * + * @author ruoyi + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Threads { + /** + * 停止线程池 + * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. + * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. + * 如果仍然超時,則強制退出. + * 另对在shutdown时线程本身被调用中断做了处理. + */ + public static void shutdownAndAwaitTermination(ExecutorService pool) { + if (pool != null && !pool.isShutdown()) { + pool.shutdown(); + try { + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + log.info("Pool did not terminate"); + } + } + } catch (InterruptedException ie) { + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + + /** + * 打印线程异常信息 + */ + public static void printException(Runnable r, Throwable t) { + if (t == null && r instanceof Future) { + try { + Future future = (Future) r; + if (future.isDone()) { + future.get(); + } + } catch (CancellationException ce) { + t = ce; + } catch (ExecutionException ee) { + t = ee.getCause(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (t != null) { + log.error(t.getMessage(), t); + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java new file mode 100644 index 0000000..c0733a3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java @@ -0,0 +1,103 @@ +package org.dromara.common.core.utils.file; + +import cn.hutool.core.io.FileUtil; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * 文件处理工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class FileUtils extends FileUtil { + + /** + * 下载文件名重新编码 + * + * @param response 响应对象 + * @param realFileName 真实文件名 + */ + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) { + String percentEncodedFileName = percentEncode(realFileName); + String contentDispositionValue = "attachment; filename=%s;filename*=utf-8''%s".formatted(percentEncodedFileName, percentEncodedFileName); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); + response.setHeader("Content-disposition", contentDispositionValue); + response.setHeader("download-filename", percentEncodedFileName); + } + + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * @return 百分号编码后的字符串 + */ + public static String percentEncode(String s) { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8); + return encode.replaceAll("\\+", "%20"); + } + + /** + * 从服务器下载文件到临时文件夹 + */ + public static String percentDecode(String fileName,String suffix) { + try { + // 1. 定义目标URL + URL url = new URL("http://111.229.25.150:8001/"+fileName+"."+suffix); + + // 2. 打开连接并获取输入流 + URLConnection connection = url.openConnection(); + try (InputStream inputStream = connection.getInputStream()) { + + // 3. 创建临时文件(或指定本地路径) + File tempFile = File.createTempFile("downloaded-", "."+suffix); + tempFile.deleteOnExit(); // 程序退出时删除临时文件 + + // 4. 将输入流写入临时文件 + try (FileOutputStream outputStream = new FileOutputStream(tempFile)) { + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + } + + // 5. 使用文件对象 + System.out.println("文件已保存至: " + tempFile.getAbsolutePath()); + return tempFile.getAbsolutePath(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + public static void writeFile(String filePath, String content) { + try (FileWriter fileWriter = new FileWriter(filePath)) { + fileWriter.write(content); + } catch (IOException e) { + throw new RuntimeException("Failed to write file", e); + } + } + + public static boolean isFileExists(String filePath) { + try { + Path path = Paths.get(filePath); + return Files.exists(path); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java new file mode 100644 index 0000000..6e2a44e --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java @@ -0,0 +1,67 @@ +package org.dromara.common.core.utils.ip; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.ObjectUtil; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.file.FileUtils; +import lombok.extern.slf4j.Slf4j; +import org.lionsoul.ip2region.xdb.Searcher; + +import java.io.File; + +/** + * 根据ip地址定位工具类,离线方式 + * 参考地址:集成 ip2region 实现离线IP地址定位库 + * + * @author lishuyan + */ +@Slf4j +public class RegionUtils { + + private static final Searcher SEARCHER; + + static { + String fileName = "/ip2region.xdb"; + File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName); + if (!FileUtils.exist(existFile)) { + ClassPathResource fileStream = new ClassPathResource(fileName); + if (ObjectUtil.isEmpty(fileStream.getStream())) { + throw new ServiceException("RegionUtils初始化失败,原因:IP地址库数据不存在!"); + } + FileUtils.writeFromStream(fileStream.getStream(), existFile); + } + + String dbPath = existFile.getPath(); + + // 1、从 dbPath 加载整个 xdb 到内存。 + byte[] cBuff; + try { + cBuff = Searcher.loadContentFromFile(dbPath); + } catch (Exception e) { + throw new ServiceException("RegionUtils初始化失败,原因:从ip2region.xdb文件加载内容失败!" + e.getMessage()); + } + // 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。 + try { + SEARCHER = Searcher.newWithBuffer(cBuff); + } catch (Exception e) { + throw new ServiceException("RegionUtils初始化失败,原因:" + e.getMessage()); + } + } + + /** + * 根据IP地址离线获取城市 + */ + public static String getCityInfo(String ip) { + try { + ip = ip.trim(); + // 3、执行查询 + String region = SEARCHER.search(ip); + return region.replace("0|", "").replace("|0", ""); + } catch (Exception e) { + log.error("IP地址离线获取城市异常 {}", ip); + return "未知"; + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000..367e8c9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java @@ -0,0 +1,56 @@ +package org.dromara.common.core.utils.reflect; + +import cn.hutool.core.util.ReflectUtil; +import org.dromara.common.core.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.lang.reflect.Method; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author Lion Li + */ +@SuppressWarnings("rawtypes") +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ReflectUtils extends ReflectUtil { + + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invoke(object, getterMethodName); + } + return (E) object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, E value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) { + if (i < names.length - 1) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invoke(object, getterMethodName); + } else { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + Method method = getMethodByName(object.getClass(), setterMethodName); + invoke(object, method, value); + } + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java new file mode 100644 index 0000000..1020c81 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java @@ -0,0 +1,56 @@ +package org.dromara.common.core.utils.sql; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.StringUtils; + +/** + * sql操作工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SqlUtil { + + /** + * 定义常用的 sql关键字 + */ + public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()"; + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new IllegalArgumentException("参数不符合规范,不能进行查询"); + } + return value; + } + + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } + + /** + * SQL关键字检查 + */ + public static void filterKeyword(String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new IllegalArgumentException("参数存在SQL注入风险"); + } + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java new file mode 100644 index 0000000..0275899 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java @@ -0,0 +1,9 @@ +package org.dromara.common.core.validate; + +/** + * 校验分组 add + * + * @author Lion Li + */ +public interface AddGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java new file mode 100644 index 0000000..3d4adb9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java @@ -0,0 +1,48 @@ +package org.dromara.common.core.validate.enumd; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.*; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * 自定义枚举校验 + * + * @author 秋辞未寒 + * @date 2024-12-09 + */ +@Documented +@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) +@Retention(RUNTIME) +@Repeatable(EnumPattern.List.class) // 允许在同一元素上多次使用该注解 +@Constraint(validatedBy = {EnumPatternValidator.class}) +public @interface EnumPattern { + + /** + * 需要校验的枚举类型 + */ + Class> type(); + + /** + * 枚举类型校验值字段名称 + * 需确保该字段实现了 getter 方法 + */ + String fieldName(); + + String message() default "输入值不在枚举范围内"; + + Class[] groups() default {}; + + Class[] payload() default {}; + + @Documented + @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}) + @Retention(RUNTIME) + @interface List { + EnumPattern[] value(); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java new file mode 100644 index 0000000..eed495f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java @@ -0,0 +1,26 @@ +package org.dromara.common.core.xss; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义xss校验注解 + * + * @author Lion Li + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) +@Constraint(validatedBy = {XssValidator.class}) +public @interface Xss { + + String message() default "不允许任何脚本运行"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/ruoyi-common/ruoyi-common-doc/pom.xml b/ruoyi-common/ruoyi-common-doc/pom.xml new file mode 100644 index 0000000..c6199a1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/pom.xml @@ -0,0 +1,41 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-doc + + + ruoyi-common-doc 系统接口 + + + + + org.dromara + ruoyi-common-core + + + + org.springdoc + springdoc-openapi-starter-webmvc-api + + + + com.github.therapi + therapi-runtime-javadoc + + + + com.fasterxml.jackson.module + jackson-module-kotlin + + + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/pom.xml b/ruoyi-common/ruoyi-common-encrypt/pom.xml new file mode 100644 index 0000000..ed4910e --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/pom.xml @@ -0,0 +1,54 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-encrypt + + + ruoyi-common-encrypt 数据加解密模块 + + + + + + org.dromara + ruoyi-common-core + + + + org.bouncycastle + bcprov-jdk15to18 + + + + cn.hutool + hutool-crypto + + + + org.springframework + spring-webmvc + + + + com.baomidou + mybatis-plus-spring-boot3-starter + true + + + org.mybatis + mybatis-spring + + + + + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java new file mode 100644 index 0000000..2f02eaf --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java @@ -0,0 +1,41 @@ +package org.dromara.common.encrypt.core; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import lombok.Data; + +/** + * 加密上下文 用于encryptor传递必要的参数。 + * + * @author 老马 + * @version 4.6.0 + */ +@Data +public class EncryptContext { + + /** + * 默认算法 + */ + private AlgorithmType algorithm; + + /** + * 安全秘钥 + */ + private String password; + + /** + * 公钥 + */ + private String publicKey; + + /** + * 私钥 + */ + private String privateKey; + + /** + * 编码方式,base64/hex + */ + private EncodeType encode; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java new file mode 100644 index 0000000..b5f194d --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java @@ -0,0 +1,159 @@ +package org.dromara.common.encrypt.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.io.Resources; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.EncryptField; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.ClassMetadata; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.util.ClassUtils; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 加密管理类 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@NoArgsConstructor +public class EncryptorManager { + + /** + * 缓存加密器 + */ + Map encryptorMap = new ConcurrentHashMap<>(); + + /** + * 类加密字段缓存 + */ + Map, Set> fieldCache = new ConcurrentHashMap<>(); + + /** + * 构造方法传入类加密字段缓存 + * + * @param typeAliasesPackage 实体类包 + */ + public EncryptorManager(String typeAliasesPackage) { + scanEncryptClasses(typeAliasesPackage); + } + + + /** + * 获取类加密字段缓存 + */ + public Set getFieldCache(Class sourceClazz) { + return ObjectUtils.notNullGetter(fieldCache, f -> f.get(sourceClazz)); + } + + /** + * 注册加密执行者到缓存 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public IEncryptor registAndGetEncryptor(EncryptContext encryptContext) { + int key = encryptContext.hashCode(); + if (encryptorMap.containsKey(key)) { + return encryptorMap.get(key); + } + IEncryptor encryptor = ReflectUtil.newInstance(encryptContext.getAlgorithm().getClazz(), encryptContext); + encryptorMap.put(key, encryptor); + return encryptor; + } + + /** + * 移除缓存中的加密执行者 + * + * @param encryptContext 加密执行者需要的相关配置参数 + */ + public void removeEncryptor(EncryptContext encryptContext) { + this.encryptorMap.remove(encryptContext.hashCode()); + } + + /** + * 根据配置进行加密。会进行本地缓存对应的算法和对应的秘钥信息。 + * + * @param value 待加密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String encrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.encrypt(value, encryptContext.getEncode()); + } + + /** + * 根据配置进行解密 + * + * @param value 待解密的值 + * @param encryptContext 加密相关的配置信息 + */ + public String decrypt(String value, EncryptContext encryptContext) { + IEncryptor encryptor = this.registAndGetEncryptor(encryptContext); + return encryptor.decrypt(value); + } + + /** + * 通过 typeAliasesPackage 设置的扫描包 扫描缓存实体 + */ + private void scanEncryptClasses(String typeAliasesPackage) { + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); + String[] packagePatternArray = StringUtils.splitPreserveAllTokens(typeAliasesPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; + try { + for (String packagePattern : packagePatternArray) { + String path = ClassUtils.convertClassNameToResourcePath(packagePattern); + Resource[] resources = resolver.getResources(classpath + path + "/*.class"); + for (Resource resource : resources) { + ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); + Class clazz = Resources.classForName(classMetadata.getClassName()); + Set encryptFieldSet = getEncryptFieldSetFromClazz(clazz); + if (CollUtil.isNotEmpty(encryptFieldSet)) { + fieldCache.put(clazz, encryptFieldSet); + } + } + } + } catch (Exception e) { + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); + } + } + + /** + * 获得一个类的加密字段集合 + */ + private Set getEncryptFieldSetFromClazz(Class clazz) { + Set fieldSet = new HashSet<>(); + // 判断clazz如果是接口,内部类,匿名类就直接返回 + if (clazz.isInterface() || clazz.isMemberClass() || clazz.isAnonymousClass()) { + return fieldSet; + } + while (clazz != null) { + Field[] fields = clazz.getDeclaredFields(); + fieldSet.addAll(Arrays.asList(fields)); + clazz = clazz.getSuperclass(); + } + fieldSet = fieldSet.stream().filter(field -> + field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class) + .collect(Collectors.toSet()); + for (Field field : fieldSet) { + field.setAccessible(true); + } + return fieldSet; + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java new file mode 100644 index 0000000..e4dc597 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java @@ -0,0 +1,55 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + +/** + * AES算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class AesEncryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public AesEncryptor(EncryptContext context) { + super(context); + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.AES; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptByAesHex(value, context.getPassword()); + } else { + return EncryptUtils.encryptByAes(value, context.getPassword()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptByAes(value, context.getPassword()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java new file mode 100644 index 0000000..0028548 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java @@ -0,0 +1,48 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + +/** + * Base64算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Base64Encryptor extends AbstractEncryptor { + + public Base64Encryptor(EncryptContext context) { + super(context); + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.BASE64; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + return EncryptUtils.encryptByBase64(value); + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptByBase64(value); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java new file mode 100644 index 0000000..adaf674 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java @@ -0,0 +1,55 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.utils.EncryptUtils; + +/** + * sm4算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Sm4Encryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public Sm4Encryptor(EncryptContext context) { + super(context); + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM4; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptBySm4Hex(value, context.getPassword()); + } else { + return EncryptUtils.encryptBySm4(value, context.getPassword()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptBySm4(value, context.getPassword()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java new file mode 100644 index 0000000..79d58da --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java @@ -0,0 +1,110 @@ +package org.dromara.common.encrypt.filter; + +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.encrypt.properties.ApiDecryptProperties; +import org.springframework.http.HttpMethod; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import java.io.IOException; + + +/** + * Crypto 过滤器 + * + * @author wdhcr + */ +public class CryptoFilter implements Filter { + private final ApiDecryptProperties properties; + + public CryptoFilter(ApiDecryptProperties properties) { + this.properties = properties; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + HttpServletRequest servletRequest = (HttpServletRequest) request; + HttpServletResponse servletResponse = (HttpServletResponse) response; + // 获取加密注解 + ApiEncrypt apiEncrypt = this.getApiEncryptAnnotation(servletRequest); + boolean responseFlag = apiEncrypt != null && apiEncrypt.response(); + ServletRequest requestWrapper = null; + ServletResponse responseWrapper = null; + EncryptResponseBodyWrapper responseBodyWrapper = null; + + // 是否为 put 或者 post 请求 + if (HttpMethod.PUT.matches(servletRequest.getMethod()) || HttpMethod.POST.matches(servletRequest.getMethod())) { + // 是否存在加密标头 + String headerValue = servletRequest.getHeader(properties.getHeaderFlag()); + if (StringUtils.isNotBlank(headerValue)) { + // 请求解密 + requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPrivateKey(), properties.getHeaderFlag()); + } else { + // 是否有注解,有就报错,没有放行 + if (ObjectUtil.isNotNull(apiEncrypt)) { + HandlerExceptionResolver exceptionResolver = SpringUtils.getBean("handlerExceptionResolver", HandlerExceptionResolver.class); + exceptionResolver.resolveException( + servletRequest, servletResponse, null, + new ServiceException("没有访问权限,请联系管理员授权", HttpStatus.FORBIDDEN)); + return; + } + } + } + + // 判断是否响应加密 + if (responseFlag) { + responseBodyWrapper = new EncryptResponseBodyWrapper(servletResponse); + responseWrapper = responseBodyWrapper; + } + + chain.doFilter( + ObjectUtil.defaultIfNull(requestWrapper, request), + ObjectUtil.defaultIfNull(responseWrapper, response)); + + if (responseFlag) { + servletResponse.reset(); + // 对原始内容加密 + String encryptContent = responseBodyWrapper.getEncryptContent( + servletResponse, properties.getPublicKey(), properties.getHeaderFlag()); + // 对加密后的内容写出 + servletResponse.getWriter().write(encryptContent); + } + } + + /** + * 获取 ApiEncrypt 注解 + */ + private ApiEncrypt getApiEncryptAnnotation(HttpServletRequest servletRequest) { + RequestMappingHandlerMapping handlerMapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); + // 获取注解 + try { + HandlerExecutionChain mappingHandler = handlerMapping.getHandler(servletRequest); + if (ObjectUtil.isNotNull(mappingHandler)) { + Object handler = mappingHandler.getHandler(); + if (ObjectUtil.isNotNull(handler)) { + // 从handler获取注解 + if (handler instanceof HandlerMethod handlerMethod) { + return handlerMethod.getMethodAnnotation(ApiEncrypt.class); + } + } + } + } catch (Exception e) { + return null; + } + return null; + } + + @Override + public void destroy() { + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..132cf29 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,3 @@ +org.dromara.common.encrypt.config.EncryptorAutoConfiguration +org.dromara.common.encrypt.config.ApiDecryptAutoConfiguration + diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java new file mode 100644 index 0000000..07cc4c4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java @@ -0,0 +1,52 @@ +package org.dromara.common.excel.convert; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +/** + * 大数值转换 + * Excel 数值长度位15位 大于15位的数值转换位字符串 + * + * @author Lion Li + */ +@Slf4j +public class ExcelBigNumberConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return Convert.toLong(cellData.getData()); + } + + @Override + public WriteCellData convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNotNull(object)) { + String str = Convert.toStr(object); + if (str.length() > 15) { + return new WriteCellData<>(str); + } + } + WriteCellData cellData = new WriteCellData<>(new BigDecimal(object)); + cellData.setType(CellDataTypeEnum.NUMBER); + return cellData; + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java new file mode 100644 index 0000000..7373e12 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java @@ -0,0 +1,73 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 默认excel返回对象 + * + * @author Yjoioooo + * @author Lion Li + */ +public class DefaultExcelResult implements ExcelResult { + + /** + * 数据对象list + */ + @Setter + private List list; + + /** + * 错误信息列表 + */ + @Setter + private List errorList; + + public DefaultExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefaultExcelResult(List list, List errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefaultExcelResult(ExcelResult excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return errorList; + } + + /** + * 获取导入回执 + * + * @return 导入回执 + */ + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorCount == 0) { + return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); + } else { + return ""; + } + } + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java new file mode 100644 index 0000000..8b53a0c --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java @@ -0,0 +1,149 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.exception.ServiceException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + *

Excel下拉可选项

+ * 注意:为确保下拉框解析正确,传值务必使用createOptionValue()做为值的拼接 + * + * @author Emil.Zhang + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuppressWarnings("unused") +public class DropDownOptions { + /** + * 一级下拉所在列index,从0开始算 + */ + private int index = 0; + /** + * 二级下拉所在的index,从0开始算,不能与一级相同 + */ + private int nextIndex = 0; + /** + * 一级下拉所包含的数据 + */ + private List options = new ArrayList<>(); + /** + * 二级下拉所包含的数据Map + *

以每一个一级选项值为Key,每个一级选项对应的二级数据为Value

+ */ + private Map> nextOptions = new HashMap<>(); + /** + * 分隔符 + */ + private static final String DELIMITER = "_"; + + /** + * 创建只有一级的下拉选 + */ + public DropDownOptions(int index, List options) { + this.index = index; + this.options = options; + } + + /** + *

创建每个选项可选值

+ *

注意:不能以数字,特殊符号开头,选项中不可以包含任何运算符号

+ * + * @param vars 可选值内包含的参数 + * @return 合规的可选值 + */ + public static String createOptionValue(Object... vars) { + StringBuilder stringBuffer = new StringBuilder(); + String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$"; + for (int i = 0; i < vars.length; i++) { + String var = StrUtil.trimToEmpty(String.valueOf(vars[i])); + if (!var.matches(regex)) { + throw new ServiceException("选项数据不符合规则,仅允许使用中英文字符以及数字"); + } + stringBuffer.append(var); + if (i < vars.length - 1) { + // 直至最后一个前,都以_作为切割线 + stringBuffer.append(DELIMITER); + } + } + if (stringBuffer.toString().matches("^\\d_*$")) { + throw new ServiceException("禁止以数字开头"); + } + return stringBuffer.toString(); + } + + /** + * 将处理后合理的可选值解析为原始的参数 + * + * @param option 经过处理后的合理的可选项 + * @return 原始的参数 + */ + public static List analyzeOptionValue(String option) { + return StrUtil.split(option, DELIMITER, true, true); + } + + /** + * 创建级联下拉选项 + * + * @param parentList 父实体可选项原始数据 + * @param parentIndex 父下拉选位置 + * @param sonList 子实体可选项原始数据 + * @param sonIndex 子下拉选位置 + * @param parentHowToGetIdFunction 父类如何获取唯一标识 + * @param sonHowToGetParentIdFunction 子类如何获取父类的唯一标识 + * @param howToBuildEveryOption 如何生成下拉选内容 + * @return 级联下拉选项 + */ + public static DropDownOptions buildLinkedOptions(List parentList, + int parentIndex, + List sonList, + int sonIndex, + Function parentHowToGetIdFunction, + Function sonHowToGetParentIdFunction, + Function howToBuildEveryOption) { + DropDownOptions parentLinkSonOptions = new DropDownOptions(); + // 先创建父类的下拉 + parentLinkSonOptions.setIndex(parentIndex); + parentLinkSonOptions.setOptions( + parentList.stream() + .map(howToBuildEveryOption) + .collect(Collectors.toList()) + ); + // 提取父-子级联下拉 + Map> sonOptions = new HashMap<>(); + // 父级依据自己的ID分组 + Map> parentGroupByIdMap = + parentList.stream().collect(Collectors.groupingBy(parentHowToGetIdFunction)); + // 遍历每个子集,提取到Map中 + sonList.forEach(everySon -> { + if (parentGroupByIdMap.containsKey(sonHowToGetParentIdFunction.apply(everySon))) { + // 找到对应的上级 + T parentObj = parentGroupByIdMap.get(sonHowToGetParentIdFunction.apply(everySon)).get(0); + // 提取名称和ID作为Key + String key = howToBuildEveryOption.apply(parentObj); + // Key对应的Value + List thisParentSonOptionList; + if (sonOptions.containsKey(key)) { + thisParentSonOptionList = sonOptions.get(key); + } else { + thisParentSonOptionList = new ArrayList<>(); + sonOptions.put(key, thisParentSonOptionList); + } + // 往Value中添加当前子集选项 + thisParentSonOptionList.add(howToBuildEveryOption.apply(everySon)); + } + }); + parentLinkSonOptions.setNextIndex(sonIndex); + parentLinkSonOptions.setNextOptions(sonOptions); + return parentLinkSonOptions; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/HeadCommentWriteHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/HeadCommentWriteHandler.java new file mode 100644 index 0000000..a1e5f19 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/HeadCommentWriteHandler.java @@ -0,0 +1,134 @@ +package org.dromara.zhishu.handler; + +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class HeadCommentWriteHandler implements CellWriteHandler { + + private final Map commentConfigMap = new HashMap<>(); + + // 缓存样式,避免重复创建 + private CellStyle cachedHeadStyle; + + public HeadCommentWriteHandler() { + commentConfigMap.put(0, new CommentConfig("\n必填项\n\n可填写13位ISBN\n\n系统会根据ISBN进行图书匹配和上传", 2, 7)); + commentConfigMap.put(1, new CommentConfig("\n商品ID\n\n更新价格、库存、上下架状态时选填,若空白则根据ISBN查询商品进行修改", 2, 6)); + commentConfigMap.put(2, new CommentConfig("\n商品编码\n\n更新价格、库存、上下架状态时选填,若空白则优先根据商品ID查询,在根据ISBN查询", 2, 6)); + commentConfigMap.put(3, new CommentConfig("\n可空白。\n\n商品标题中的书名优先使用表格中的书名。如果表格书名空白,则商品标题中的书名采用系统数据库中的书名", 3, 7)); + commentConfigMap.put(4, new CommentConfig("\n库存数量\n\n修改库存必填,填写的库存数量就是平台上的实际库存数量", 2, 6)); + commentConfigMap.put(5, new CommentConfig("\n创建时间\n\n导出项,平台的商品创建时间", 2, 5)); + commentConfigMap.put(6, new CommentConfig("\n价格\n\n注意这个价格是拼单价的基础价,在这个价格的基础上根据店铺的价格模板进行计算拼单价。\n\n单买价为计算后的价格加1元", 3, 7)); + commentConfigMap.put(7, new CommentConfig("\n规格编码\n\n拼多多店铺中的规格编码\n孔夫子店铺中的货号\n若上传时为空,优先选择商品编码,若已经为空则默认ISBN", 2, 9)); + commentConfigMap.put(8, new CommentConfig("\n可空白\n\n设置平台上商品的上下架状态\n\n拼多多发布商品不能选下架状态", 2, 5)); + commentConfigMap.put(9, new CommentConfig("\n可空白\n\n填写图片http地址\n\n发布时轮播图使用的图片,若为空或无法访问则系统会根据ISBN进行图书匹配获取图片\n多张图片链接用逗号进行分割", 3, 5)); + } + + @Override + public void afterCellDispose(CellWriteHandlerContext context) { + if (context.getRowIndex() != 0) { + return; + } + + Cell cell = context.getCell(); + if (cell == null) { + return; + } + + // 获取或创建表头单元格样式 + CellStyle style = getOrCreateHeadStyle(cell.getSheet().getWorkbook()); + cell.setCellStyle(style); + + // 添加带格式的批注 + int columnIndex = cell.getColumnIndex(); + CommentConfig config = commentConfigMap.get(columnIndex); + if (config != null) { + addStyledComment(cell, config); + } + } + + /** + * 获取或创建表头样式(单例模式) + */ + private CellStyle getOrCreateHeadStyle(Workbook workbook) { + if (cachedHeadStyle == null) { + Font font = workbook.createFont(); + font.setBold(true); + font.setFontHeightInPoints((short) 16); + + cachedHeadStyle = workbook.createCellStyle(); + cachedHeadStyle.setFont(font); + cachedHeadStyle.setWrapText(true); + cachedHeadStyle.setAlignment(HorizontalAlignment.CENTER); + cachedHeadStyle.setVerticalAlignment(VerticalAlignment.CENTER); + cachedHeadStyle.setBorderTop(BorderStyle.THIN); + cachedHeadStyle.setBorderBottom(BorderStyle.THIN); + cachedHeadStyle.setBorderLeft(BorderStyle.THIN); + cachedHeadStyle.setBorderRight(BorderStyle.THIN); + } + return cachedHeadStyle; + } + + /** + * 添加带格式的批注(加粗、字体大小) + */ + private void addStyledComment(Cell cell, CommentConfig config) { + try { + Sheet sheet = cell.getSheet(); + Drawing drawing = sheet.createDrawingPatriarch(); + int columnIndex = cell.getColumnIndex(); + + Comment comment = drawing.createCellComment( + new XSSFClientAnchor(0, 0, 0, 0, + (short) columnIndex, 0, + (short) (columnIndex + config.col2), config.row2) + ); + + // 创建带格式的批注文本 + XSSFRichTextString richText = new XSSFRichTextString(config.commentText); + + // 获取批注字体(加粗、大小14号) + Font commentFont = cell.getSheet().getWorkbook().createFont(); + commentFont.setBold(true); + commentFont.setFontHeightInPoints((short) 14); + + // 将整个批注文本应用字体样式 + richText.applyFont(commentFont); + + // 可选:只对第一行(标题)加粗并放大字体 + // int firstLineEnd = config.commentText.indexOf("\n"); + // if (firstLineEnd > 0) { + // Font titleFont = cell.getSheet().getWorkbook().createFont(); + // titleFont.setBold(true); + // titleFont.setFontHeightInPoints((short) 16); + // richText.applyFont(0, firstLineEnd, titleFont); + // } + + comment.setString(richText); + comment.setAuthor("系统"); + cell.setCellComment(comment); + + log.debug("为第 {} 列添加带格式批注", columnIndex); + } catch (Exception e) { + log.error("添加批注失败", e); + } + } + + private static class CommentConfig { + String commentText; + int col2; + int row2; + public CommentConfig(String commentText, int col2, int row2) { + this.commentText = commentText; + this.col2 = col2; + this.row2 = row2; + } + } +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java new file mode 100644 index 0000000..5a27e91 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java @@ -0,0 +1,146 @@ +package org.dromara.common.idempotent.aspectj; + +import cn.dev33.satoken.SaManager; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.SecureUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.time.Duration; +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; + +/** + * 防止重复提交(参考美团GTIS防重系统) + * + * @author Lion Li + */ +@Aspect +public class RepeatSubmitAspect { + + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + + @Before("@annotation(repeatSubmit)") + public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { + // 如果注解不为0 则使用注解数值 + long interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval()); + + if (interval < 1000) { + throw new ServiceException("重复提交间隔时间不能小于'1'秒"); + } + HttpServletRequest request = ServletUtils.getRequest(); + String nowParams = argsArrayToString(point.getArgs()); + + // 请求地址(作为存放cache的key值) + String url = request.getRequestURI(); + + // 唯一值(没有消息头则使用请求地址) + String submitKey = StringUtils.trimToEmpty(request.getHeader(SaManager.getConfig().getTokenName())); + + submitKey = SecureUtil.md5(submitKey + ":" + nowParams); + // 唯一标识(指定key + url + 消息头) + String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey; + if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) { + KEY_CACHE.set(cacheRepeatKey); + } else { + String message = repeatSubmit.message(); + if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { + message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); + } + throw new ServiceException(message); + } + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) { + if (jsonResult instanceof R r) { + try { + // 成功则不删除redis数据 保证在有效时间内无法重复提交 + if (r.getCode() == R.SUCCESS) { + return; + } + RedisUtils.deleteObject(KEY_CACHE.get()); + } finally { + KEY_CACHE.remove(); + } + } + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) { + RedisUtils.deleteObject(KEY_CACHE.get()); + KEY_CACHE.remove(); + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray) { + StringJoiner params = new StringJoiner(" "); + if (ArrayUtil.isEmpty(paramsArray)) { + return params.toString(); + } + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + params.add(JsonUtils.toJsonString(o)); + } + } + return params.toString(); + } + + /** + * 判断是否需要过滤的对象。 + * + * @param o 对象信息。 + * @return 如果是需要过滤的对象,则返回true;否则返回false。 + */ + @SuppressWarnings("rawtypes") + public boolean isFilterObject(final Object o) { + Class clazz = o.getClass(); + if (clazz.isArray()) { + return MultipartFile.class.isAssignableFrom(clazz.getComponentType()); + } else if (Collection.class.isAssignableFrom(clazz)) { + Collection collection = (Collection) o; + for (Object value : collection) { + return value instanceof MultipartFile; + } + } else if (Map.class.isAssignableFrom(clazz)) { + Map map = (Map) o; + for (Object value : map.values()) { + return value instanceof MultipartFile; + } + } + return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse + || o instanceof BindingResult; + } + +} diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java new file mode 100644 index 0000000..fcb9d03 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java @@ -0,0 +1,21 @@ +package org.dromara.common.idempotent.config; + +import org.dromara.common.idempotent.aspectj.RepeatSubmitAspect; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisConfiguration; + +/** + * 幂等功能配置 + * + * @author Lion Li + */ +@AutoConfiguration(after = RedisConfiguration.class) +public class IdempotentConfig { + + @Bean + public RepeatSubmitAspect repeatSubmitAspect() { + return new RepeatSubmitAspect(); + } + +} diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..f2fa958 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.idempotent.config.IdempotentConfig diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java new file mode 100644 index 0000000..cba3753 --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java @@ -0,0 +1,37 @@ +package org.dromara.common.job.config; + +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import ch.qos.logback.classic.spi.ILoggingEvent; +import com.aizuda.snailjob.client.common.appender.SnailLogbackAppender; +import com.aizuda.snailjob.client.common.event.SnailClientStartingEvent; +import com.aizuda.snailjob.client.starter.EnableSnailJob; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * 启动定时任务 + * + * @author opensnail + * @date 2024-05-17 + */ +@AutoConfiguration +@ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true") +@EnableScheduling +@EnableSnailJob +public class SnailJobConfig { + + @EventListener(SnailClientStartingEvent.class) + public void onStarting(SnailClientStartingEvent event) { + LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); + SnailLogbackAppender ca = new SnailLogbackAppender<>(); + ca.setName("snail_log_appender"); + ca.start(); + Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME); + rootLogger.addAppender(ca); + } + +} diff --git a/ruoyi-common/ruoyi-common-json/pom.xml b/ruoyi-common/ruoyi-common-json/pom.xml new file mode 100644 index 0000000..870df5c --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/pom.xml @@ -0,0 +1,37 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-json + + + ruoyi-common-json 序列化模块 + + + + + org.dromara + ruoyi-common-core + + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + + diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java new file mode 100644 index 0000000..8f5a45d --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java @@ -0,0 +1,47 @@ +package org.dromara.common.json.config; + +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import org.dromara.common.json.handler.BigNumberSerializer; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.context.annotation.Bean; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * jackson 配置 + * + * @author Lion Li + */ +@Slf4j +@AutoConfiguration(before = JacksonAutoConfiguration.class) +public class JacksonConfig { + + @Bean + public Jackson2ObjectMapperBuilderCustomizer customizer() { + return builder -> { + // 全局配置序列化返回 JSON 处理 + JavaTimeModule javaTimeModule = new JavaTimeModule(); + javaTimeModule.addSerializer(Long.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(Long.TYPE, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigInteger.class, BigNumberSerializer.INSTANCE); + javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + builder.modules(javaTimeModule); + builder.timeZone(TimeZone.getDefault()); + log.info("初始化 jackson 配置"); + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..1625397 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.json.config.JacksonConfig diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java new file mode 100644 index 0000000..d303dc3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java @@ -0,0 +1,18 @@ +package org.dromara.common.log.enums; + +/** + * 操作状态 + * + * @author ruoyi + */ +public enum BusinessStatus { + /** + * 成功 + */ + SUCCESS, + + /** + * 失败 + */ + FAIL, +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java new file mode 100644 index 0000000..2d25ebb --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java @@ -0,0 +1,58 @@ +package org.dromara.common.log.enums; + +/** + * 业务操作类型 + * + * @author ruoyi + */ +public enum BusinessType { + /** + * 其它 + */ + OTHER, + + /** + * 新增 + */ + INSERT, + + /** + * 修改 + */ + UPDATE, + + /** + * 删除 + */ + DELETE, + + /** + * 授权 + */ + GRANT, + + /** + * 导出 + */ + EXPORT, + + /** + * 导入 + */ + IMPORT, + + /** + * 强退 + */ + FORCE, + + /** + * 生成代码 + */ + GENCODE, + + /** + * 清空数据 + */ + CLEAN, +} diff --git a/ruoyi-common/ruoyi-common-mail/pom.xml b/ruoyi-common/ruoyi-common-mail/pom.xml new file mode 100644 index 0000000..c0e1b2e --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/pom.xml @@ -0,0 +1,34 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-mail + + + ruoyi-common-mail 邮件模块 + + + + + org.dromara + ruoyi-common-core + + + + jakarta.mail + jakarta.mail-api + + + org.eclipse.angus + jakarta.mail + + + + diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java new file mode 100644 index 0000000..e44aa3d --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java @@ -0,0 +1,75 @@ +package org.dromara.common.mail.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * JavaMail 配置属性 + * + * @author Michelle.Chung + */ +@Data +@ConfigurationProperties(prefix = "mail") +public class MailProperties { + + /** + * 过滤开关 + */ + private Boolean enabled; + + /** + * SMTP服务器域名 + */ + private String host; + + /** + * SMTP服务端口 + */ + private Integer port; + + /** + * 是否需要用户名密码验证 + */ + private Boolean auth; + + /** + * 用户名 + */ + private String user; + + /** + * 密码 + */ + private String pass; + + /** + * 发送方,遵循RFC-822标准
+ * 发件人可以是以下形式: + * + *
+     * 1. user@xxx.xx
+     * 2.  name <user@xxx.xx>
+     * 
+ */ + private String from; + + /** + * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。 + */ + private Boolean starttlsEnable; + + /** + * 使用 SSL安全连接 + */ + private Boolean sslEnable; + + /** + * SMTP超时时长,单位毫秒,缺省值不超时 + */ + private Long timeout; + + /** + * Socket连接超时值,单位毫秒,缺省值不超时 + */ + private Long connectionTimeout; +} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java new file mode 100644 index 0000000..a28701f --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java @@ -0,0 +1,469 @@ +package org.dromara.common.mail.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.JakartaMail; +import cn.hutool.extra.mail.JakartaUserPassAuthenticator; +import cn.hutool.extra.mail.MailAccount; +import jakarta.mail.Authenticator; +import jakarta.mail.Session; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; + +import java.io.File; +import java.io.InputStream; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * 邮件工具类 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MailUtils { + + private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class); + + /** + * 获取邮件发送实例 + */ + public static MailAccount getMailAccount() { + return ACCOUNT; + } + + /** + * 获取邮件发送实例 (自定义发送人以及授权码) + * + * @param user 发送人 + * @param pass 授权码 + */ + public static MailAccount getMailAccount(String from, String user, String pass) { + ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom())); + ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser())); + ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass())); + return ACCOUNT; + } + + /** + * 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendText(String to, String subject, String content, File... files) { + return send(to, subject, content, false, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, File... files) { + return send(to, subject, content, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送文本邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + */ + public static String sendText(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, false, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, Map imageMap, File... files) { + return send(to, subject, content, imageMap, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, Map imageMap, File... files) { + return send(tos, subject, content, imageMap, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, + boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + + /** + * 根据配置文件,获取邮件客户端会话 + * + * @param mailAccount 邮件账户配置 + * @param isSingleton 是否单例(全局共享会话) + * @return {@link Session} + * @since 5.5.7 + */ + public static Session getSession(MailAccount mailAccount, boolean isSingleton) { + Authenticator authenticator = null; + if (mailAccount.isAuth()) { + authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass()); + } + + return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) // + : Session.getInstance(mailAccount.getSmtpProps(), authenticator); + } + + // ------------------------------------------------------------------------------------------------------------------------ Private method start + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param useGlobalSession 是否全局共享Session + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:${cid} + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection tos, Collection ccs, Collection bccs, String subject, String content, + Map imageMap, boolean isHtml, File... files) { + final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession); + + // 可选抄送人 + if (CollUtil.isNotEmpty(ccs)) { + mail.setCcs(ccs.toArray(new String[0])); + } + // 可选密送人 + if (CollUtil.isNotEmpty(bccs)) { + mail.setBccs(bccs.toArray(new String[0])); + } + + mail.setTos(tos.toArray(new String[0])); + mail.setTitle(subject); + mail.setContent(content); + mail.setHtml(isHtml); + mail.setFiles(files); + + // 图片 + if (MapUtil.isNotEmpty(imageMap)) { + for (Entry entry : imageMap.entrySet()) { + mail.addImage(entry.getKey(), entry.getValue()); + // 关闭流 + IoUtil.close(entry.getValue()); + } + } + + return mail.send(); + } + + /** + * 将多个联系人转为列表,分隔符为逗号或者分号 + * + * @param addresses 多个联系人,如果为空返回null + * @return 联系人列表 + */ + private static List splitAddress(String addresses) { + if (StrUtil.isBlank(addresses)) { + return null; + } + + List result; + if (StrUtil.contains(addresses, CharUtil.COMMA)) { + result = StrUtil.splitTrim(addresses, CharUtil.COMMA); + } else if (StrUtil.contains(addresses, ';')) { + result = StrUtil.splitTrim(addresses, ';'); + } else { + result = CollUtil.newArrayList(addresses); + } + return result; + } + // ------------------------------------------------------------------------------------------------------------------------ Private method end +} diff --git a/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..ef0cf11 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.mail.config.MailConfig diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java new file mode 100644 index 0000000..64e18ad --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java @@ -0,0 +1,169 @@ +package org.dromara.common.mybatis.core.page; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.sql.SqlUtil; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 分页查询实体类 + * + * @author Lion Li + */ +@Data +public class PageQuery implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 分页大小 + */ + private Integer pageSize; + + /** + * 当前页数 + */ + private Integer pageNum; + + /** + * 排序列 + */ + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + private String isAsc; + + /** + * 当前记录起始索引 默认值 + */ + public static final int DEFAULT_PAGE_NUM = 1; + + /** + * 每页显示记录数 默认值 默认查全部 + */ + // public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; + + + // 修复:设置合理的默认分页大小 + public static final int DEFAULT_PAGE_SIZE = 20; + + // 添加最大分页大小限制 + public static final int MAX_PAGE_SIZE = 1000; + + public static final int min_size=0; + + /** + * 构建分页对象 + */ + // public Page build() { + // Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); + // Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); + // + // if (pageNum <= 0) { + // pageNum = DEFAULT_PAGE_NUM; + // } + // Page page = new Page<>(pageNum, pageSize); + // List orderItems = buildOrderItem(); + // if (CollUtil.isNotEmpty(orderItems)) { + // page.addOrder(orderItems); + // } + // return page; + // } + + + + /** + * 构建分页对象 + */ + public Page build() { + Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); + Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); + + // 修复:验证分页参数 + if (pageNum <= 0) { + pageNum = DEFAULT_PAGE_NUM; + } + if (pageSize <= 0) { + pageSize = DEFAULT_PAGE_SIZE; + } + // 修复:限制最大分页大小 + if (pageSize > MAX_PAGE_SIZE) { + pageSize = min_size; + + throw new ServiceException("分页大小不能超过 " + MAX_PAGE_SIZE); + // 可以记录日志或抛出异常 + // log.warn("分页大小超过限制,已自动调整为最大值: {}", MAX_PAGE_SIZE); + } + + Page page = new Page<>(pageNum, pageSize); + List orderItems = buildOrderItem(); + if (CollUtil.isNotEmpty(orderItems)) { + page.addOrder(orderItems); + } + return page; + } + /** + * 构建排序 + * + * 支持的用法如下: + * {isAsc:"asc",orderByColumn:"id"} order by id asc + * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc + * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc + * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc + */ + private List buildOrderItem() { + if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) { + return null; + } + String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); + orderBy = StringUtils.toUnderScoreCase(orderBy); + + // 兼容前端排序类型 + isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"}); + + String[] orderByArr = orderBy.split(StringUtils.SEPARATOR); + String[] isAscArr = isAsc.split(StringUtils.SEPARATOR); + if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) { + throw new ServiceException("排序参数有误"); + } + + List list = new ArrayList<>(); + // 每个字段各自排序 + for (int i = 0; i < orderByArr.length; i++) { + String orderByStr = orderByArr[i]; + String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i]; + if ("asc".equals(isAscStr)) { + list.add(OrderItem.asc(orderByStr)); + } else if ("desc".equals(isAscStr)) { + list.add(OrderItem.desc(orderByStr)); + } else { + throw new ServiceException("排序参数有误"); + } + } + return list; + } + + @JsonIgnore + public Integer getFirstNum() { + return (pageNum - 1) * pageSize; + } + + public PageQuery(Integer pageSize, Integer pageNum) { + this.pageSize = pageSize; + this.pageNum = pageNum; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java new file mode 100644 index 0000000..02a5f48 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java @@ -0,0 +1,87 @@ +package org.dromara.common.mybatis.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.helper.DataPermissionHelper; + +/** + * 数据权限类型枚举 + *

+ * 支持使用 SpEL 模板表达式定义 SQL 查询条件 + * 内置数据: + * - {@code user}: 当前登录用户信息,参考 {@link LoginUser} + * 内置服务: + * - {@code sdss}: 系统数据权限服务,参考 ISysDataScopeService + * 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作 + * 如需扩展服务,可以通过 ISysDataScopeService 自行编写 + *

+ * + * @author Lion Li + * @version 3.5.0 + */ +@Getter +@AllArgsConstructor +public enum DataScopeType { + + /** + * 全部数据权限 + */ + ALL("1", "", ""), + + /** + * 自定数据权限 + */ + CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "), + + /** + * 部门数据权限 + */ + DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "), + + /** + * 部门及以下数据权限 + */ + DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "), + + /** + * 仅本人数据权限 + */ + SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "), + + /** + * 部门及以下或本人数据权限 + */ + DEPT_AND_CHILD_OR_SELF("6", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} ) OR #{#userName} = #{#user.userId} ", " 1 = 0 "); + + private final String code; + + /** + * SpEL 模板表达式,用于构建 SQL 查询条件 + */ + private final String sqlTemplate; + + /** + * 如果不满足 {@code sqlTemplate} 的条件,则使用此默认 SQL 表达式 + */ + private final String elseSql; + + /** + * 根据枚举代码查找对应的枚举值 + * + * @param code 枚举代码 + * @return 对应的枚举值,如果未找到则返回 null + */ + public static DataScopeType findCode(String code) { + if (StringUtils.isBlank(code)) { + return null; + } + for (DataScopeType type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml new file mode 100644 index 0000000..14662e1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml @@ -0,0 +1,33 @@ +# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖 +# MyBatisPlus配置 +# https://baomidou.com/config/ +mybatis-plus: + # 启动时是否检查 MyBatis XML 文件的存在,默认不检查 + checkConfigLocation: false + configuration: + # 自动驼峰命名规则(camel case)映射 + mapUnderscoreToCamelCase: true + # MyBatis 自动映射策略 + # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射 + autoMappingBehavior: FULL + # MyBatis 自动映射时未知列或未知属性处理策 + # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息 + autoMappingUnknownColumnBehavior: NONE + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl + logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl + global-config: + # 是否打印 Logo banner + banner: true + dbConfig: + # 主键类型 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID + idType: ASSIGN_ID + # 逻辑已删除值(可按需求随意修改) + logicDeleteValue: 1 + # 逻辑未删除值 + logicNotDeleteValue: 0 + insertStrategy: NOT_NULL + updateStrategy: NOT_NULL + whereStrategy: NOT_NULL diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java new file mode 100644 index 0000000..9d8db93 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java @@ -0,0 +1,40 @@ +package org.dromara.common.oss.constant; + +import org.dromara.common.core.constant.GlobalConstants; + +import java.util.Arrays; +import java.util.List; + +/** + * 对象存储常量 + * + * @author Lion Li + */ +public interface OssConstant { + + /** + * 默认配置KEY + */ + String DEFAULT_CONFIG_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "sys_oss:default_config"; + + /** + * 预览列表资源开关Key + */ + String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource"; + + /** + * 系统数据ids + */ + List SYSTEM_DATA_IDS = Arrays.asList(1L, 2L, 3L, 4L); + + /** + * 云服务商 + */ + String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu", "obs"}; + + /** + * https 状态 + */ + String IS_HTTPS = "Y"; + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java new file mode 100644 index 0000000..81a18e6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java @@ -0,0 +1,30 @@ +package org.dromara.common.oss.entity; + +import lombok.Builder; +import lombok.Data; + +/** + * 上传返回体 + * + * @author Lion Li + */ +@Data +@Builder +public class UploadResult { + + /** + * 文件路径 + */ + private String url; + + /** + * 文件名 + */ + private String filename; + + /** + * 已上传对象的实体标记(用来校验文件) + */ + private String eTag; + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java new file mode 100644 index 0000000..a257bba --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enumd/AccessPolicyType.java @@ -0,0 +1,56 @@ +package org.dromara.common.oss.enumd; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import software.amazon.awssdk.services.s3.model.BucketCannedACL; +import software.amazon.awssdk.services.s3.model.ObjectCannedACL; + +/** + * 桶访问策略配置 + * + * @author 陈賝 + */ +@Getter +@AllArgsConstructor +public enum AccessPolicyType { + + /** + * private + */ + PRIVATE("0", BucketCannedACL.PRIVATE, ObjectCannedACL.PRIVATE), + + /** + * public + */ + PUBLIC("1", BucketCannedACL.PUBLIC_READ_WRITE, ObjectCannedACL.PUBLIC_READ_WRITE), + + /** + * custom + */ + CUSTOM("2", BucketCannedACL.PUBLIC_READ, ObjectCannedACL.PUBLIC_READ); + + /** + * 桶 权限类型(数据库值) + */ + private final String type; + + /** + * 桶 权限类型 + */ + private final BucketCannedACL bucketCannedACL; + + /** + * 文件对象 权限类型 + */ + private final ObjectCannedACL objectCannedACL; + + public static AccessPolicyType getByType(String type) { + for (AccessPolicyType value : values()) { + if (value.getType().equals(type)) { + return value; + } + } + throw new RuntimeException("'type' not found By " + type); + } + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java new file mode 100644 index 0000000..cb37206 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java @@ -0,0 +1,63 @@ +package org.dromara.common.oss.properties; + +import lombok.Data; + +/** + * OSS对象存储 配置属性 + * + * @author Lion Li + */ +@Data +public class OssProperties { + + /** + * 租户id + */ + private String tenantId; + + /** + * 访问站点 + */ + private String endpoint; + + /** + * 自定义域名 + */ + private String domain; + + /** + * 前缀 + */ + private String prefix; + + /** + * ACCESS_KEY + */ + private String accessKey; + + /** + * SECRET_KEY + */ + private String secretKey; + + /** + * 存储空间名 + */ + private String bucketName; + + /** + * 存储区域 + */ + private String region; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; + +} diff --git a/ruoyi-common/ruoyi-common-ratelimiter/pom.xml b/ruoyi-common/ruoyi-common-ratelimiter/pom.xml new file mode 100644 index 0000000..bbde940 --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/pom.xml @@ -0,0 +1,30 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-ratelimiter + + + ruoyi-common-ratelimiter 限流功能 + + + + + org.dromara + ruoyi-common-core + + + + org.dromara + ruoyi-common-redis + + + + diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java new file mode 100644 index 0000000..2d6d82e --- /dev/null +++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java @@ -0,0 +1,112 @@ +package org.dromara.common.ratelimiter.aspectj; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.reflect.MethodSignature; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.ratelimiter.annotation.RateLimiter; +import org.dromara.common.ratelimiter.enums.LimitType; +import org.dromara.common.redis.utils.RedisUtils; +import org.redisson.api.RateType; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.context.expression.MethodBasedEvaluationContext; +import org.springframework.core.DefaultParameterNameDiscoverer; +import org.springframework.core.ParameterNameDiscoverer; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.ParserContext; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; + +import java.lang.reflect.Method; + +/** + * 限流处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +public class RateLimiterAspect { + + /** + * 定义spel表达式解析器 + */ + private final ExpressionParser parser = new SpelExpressionParser(); + /** + * 定义spel解析模版 + */ + private final ParserContext parserContext = new TemplateParserContext(); + /** + * 方法参数解析器 + */ + private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer(); + + + @Before("@annotation(rateLimiter)") + public void doBefore(JoinPoint point, RateLimiter rateLimiter) { + int time = rateLimiter.time(); + int count = rateLimiter.count(); + int timeout = rateLimiter.timeout(); + try { + String combineKey = getCombineKey(rateLimiter, point); + RateType rateType = RateType.OVERALL; + if (rateLimiter.limitType() == LimitType.CLUSTER) { + rateType = RateType.PER_CLIENT; + } + long number = RedisUtils.rateLimiter(combineKey, rateType, count, time, timeout); + if (number == -1) { + String message = rateLimiter.message(); + if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { + message = MessageUtils.message(StringUtils.substring(message, 1, message.length() - 1)); + } + throw new ServiceException(message); + } + log.info("限制令牌 => {}, 剩余令牌 => {}, 缓存key => '{}'", count, number, combineKey); + } catch (Exception e) { + if (e instanceof ServiceException) { + throw e; + } else { + throw new RuntimeException("服务器限流异常,请稍候再试", e); + } + } + } + + private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) { + String key = rateLimiter.key(); + // 判断 key 不为空 和 不是表达式 + if (StringUtils.isNotBlank(key) && StringUtils.containsAny(key, "#")) { + MethodSignature signature = (MethodSignature) point.getSignature(); + Method targetMethod = signature.getMethod(); + Object[] args = point.getArgs(); + MethodBasedEvaluationContext context = + new MethodBasedEvaluationContext(null, targetMethod, args, pnd); + context.setBeanResolver(new BeanFactoryResolver(SpringUtils.getBeanFactory())); + Expression expression; + if (StringUtils.startsWith(key, parserContext.getExpressionPrefix()) + && StringUtils.endsWith(key, parserContext.getExpressionSuffix())) { + expression = parser.parseExpression(key, parserContext); + } else { + expression = parser.parseExpression(key); + } + key = expression.getValue(context, String.class); + } + StringBuilder stringBuffer = new StringBuilder(GlobalConstants.RATE_LIMIT_KEY); + stringBuffer.append(ServletUtils.getRequest().getRequestURI()).append(":"); + if (rateLimiter.limitType() == LimitType.IP) { + // 获取请求ip + stringBuffer.append(ServletUtils.getClientIP()).append(":"); + } else if (rateLimiter.limitType() == LimitType.CLUSTER) { + // 获取客户端实例id + stringBuffer.append(RedisUtils.getClient().getId()).append(":"); + } + return stringBuffer.append(key).toString(); + } +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java new file mode 100644 index 0000000..7ba9475 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java @@ -0,0 +1,159 @@ +package org.dromara.common.redis.config; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.redis.config.properties.RedissonProperties; +import org.dromara.common.redis.handler.KeyPrefixHandler; +import org.dromara.common.redis.handler.RedisExceptionHandler; +import org.redisson.client.codec.StringCodec; +import org.redisson.codec.CompositeCodec; +import org.redisson.codec.TypedJsonJacksonCodec; +import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.core.task.VirtualThreadTaskExecutor; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.TimeZone; + +/** + * redis配置 + * + * @author Lion Li + */ +@Slf4j +@AutoConfiguration +@EnableConfigurationProperties(RedissonProperties.class) +public class RedisConfig { + + @Autowired + private RedissonProperties redissonProperties; + + @Bean + public RedissonAutoConfigurationCustomizer redissonCustomizer() { + return config -> { + JavaTimeModule javaTimeModule = new JavaTimeModule(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(formatter)); + javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(formatter)); + ObjectMapper om = new ObjectMapper(); + om.registerModule(javaTimeModule); + om.setTimeZone(TimeZone.getDefault()); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + // 指定序列化输入的类型,类必须是非final修饰的。序列化时将对象全类名一起保存下来 + om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL); +// LoggerFactory.useSlf4jLogging(true); +// FuryCodec furyCodec = new FuryCodec(); +// CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, furyCodec, furyCodec); + TypedJsonJacksonCodec jsonCodec = new TypedJsonJacksonCodec(Object.class, om); + // 组合序列化 key 使用 String 内容使用通用 json 格式 + CompositeCodec codec = new CompositeCodec(StringCodec.INSTANCE, jsonCodec, jsonCodec); + config.setThreads(redissonProperties.getThreads()) + .setNettyThreads(redissonProperties.getNettyThreads()) + // 缓存 Lua 脚本 减少网络传输(redisson 大部分的功能都是基于 Lua 脚本实现) + .setUseScriptCache(true) + .setCodec(codec); + if (SpringUtils.isVirtual()) { + config.setNettyExecutor(new VirtualThreadTaskExecutor("redisson-")); + } + RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); + if (ObjectUtil.isNotNull(singleServerConfig)) { + // 使用单机模式 + config.useSingleServer() + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(singleServerConfig.getTimeout()) + .setClientName(singleServerConfig.getClientName()) + .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) + .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) + .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()); + } + // 集群配置方式 参考下方注释 + RedissonProperties.ClusterServersConfig clusterServersConfig = redissonProperties.getClusterServersConfig(); + if (ObjectUtil.isNotNull(clusterServersConfig)) { + config.useClusterServers() + //设置redis key前缀 + .setNameMapper(new KeyPrefixHandler(redissonProperties.getKeyPrefix())) + .setTimeout(clusterServersConfig.getTimeout()) + .setClientName(clusterServersConfig.getClientName()) + .setIdleConnectionTimeout(clusterServersConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionPoolSize(clusterServersConfig.getSubscriptionConnectionPoolSize()) + .setMasterConnectionMinimumIdleSize(clusterServersConfig.getMasterConnectionMinimumIdleSize()) + .setMasterConnectionPoolSize(clusterServersConfig.getMasterConnectionPoolSize()) + .setSlaveConnectionMinimumIdleSize(clusterServersConfig.getSlaveConnectionMinimumIdleSize()) + .setSlaveConnectionPoolSize(clusterServersConfig.getSlaveConnectionPoolSize()) + .setReadMode(clusterServersConfig.getReadMode()) + .setSubscriptionMode(clusterServersConfig.getSubscriptionMode()); + } + log.info("初始化 redis 配置"); + }; + } + + /** + * 异常处理器 + */ + @Bean + public RedisExceptionHandler redisExceptionHandler() { + return new RedisExceptionHandler(); + } + + /** + * redis集群配置 yml + * + * --- # redis 集群配置(单机与集群只能开启一个另一个需要注释掉) + * spring.data: + * redis: + * cluster: + * nodes: + * - 192.168.0.100:6379 + * - 192.168.0.101:6379 + * - 192.168.0.102:6379 + * # 密码 + * password: + * # 连接超时时间 + * timeout: 10s + * # 是否开启ssl + * ssl.enabled: false + * + * redisson: + * # 线程池数量 + * threads: 16 + * # Netty线程池数量 + * nettyThreads: 32 + * # 集群配置 + * clusterServersConfig: + * # 客户端名称 + * clientName: ${ruoyi.name} + * # master最小空闲连接数 + * masterConnectionMinimumIdleSize: 32 + * # master连接池大小 + * masterConnectionPoolSize: 64 + * # slave最小空闲连接数 + * slaveConnectionMinimumIdleSize: 32 + * # slave连接池大小 + * slaveConnectionPoolSize: 64 + * # 连接空闲超时,单位:毫秒 + * idleConnectionTimeout: 10000 + * # 命令等待超时,单位:毫秒 + * timeout: 3000 + * # 发布和订阅连接池大小 + * subscriptionConnectionPoolSize: 50 + * # 读取模式 + * readMode: "SLAVE" + * # 订阅模式 + * subscriptionMode: "MASTER" + */ + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java new file mode 100644 index 0000000..ebec786 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java @@ -0,0 +1,135 @@ +package org.dromara.common.redis.config.properties; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.redisson.config.ReadMode; +import org.redisson.config.SubscriptionMode; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Redisson 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "redisson") +public class RedissonProperties { + + /** + * redis缓存key前缀 + */ + private String keyPrefix; + + /** + * 线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int threads; + + /** + * Netty线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int nettyThreads; + + /** + * 单机服务配置 + */ + private SingleServerConfig singleServerConfig; + + /** + * 集群服务配置 + */ + private ClusterServersConfig clusterServersConfig; + + @Data + @NoArgsConstructor + public static class SingleServerConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * 最小空闲连接数 + */ + private int connectionMinimumIdleSize; + + /** + * 连接池大小 + */ + private int connectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + } + + @Data + @NoArgsConstructor + public static class ClusterServersConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * master最小空闲连接数 + */ + private int masterConnectionMinimumIdleSize; + + /** + * master连接池大小 + */ + private int masterConnectionPoolSize; + + /** + * slave最小空闲连接数 + */ + private int slaveConnectionMinimumIdleSize; + + /** + * slave连接池大小 + */ + private int slaveConnectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + /** + * 读取模式 + */ + private ReadMode readMode; + + /** + * 订阅模式 + */ + private SubscriptionMode subscriptionMode; + + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java new file mode 100644 index 0000000..3bf3e34 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java @@ -0,0 +1,50 @@ +package org.dromara.common.redis.handler; + +import org.dromara.common.core.utils.StringUtils; +import org.redisson.api.NameMapper; + +/** + * redis缓存key前缀处理 + * + * @author ye + * @date 2022/7/14 17:44 + * @since 4.3.0 + */ +public class KeyPrefixHandler implements NameMapper { + + private final String keyPrefix; + + public KeyPrefixHandler(String keyPrefix) { + //前缀为空 则返回空前缀 + this.keyPrefix = StringUtils.isBlank(keyPrefix) ? "" : keyPrefix + ":"; + } + + /** + * 增加前缀 + */ + @Override + public String map(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && !name.startsWith(keyPrefix)) { + return keyPrefix + name; + } + return name; + } + + /** + * 去除前缀 + */ + @Override + public String unmap(String name) { + if (StringUtils.isBlank(name)) { + return null; + } + if (StringUtils.isNotBlank(keyPrefix) && name.startsWith(keyPrefix)) { + return name.substring(keyPrefix.length()); + } + return name; + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java new file mode 100644 index 0000000..5e904f3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java @@ -0,0 +1,30 @@ +package org.dromara.common.redis.handler; + +import cn.hutool.http.HttpStatus; +import com.baomidou.lock.exception.LockFailureException; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * Redis异常处理器 + * + * @author AprilWind + */ +@Slf4j +@RestControllerAdvice +public class RedisExceptionHandler { + + /** + * 分布式锁Lock4j异常 + */ + @ExceptionHandler(LockFailureException.class) + public R handleLockFailureException(LockFailureException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("获取锁失败了'{}',发生Lock4j异常.", requestURI, e); + return R.fail(HttpStatus.HTTP_UNAVAILABLE, "业务处理中,请稍后再试..."); + } + +} diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java new file mode 100644 index 0000000..740e2a1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2013-2021 Nikita Koksharov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.dromara.common.redis.manager; + +import org.dromara.common.redis.utils.RedisUtils; +import org.redisson.api.RMap; +import org.redisson.api.RMapCache; +import org.redisson.spring.cache.CacheConfig; +import org.redisson.spring.cache.RedissonCache; +import org.springframework.boot.convert.DurationStyle; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.cache.transaction.TransactionAwareCacheDecorator; +import org.springframework.util.StringUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A {@link org.springframework.cache.CacheManager} implementation + * backed by Redisson instance. + *

+ * 修改 RedissonSpringCacheManager 源码 + * 重写 cacheName 处理方法 支持多参数 + * + * @author Nikita Koksharov + * + */ +@SuppressWarnings("unchecked") +public class PlusSpringCacheManager implements CacheManager { + + private boolean dynamic = true; + + private boolean allowNullValues = true; + + private boolean transactionAware = true; + + Map configMap = new ConcurrentHashMap<>(); + ConcurrentMap instanceMap = new ConcurrentHashMap<>(); + + /** + * Creates CacheManager supplied by Redisson instance + */ + public PlusSpringCacheManager() { + } + + + /** + * Defines possibility of storing {@code null} values. + *

+ * Default is true + * + * @param allowNullValues stores if true + */ + public void setAllowNullValues(boolean allowNullValues) { + this.allowNullValues = allowNullValues; + } + + /** + * Defines if cache aware of Spring-managed transactions. + * If {@code true} put/evict operations are executed only for successful transaction in after-commit phase. + *

+ * Default is false + * + * @param transactionAware cache is transaction aware if true + */ + public void setTransactionAware(boolean transactionAware) { + this.transactionAware = transactionAware; + } + + /** + * Defines 'fixed' cache names. + * A new cache instance will not be created in dynamic for non-defined names. + *

+ * `null` parameter setups dynamic mode + * + * @param names of caches + */ + public void setCacheNames(Collection names) { + if (names != null) { + for (String name : names) { + getCache(name); + } + dynamic = false; + } else { + dynamic = true; + } + } + + /** + * Set cache config mapped by cache name + * + * @param config object + */ + public void setConfig(Map config) { + this.configMap = (Map) config; + } + + protected CacheConfig createDefaultConfig() { + return new CacheConfig(); + } + + @Override + public Cache getCache(String name) { + // 重写 cacheName 支持多参数 + String[] array = StringUtils.delimitedListToStringArray(name, "#"); + name = array[0]; + + Cache cache = instanceMap.get(name); + if (cache != null) { + return cache; + } + if (!dynamic) { + return cache; + } + + CacheConfig config = configMap.get(name); + if (config == null) { + config = createDefaultConfig(); + configMap.put(name, config); + } + + if (array.length > 1) { + config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis()); + } + if (array.length > 2) { + config.setMaxIdleTime(DurationStyle.detectAndParse(array[2]).toMillis()); + } + if (array.length > 3) { + config.setMaxSize(Integer.parseInt(array[3])); + } + + if (config.getMaxIdleTime() == 0 && config.getTTL() == 0 && config.getMaxSize() == 0) { + return createMap(name, config); + } + + return createMapCache(name, config); + } + + private Cache createMap(String name, CacheConfig config) { + RMap map = RedisUtils.getClient().getMap(name); + + Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, allowNullValues)); + if (transactionAware) { + cache = new TransactionAwareCacheDecorator(cache); + } + Cache oldCache = instanceMap.putIfAbsent(name, cache); + if (oldCache != null) { + cache = oldCache; + } + return cache; + } + + private Cache createMapCache(String name, CacheConfig config) { + RMapCache map = RedisUtils.getClient().getMapCache(name); + + Cache cache = new CaffeineCacheDecorator(name, new RedissonCache(map, config, allowNullValues)); + if (transactionAware) { + cache = new TransactionAwareCacheDecorator(cache); + } + Cache oldCache = instanceMap.putIfAbsent(name, cache); + if (oldCache != null) { + cache = oldCache; + } else { + map.setMaxSize(config.getMaxSize()); + } + return cache; + } + + @Override + public Collection getCacheNames() { + return Collections.unmodifiableSet(configMap.keySet()); + } + + +} diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java new file mode 100644 index 0000000..61c6b9a --- /dev/null +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java @@ -0,0 +1,54 @@ +package org.dromara.common.satoken.config; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.dev33.satoken.jwt.StpLogicJwtForSimple; +import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.stp.StpLogic; +import org.dromara.common.core.factory.YmlPropertySourceFactory; +import org.dromara.common.satoken.core.dao.PlusSaTokenDao; +import org.dromara.common.satoken.core.service.SaPermissionImpl; +import org.dromara.common.satoken.handler.SaTokenExceptionHandler; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; + +/** + * sa-token 配置 + * + * @author Lion Li + */ +@AutoConfiguration +@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class) +public class SaTokenConfig { + + @Bean + public StpLogic getStpLogicJwt() { + // Sa-Token 整合 jwt (简单模式) + return new StpLogicJwtForSimple(); + } + + /** + * 权限接口实现(使用bean注入方便用户替换) + */ + @Bean + public StpInterface stpInterface() { + return new SaPermissionImpl(); + } + + /** + * 自定义dao层存储 + */ + @Bean + public SaTokenDao saTokenDao() { + return new PlusSaTokenDao(); + } + + /** + * 异常处理器 + */ + @Bean + public SaTokenExceptionHandler saTokenExceptionHandler() { + return new SaTokenExceptionHandler(); + } + +} diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java new file mode 100644 index 0000000..1cef9a7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java @@ -0,0 +1,47 @@ +package org.dromara.common.satoken.core.service; + +import cn.dev33.satoken.stp.StpInterface; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.enums.UserType; +import org.dromara.common.satoken.utils.LoginHelper; + +import java.util.ArrayList; +import java.util.List; + +/** + * sa-token 权限管理实现类 + * + * @author Lion Li + */ +public class SaPermissionImpl implements StpInterface { + + /** + * 获取菜单权限列表 + */ + @Override + public List getPermissionList(Object loginId, String loginType) { + LoginUser loginUser = LoginHelper.getLoginUser(); + UserType userType = UserType.getUserType(loginUser.getUserType()); + if (userType == UserType.SYS_USER) { + return new ArrayList<>(loginUser.getMenuPermission()); + } else if (userType == UserType.APP_USER) { + // 其他端 自行根据业务编写 + } + return new ArrayList<>(); + } + + /** + * 获取角色权限列表 + */ + @Override + public List getRoleList(Object loginId, String loginType) { + LoginUser loginUser = LoginHelper.getLoginUser(); + UserType userType = UserType.getUserType(loginUser.getUserType()); + if (userType == UserType.SYS_USER) { + return new ArrayList<>(loginUser.getRolePermission()); + } else if (userType == UserType.APP_USER) { + // 其他端 自行根据业务编写 + } + return new ArrayList<>(); + } +} diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java new file mode 100644 index 0000000..5a10ef0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java @@ -0,0 +1,53 @@ +package org.dromara.common.satoken.handler; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.exception.NotPermissionException; +import cn.dev33.satoken.exception.NotRoleException; +import cn.hutool.http.HttpStatus; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * SaToken异常处理器 + * + * @author Lion Li + */ +@Slf4j +@RestControllerAdvice +public class SaTokenExceptionHandler { + + /** + * 权限码异常 + */ + @ExceptionHandler(NotPermissionException.class) + public R handleNotPermissionException(NotPermissionException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权"); + } + + /** + * 角色权限异常 + */ + @ExceptionHandler(NotRoleException.class) + public R handleNotRoleException(NotRoleException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',角色权限校验失败'{}'", requestURI, e.getMessage()); + return R.fail(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权"); + } + + /** + * 认证失败 + */ + @ExceptionHandler(NotLoginException.class) + public R handleNotLoginException(NotLoginException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage()); +// System.out.println("认证失败"); + return R.fail(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源"); + } + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java new file mode 100644 index 0000000..a4e921f --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java @@ -0,0 +1,105 @@ +package org.dromara.common.security.config; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.filter.SaServletFilter; +import cn.dev33.satoken.httpauth.basic.SaHttpBasicUtil; +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.util.SaResult; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.HttpStatus; +import org.dromara.common.core.exception.SseException; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.security.config.properties.SecurityProperties; +import org.dromara.common.security.handler.AllUrlHandler; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 权限安全配置 + * + * @author Lion Li + */ + +@Slf4j +@AutoConfiguration +@EnableConfigurationProperties(SecurityProperties.class) +@RequiredArgsConstructor +public class SecurityConfig implements WebMvcConfigurer { + + private final SecurityProperties securityProperties; + + /** + * 注册sa-token的拦截器 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册路由拦截器,自定义验证规则 + registry.addInterceptor(new SaInterceptor(handler -> { + AllUrlHandler allUrlHandler = SpringUtils.getBean(AllUrlHandler.class); + // 登录验证 -- 排除多个路径 + SaRouter + // 获取所有的 + .match(allUrlHandler.getUrls()) + // 对未排除的路径进行检查 + .check(() -> { + HttpServletRequest request = ServletUtils.getRequest(); + // 检查是否登录 是否有token + try { + StpUtil.checkLogin(); + } catch (NotLoginException e) { + if (request.getRequestURI().contains("sse")) { + throw new SseException(e.getMessage(), e.getCode()); + } else { + throw e; + } + } + + // 检查 header 与 param 里的 clientid 与 token 里的是否一致 + String headerCid = request.getHeader(LoginHelper.CLIENT_KEY); + String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY); + String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString(); + if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) { + // token 无效 + throw NotLoginException.newInstance(StpUtil.getLoginType(), + "-100", "客户端ID与Token不匹配", + StpUtil.getTokenValue()); + } + + // 有效率影响 用于临时测试 + // if (log.isDebugEnabled()) { + // log.info("剩余有效时间: {}", StpUtil.getTokenTimeout()); + // log.info("临时有效时间: {}", StpUtil.getTokenActivityTimeout()); + // } + + }); + })).addPathPatterns("/**") + // 排除不需要拦截的路径 + .excludePathPatterns(securityProperties.getExcludes()); + } + + /** + * 对 actuator 健康检查接口 做账号密码鉴权 + */ + @Bean + public SaServletFilter getSaServletFilter() { + String username = SpringUtils.getProperty("spring.boot.admin.client.username"); + String password = SpringUtils.getProperty("spring.boot.admin.client.password"); + return new SaServletFilter() + .addInclude("/actuator", "/actuator/**") + .setAuth(obj -> { + SaHttpBasicUtil.check(username + ":" + password); + }) + .setError(e -> SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED)); + } + +} diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java new file mode 100644 index 0000000..be1cc6e --- /dev/null +++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java @@ -0,0 +1,21 @@ +package org.dromara.common.security.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Security 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "security") +public class SecurityProperties { + + /** + * 排除路径 + */ + private String[] excludes; + + +} diff --git a/ruoyi-common/ruoyi-common-sms/pom.xml b/ruoyi-common/ruoyi-common-sms/pom.xml new file mode 100644 index 0000000..932cb9d --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/pom.xml @@ -0,0 +1,33 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-sms + + + ruoyi-common-sms 短信模块 + + + + + + org.dromara.sms4j + sms4j-spring-boot-starter + + + + + org.dromara + ruoyi-common-redis + + + + + diff --git a/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..5919ce3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.sms.config.SmsAutoConfiguration diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java new file mode 100644 index 0000000..19b39d8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java @@ -0,0 +1,23 @@ +package org.dromara.common.social.config; + +import me.zhyd.oauth.cache.AuthStateCache; +import org.dromara.common.social.config.properties.SocialProperties; +import org.dromara.common.social.utils.AuthRedisStateCache; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * Social 配置属性 + * @author thiszhc + */ +@AutoConfiguration +@EnableConfigurationProperties(SocialProperties.class) +public class SocialAutoConfiguration { + + @Bean + public AuthStateCache authStateCache() { + return new AuthRedisStateCache(); + } + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java new file mode 100644 index 0000000..5f49d9c --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java @@ -0,0 +1,75 @@ +package org.dromara.common.social.config.properties; + +import lombok.Data; + +import java.util.List; + +/** + * 社交登录配置 + * + * @author thiszhc + */ +@Data +public class SocialLoginConfigProperties { + + /** + * 应用 ID + */ + private String clientId; + + /** + * 应用密钥 + */ + private String clientSecret; + + /** + * 回调地址 + */ + private String redirectUri; + + /** + * 是否获取unionId + */ + private boolean unionId; + + /** + * Coding 企业名称 + */ + private String codingGroupName; + + /** + * 支付宝公钥 + */ + private String alipayPublicKey; + + /** + * 企业微信应用ID + */ + private String agentId; + + /** + * stackoverflow api key + */ + private String stackOverflowKey; + + /** + * 设备ID + */ + private String deviceId; + + /** + * 客户端系统类型 + */ + private String clientOsType; + + /** + * maxkey 服务器地址 + */ + private String serverUrl; + + /** + * 请求范围 + */ + private List scopes; + +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..fc544a0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.social.config.SocialAutoConfiguration diff --git a/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java new file mode 100644 index 0000000..7a4dff1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java @@ -0,0 +1,48 @@ +package org.dromara.common.sse.listener; + +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.sse.core.SseEmitterManager; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.Ordered; + +/** + * SSE 主题订阅监听器 + * + * @author Lion Li + */ +@Slf4j +public class SseTopicListener implements ApplicationRunner, Ordered { + + @Autowired + private SseEmitterManager sseEmitterManager; + + /** + * 在Spring Boot应用程序启动时初始化SSE主题订阅监听器 + * + * @param args 应用程序参数 + * @throws Exception 初始化过程中可能抛出的异常 + */ + @Override + public void run(ApplicationArguments args) throws Exception { + sseEmitterManager.subscribeMessage((message) -> { + log.info("SSE主题订阅收到消息session keys={} message={}", message.getUserIds(), message.getMessage()); + // 如果key不为空就按照key发消息 如果为空就群发 + if (CollUtil.isNotEmpty(message.getUserIds())) { + message.getUserIds().forEach(key -> { + sseEmitterManager.sendMessage(key, message.getMessage()); + }); + } else { + sseEmitterManager.sendMessage(message.getMessage()); + } + }); + log.info("初始化SSE主题订阅监听器成功"); + } + + @Override + public int getOrder() { + return -1; + } +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java new file mode 100644 index 0000000..cede235 --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java @@ -0,0 +1,86 @@ +package org.dromara.common.tenant.config; + +import cn.dev33.satoken.dao.SaTokenDao; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.redis.config.RedisConfig; +import org.dromara.common.redis.config.properties.RedissonProperties; +import org.dromara.common.tenant.core.TenantSaTokenDao; +import org.dromara.common.tenant.handle.PlusTenantLineHandler; +import org.dromara.common.tenant.handle.TenantKeyPrefixHandler; +import org.dromara.common.tenant.manager.TenantSpringCacheManager; +import org.dromara.common.tenant.properties.TenantProperties; +import org.redisson.config.ClusterServersConfig; +import org.redisson.config.SingleServerConfig; +import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; + +/** + * 租户配置类 + * + * @author Lion Li + */ +@EnableConfigurationProperties(TenantProperties.class) +@AutoConfiguration(after = {RedisConfig.class}) +@ConditionalOnProperty(value = "tenant.enable", havingValue = "true") +public class TenantConfig { + + @ConditionalOnClass(TenantLineInnerInterceptor.class) + @AutoConfiguration + static class MybatisPlusConfiguration { + + /** + * 多租户插件 + */ + @Bean + public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties tenantProperties) { + return new TenantLineInnerInterceptor(new PlusTenantLineHandler(tenantProperties)); + } + + } + + @Bean + public RedissonAutoConfigurationCustomizer tenantRedissonCustomizer(RedissonProperties redissonProperties) { + return config -> { + TenantKeyPrefixHandler nameMapper = new TenantKeyPrefixHandler(redissonProperties.getKeyPrefix()); + SingleServerConfig singleServerConfig = ReflectUtils.invokeGetter(config, "singleServerConfig"); + if (ObjectUtil.isNotNull(singleServerConfig)) { + // 使用单机模式 + // 设置多租户 redis key前缀 + //singleServerConfig.setNameMapper(nameMapper); + } + ClusterServersConfig clusterServersConfig = ReflectUtils.invokeGetter(config, "clusterServersConfig"); + // 集群配置方式 参考下方注释 + if (ObjectUtil.isNotNull(clusterServersConfig)) { + // 设置多租户 redis key前缀 + //clusterServersConfig.setNameMapper(nameMapper); + } + }; + } + + /** + * 多租户缓存管理器 + */ + @Primary + @Bean + public CacheManager tenantCacheManager() { + return new TenantSpringCacheManager(); + } + + /** + * 多租户鉴权dao实现 + */ + @Primary + @Bean + public SaTokenDao tenantSaTokenDao() { + return new TenantSaTokenDao(); + } + +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java new file mode 100644 index 0000000..8ad0d2c --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java @@ -0,0 +1,21 @@ +package org.dromara.common.tenant.core; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 租户基类 + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class TenantEntity extends BaseEntity { + + /** + * 租户编号 + */ + private String tenantId; + +} diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..f837191 --- /dev/null +++ b/ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.tenant.config.TenantConfig diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java new file mode 100644 index 0000000..c24aa6f --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java @@ -0,0 +1,39 @@ +package org.dromara.common.translation.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.dromara.common.translation.core.handler.TranslationHandler; + +import java.lang.annotation.*; + +/** + * 通用翻译注解 + * + * @author Lion Li + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +@Documented +@JacksonAnnotationsInside +@JsonSerialize(using = TranslationHandler.class) +public @interface Translation { + + /** + * 类型 (需与实现类上的 {@link TranslationType} 注解type对应) + *

+ * 默认取当前字段的值 如果设置了 @{@link Translation#mapper()} 则取映射字段的值 + */ + String type(); + + /** + * 映射字段 (如果不为空则取此字段的值) + */ + String mapper() default ""; + + /** + * 其他条件 例如: 字典type(sys_user_sex) + */ + String other() default ""; + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java new file mode 100644 index 0000000..5dcd0c1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java @@ -0,0 +1,50 @@ +package org.dromara.common.translation.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.dromara.common.translation.annotation.TranslationType; +import org.dromara.common.translation.core.TranslationInterface; +import org.dromara.common.translation.core.handler.TranslationBeanSerializerModifier; +import org.dromara.common.translation.core.handler.TranslationHandler; +import jakarta.annotation.PostConstruct; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 翻译模块配置类 + * + * @author Lion Li + */ +@Slf4j +@AutoConfiguration +public class TranslationConfig { + + @Autowired + private List> list; + + @Autowired + private ObjectMapper objectMapper; + + @PostConstruct + public void init() { + Map> map = new HashMap<>(list.size()); + for (TranslationInterface trans : list) { + if (trans.getClass().isAnnotationPresent(TranslationType.class)) { + TranslationType annotation = trans.getClass().getAnnotation(TranslationType.class); + map.put(annotation.type(), trans); + } else { + log.warn(trans.getClass().getName() + " 翻译实现类未标注 TranslationType 注解!"); + } + } + TranslationHandler.TRANSLATION_MAPPER.putAll(map); + // 设置 Bean 序列化修改器 + objectMapper.setSerializerFactory( + objectMapper.getSerializerFactory() + .withSerializerModifier(new TranslationBeanSerializerModifier())); + } + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java new file mode 100644 index 0000000..c084ea1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java @@ -0,0 +1,35 @@ +package org.dromara.common.translation.constant; + +/** + * 翻译常量 + * + * @author Lion Li + */ +public interface TransConstant { + + /** + * 用户id转账号 + */ + String USER_ID_TO_NAME = "user_id_to_name"; + + /** + * 用户id转用户名称 + */ + String USER_ID_TO_NICKNAME = "user_id_to_nickname"; + + /** + * 部门id转名称 + */ + String DEPT_ID_TO_NAME = "dept_id_to_name"; + + /** + * 字典type转label + */ + String DICT_TYPE_TO_LABEL = "dict_type_to_label"; + + /** + * ossId转url + */ + String OSS_ID_TO_URL = "oss_id_to_url"; + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java new file mode 100644 index 0000000..727672f --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java @@ -0,0 +1,29 @@ +package org.dromara.common.translation.core.handler; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; +import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; + +import java.util.List; + +/** + * Bean 序列化修改器 解决 Null 被单独处理问题 + * + * @author Lion Li + */ +public class TranslationBeanSerializerModifier extends BeanSerializerModifier { + + @Override + public List changeProperties(SerializationConfig config, BeanDescription beanDesc, + List beanProperties) { + for (BeanPropertyWriter writer : beanProperties) { + // 如果序列化器为 TranslationHandler 的话 将 Null 值也交给他处理 + if (writer.getSerializer() instanceof TranslationHandler serializer) { + writer.assignNullSerializer(serializer); + } + } + return beanProperties; + } + +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java new file mode 100644 index 0000000..c391437 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java @@ -0,0 +1,29 @@ +package org.dromara.common.translation.core.impl; + +import org.dromara.common.core.service.DeptService; +import org.dromara.common.translation.annotation.TranslationType; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.common.translation.core.TranslationInterface; +import lombok.AllArgsConstructor; + +/** + * 部门翻译实现 + * + * @author Lion Li + */ +@AllArgsConstructor +@TranslationType(type = TransConstant.DEPT_ID_TO_NAME) +public class DeptNameTranslationImpl implements TranslationInterface { + + private final DeptService deptService; + + @Override + public String translation(Object key, String other) { + if (key instanceof String ids) { + return deptService.selectDeptNameByIds(ids); + } else if (key instanceof Long id) { + return deptService.selectDeptNameByIds(id.toString()); + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..ad40205 --- /dev/null +++ b/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,6 @@ +org.dromara.common.translation.config.TranslationConfig +org.dromara.common.translation.core.impl.DeptNameTranslationImpl +org.dromara.common.translation.core.impl.DictTypeTranslationImpl +org.dromara.common.translation.core.impl.OssUrlTranslationImpl +org.dromara.common.translation.core.impl.UserNameTranslationImpl +org.dromara.common.translation.core.impl.NicknameTranslationImpl diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java new file mode 100644 index 0000000..650517e --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java @@ -0,0 +1,65 @@ +package org.dromara.common.web.config; + +import cn.hutool.captcha.CaptchaUtil; +import cn.hutool.captcha.CircleCaptcha; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.captcha.ShearCaptcha; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; + +import java.awt.*; + +/** + * 验证码配置 + * + * @author Lion Li + */ +@AutoConfiguration +@EnableConfigurationProperties(CaptchaProperties.class) +public class CaptchaConfig { + + private static final int WIDTH = 160; + private static final int HEIGHT = 60; + private static final Color BACKGROUND = Color.LIGHT_GRAY; + private static final Font FONT = new Font("Arial", Font.BOLD, 48); + + /** + * 圆圈干扰验证码 + */ + @Lazy + @Bean + public CircleCaptcha circleCaptcha() { + CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + + /** + * 线段干扰的验证码 + */ + @Lazy + @Bean + public LineCaptcha lineCaptcha() { + LineCaptcha captcha = CaptchaUtil.createLineCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + + /** + * 扭曲干扰验证码 + */ + @Lazy + @Bean + public ShearCaptcha shearCaptcha() { + ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(WIDTH, HEIGHT); + captcha.setBackground(BACKGROUND); + captcha.setFont(FONT); + return captcha; + } + +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java new file mode 100644 index 0000000..1371913 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java @@ -0,0 +1,61 @@ +package org.dromara.common.web.config; + +import org.dromara.common.web.handler.GlobalExceptionHandler; +import org.dromara.common.web.interceptor.PlusWebInvokeTimeInterceptor; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 通用配置 + * + * @author Lion Li + */ +@AutoConfiguration +public class ResourcesConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 全局访问性能拦截 + registry.addInterceptor(new PlusWebInvokeTimeInterceptor()); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + } + + /** + * 跨域配置 + */ + @Bean + public CorsFilter corsFilter() { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + // 设置访问源地址 + config.addAllowedOriginPattern("*"); + // 设置访问源请求头 + config.addAllowedHeader("*"); + // 设置访问源请求方法 + config.addAllowedMethod("*"); + // 有效期 1800秒 + config.setMaxAge(1800L); + // 添加映射路径,拦截一切请求 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + // 返回新的CorsFilter + return new CorsFilter(source); + } + + /** + * 全局异常处理器 + */ + @Bean + public GlobalExceptionHandler globalExceptionHandler() { + return new GlobalExceptionHandler(); + } +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java new file mode 100644 index 0000000..bfc52f4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java @@ -0,0 +1,38 @@ +package org.dromara.common.web.config.properties; + +import org.dromara.common.web.enums.CaptchaCategory; +import org.dromara.common.web.enums.CaptchaType; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 验证码 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "captcha") +public class CaptchaProperties { + + private Boolean enable; + + /** + * 验证码类型 + */ + private CaptchaType type; + + /** + * 验证码类别 + */ + private CaptchaCategory category; + + /** + * 数字验证码位数 + */ + private Integer numberLength; + + /** + * 字符验证码长度 + */ + private Integer charLength; +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaCategory.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaCategory.java new file mode 100644 index 0000000..ecf2658 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/enums/CaptchaCategory.java @@ -0,0 +1,35 @@ +package org.dromara.common.web.enums; + +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.CircleCaptcha; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.captcha.ShearCaptcha; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 验证码类别 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum CaptchaCategory { + + /** + * 线段干扰 + */ + LINE(LineCaptcha.class), + + /** + * 圆圈干扰 + */ + CIRCLE(CircleCaptcha.class), + + /** + * 扭曲干扰 + */ + SHEAR(ShearCaptcha.class); + + private final Class clazz; +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java new file mode 100644 index 0000000..95bcdd9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java @@ -0,0 +1,59 @@ +package org.dromara.common.web.filter; + +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.web.config.properties.XssProperties; +import org.springframework.http.HttpMethod; + +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * 防止XSS攻击的过滤器 + * + * @author ruoyi + */ +public class XssFilter implements Filter { + /** + * 排除链接 + */ + public List excludes = new ArrayList<>(); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + XssProperties properties = SpringUtils.getBean(XssProperties.class); + excludes.addAll(properties.getExcludeUrls()); + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + if (handleExcludeURL(req, resp)) { + chain.doFilter(request, response); + return; + } + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); + chain.doFilter(xssRequest, response); + } + + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { + String url = request.getServletPath(); + String method = request.getMethod(); + // GET DELETE 不过滤 + if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) { + return true; + } + return StringUtils.matches(url, excludes); + } + + @Override + public void destroy() { + + } +} diff --git a/ruoyi-common/ruoyi-common-websocket/pom.xml b/ruoyi-common/ruoyi-common-websocket/pom.xml new file mode 100644 index 0000000..0587cd7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-websocket/pom.xml @@ -0,0 +1,46 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-websocket + + + ruoyi-common-websocket 模块 + + + + + org.dromara + ruoyi-common-core + + + org.dromara + ruoyi-common-redis + + + org.dromara + ruoyi-common-satoken + + + org.dromara + ruoyi-common-json + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + diff --git a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java new file mode 100644 index 0000000..8b1cc5d --- /dev/null +++ b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java @@ -0,0 +1,122 @@ +package org.dromara.common.websocket.handler; + +import cn.hutool.core.util.ObjectUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.websocket.dto.WebSocketMessageDto; +import org.dromara.common.websocket.holder.WebSocketSessionHolder; +import org.dromara.common.websocket.utils.WebSocketUtils; +import org.springframework.web.socket.*; +import org.springframework.web.socket.handler.AbstractWebSocketHandler; + +import java.io.IOException; +import java.util.List; + +import static org.dromara.common.websocket.constant.WebSocketConstants.LOGIN_USER_KEY; + +/** + * WebSocketHandler 实现类 + * + * @author zendwang + */ +@Slf4j +public class PlusWebSocketHandler extends AbstractWebSocketHandler { + + /** + * 连接成功后 + */ + @Override + public void afterConnectionEstablished(WebSocketSession session) throws IOException { + LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); + if (ObjectUtil.isNull(loginUser)) { + session.close(CloseStatus.BAD_DATA); + log.info("[connect] invalid token received. sessionId: {}", session.getId()); + return; + } + WebSocketSessionHolder.addSession(loginUser.getUserId(), session); + log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); + } + + /** + * 处理接收到的文本消息 + * + * @param session WebSocket会话 + * @param message 接收到的文本消息 + * @throws Exception 处理消息过程中可能抛出的异常 + */ + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + // 从WebSocket会话中获取登录用户信息 + LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); + + // 创建WebSocket消息DTO对象 + WebSocketMessageDto webSocketMessageDto = new WebSocketMessageDto(); + webSocketMessageDto.setSessionKeys(List.of(loginUser.getUserId())); + webSocketMessageDto.setMessage(message.getPayload()); + WebSocketUtils.publishMessage(webSocketMessageDto); + } + + /** + * 处理接收到的二进制消息 + * + * @param session WebSocket会话 + * @param message 接收到的二进制消息 + * @throws Exception 处理消息过程中可能抛出的异常 + */ + @Override + protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception { + super.handleBinaryMessage(session, message); + } + + /** + * 处理接收到的Pong消息(心跳监测) + * + * @param session WebSocket会话 + * @param message 接收到的Pong消息 + * @throws Exception 处理消息过程中可能抛出的异常 + */ + @Override + protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception { + WebSocketUtils.sendPongMessage(session); + } + + /** + * 处理WebSocket传输错误 + * + * @param session WebSocket会话 + * @param exception 发生的异常 + * @throws Exception 处理过程中可能抛出的异常 + */ + @Override + public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { + log.error("[transport error] sessionId: {} , exception:{}", session.getId(), exception.getMessage()); + } + + /** + * 在WebSocket连接关闭后执行清理操作 + * + * @param session WebSocket会话 + * @param status 关闭状态信息 + */ + @Override + public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { + LoginUser loginUser = (LoginUser) session.getAttributes().get(LOGIN_USER_KEY); + if (ObjectUtil.isNull(loginUser)) { + log.info("[disconnect] invalid token received. sessionId: {}", session.getId()); + return; + } + WebSocketSessionHolder.removeSession(loginUser.getUserId()); + log.info("[disconnect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType()); + } + + /** + * 指示处理程序是否支持接收部分消息 + * + * @return 如果支持接收部分消息,则返回true;否则返回false + */ + @Override + public boolean supportsPartialMessages() { + return false; + } + +} diff --git a/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java new file mode 100644 index 0000000..0ad39af --- /dev/null +++ b/ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java @@ -0,0 +1,50 @@ +package org.dromara.common.websocket.listener; + +import cn.hutool.core.collection.CollUtil; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.websocket.holder.WebSocketSessionHolder; +import org.dromara.common.websocket.utils.WebSocketUtils; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.core.Ordered; + +/** + * WebSocket 主题订阅监听器 + * + * @author zendwang + */ +@Slf4j +public class WebSocketTopicListener implements ApplicationRunner, Ordered { + + /** + * 在Spring Boot应用程序启动时初始化WebSocket主题订阅监听器 + * + * @param args 应用程序参数 + * @throws Exception 初始化过程中可能抛出的异常 + */ + @Override + public void run(ApplicationArguments args) throws Exception { + // 订阅WebSocket消息 + WebSocketUtils.subscribeMessage((message) -> { + log.info("WebSocket主题订阅收到消息session keys={} message={}", message.getSessionKeys(), message.getMessage()); + // 如果key不为空就按照key发消息 如果为空就群发 + if (CollUtil.isNotEmpty(message.getSessionKeys())) { + message.getSessionKeys().forEach(key -> { + if (WebSocketSessionHolder.existSession(key)) { + WebSocketUtils.sendMessage(key, message.getMessage()); + } + }); + } else { + WebSocketSessionHolder.getSessionsAll().forEach(key -> { + WebSocketUtils.sendMessage(key, message.getMessage()); + }); + } + }); + log.info("初始化WebSocket主题订阅监听器成功"); + } + + @Override + public int getOrder() { + return -1; + } +} diff --git a/ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..c3a7305 --- /dev/null +++ b/ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.websocket.config.WebSocketConfig diff --git a/ruoyi-extend/ruoyi-monitor-admin/Dockerfile b/ruoyi-extend/ruoyi-monitor-admin/Dockerfile new file mode 100644 index 0000000..d55b956 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/Dockerfile @@ -0,0 +1,22 @@ +# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ +FROM bellsoft/liberica-openjdk-debian:17.0.11-cds +#FROM bellsoft/liberica-openjdk-debian:21.0.5-cds +#FROM findepi/graalvm:java17-native + +LABEL maintainer="Lion Li" + +RUN mkdir -p /ruoyi/monitor/logs + +WORKDIR /ruoyi/monitor + +ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" + +EXPOSE 9090 + +ADD ./target/ruoyi-monitor-admin.jar ./app.jar + +SHELL ["/bin/bash", "-c"] + +ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom \ + -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ + -jar app.jar diff --git a/ruoyi-extend/ruoyi-monitor-admin/pom.xml b/ruoyi-extend/ruoyi-monitor-admin/pom.xml new file mode 100644 index 0000000..77c9eb7 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/pom.xml @@ -0,0 +1,76 @@ + + + + ruoyi-extend + org.dromara + ${revision} + + 4.0.0 + jar + ruoyi-monitor-admin + + + + + org.springframework.boot + spring-boot-starter-web + + + spring-boot-starter-tomcat + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-undertow + + + + + org.springframework.boot + spring-boot-starter-security + + + + de.codecentric + spring-boot-admin-starter-server + + + + de.codecentric + spring-boot-admin-starter-client + + + + org.projectlombok + lombok + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + + + + repackage + + + + + + + + diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java new file mode 100644 index 0000000..0339ebb --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java @@ -0,0 +1,19 @@ +package org.dromara.monitor.admin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Admin 监控启动程序 + * + * @author Lion Li + */ +@SpringBootApplication +public class MonitorAdminApplication { + + public static void main(String[] args) { + SpringApplication.run(MonitorAdminApplication.class, args); + System.out.println("Admin 监控启动成功"); + } + +} diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java new file mode 100644 index 0000000..3458cc9 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java @@ -0,0 +1,54 @@ +package org.dromara.monitor.admin.config; + +import de.codecentric.boot.admin.server.config.AdminServerProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; + +/** + * admin 监控 安全配置 + * + * @author Lion Li + */ +@EnableWebSecurity +@Configuration +public class SecurityConfig { + + private final String adminContextPath; + + public SecurityConfig(AdminServerProperties adminServerProperties) { + this.adminContextPath = adminServerProperties.getContextPath(); + } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); + successHandler.setTargetUrlParameter("redirectTo"); + successHandler.setDefaultTargetUrl(adminContextPath + "/"); + + return httpSecurity + .headers((header) -> + header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) + .authorizeHttpRequests((authorize) -> + authorize.requestMatchers( + new AntPathRequestMatcher(adminContextPath + "/assets/**"), + new AntPathRequestMatcher(adminContextPath + "/login") + ).permitAll() + .anyRequest().authenticated()) + .formLogin((formLogin) -> + formLogin.loginPage(adminContextPath + "/login").successHandler(successHandler)) + .logout((logout) -> + logout.logoutUrl(adminContextPath + "/logout")) + .httpBasic(Customizer.withDefaults()) + .csrf(AbstractHttpConfigurer::disable) + .build(); + } + +} diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java new file mode 100644 index 0000000..838eefc --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java @@ -0,0 +1,55 @@ +package org.dromara.monitor.admin.notifier; + +import de.codecentric.boot.admin.server.domain.entities.Instance; +import de.codecentric.boot.admin.server.domain.entities.InstanceRepository; +import de.codecentric.boot.admin.server.domain.events.InstanceEvent; +import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent; +import de.codecentric.boot.admin.server.notify.AbstractEventNotifier; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Mono; + +import static de.codecentric.boot.admin.server.domain.values.StatusInfo.*; + +/** + * 自定义事件通知处理 + * + * @author Lion Li + */ +@Slf4j +@Component +public class CustomNotifier extends AbstractEventNotifier { + + protected CustomNotifier(InstanceRepository repository) { + super(repository); + } + + @Override + @SuppressWarnings("all") + protected Mono doNotify(InstanceEvent event, Instance instance) { + return Mono.fromRunnable(() -> { + // 实例状态改变事件 + if (event instanceof InstanceStatusChangedEvent) { + // 获取实例注册名称 + String registName = instance.getRegistration().getName(); + // 获取实例ID + String instanceId = event.getInstance().getValue(); + // 获取实例状态 + String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(); + // 获取服务URL + String serviceUrl = instance.getRegistration().getServiceUrl(); + String statusName = switch (status) { + case STATUS_UP -> "服务上线"; // 实例成功启动并可以正常处理请求 + case STATUS_OFFLINE -> "服务离线"; //实例被手动或自动地从服务中移除 + case STATUS_RESTRICTED -> "服务受限"; //表示实例在某些方面受限,可能无法完全提供所有服务 + case STATUS_OUT_OF_SERVICE -> "停止服务状态"; //表示实例已被标记为停止提供服务,可能是计划内维护或测试 + case STATUS_DOWN -> "服务下线"; //实例因崩溃、错误或其他原因停止运行 + case STATUS_UNKNOWN -> "服务未知异常"; //监控系统无法确定实例的当前状态 + default -> "未知状态"; //没有匹配的状态 + }; + log.info("Instance Status Change: 状态名称【{}】, 注册名称【{}】, 实例ID【{}】, 状态【{}】, 服务URL【{}】", + statusName, registName, instanceId, status, serviceUrl); + } + }); + } +} diff --git a/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java new file mode 100644 index 0000000..e3a6892 --- /dev/null +++ b/ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java @@ -0,0 +1,64 @@ +package com.aizuda.snailjob.server.starter.filter; + +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class ActuatorAuthFilter implements Filter { + + private final String username; + private final String password; + + public ActuatorAuthFilter(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + // 获取 Authorization 头 + String authHeader = request.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith("Basic ")) { + // 如果没有提供 Authorization 或者格式不对,则返回 401 + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + + // 解码 Base64 编码的用户名和密码 + String base64Credentials = authHeader.substring("Basic ".length()); + byte[] credDecoded = Base64.getDecoder().decode(base64Credentials); + String credentials = new String(credDecoded, StandardCharsets.UTF_8); + String[] split = credentials.split(":"); + if (split.length != 2) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 验证用户名和密码 + if (!username.equals(split[0]) && password.equals(split[1])) { + response.setHeader("WWW-Authenticate", "Basic realm=\"realm\""); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); + return; + } + // 如果认证成功,继续处理请求 + filterChain.doFilter(request, response); + } + + @Override + public void init(FilterConfig filterConfig) { + } + + @Override + public void destroy() { + } + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java new file mode 100644 index 0000000..dc03afe --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java @@ -0,0 +1,92 @@ +package org.dromara.demo.controller; + +import cn.hutool.core.thread.ThreadUtil; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.R; +import org.dromara.common.redis.utils.RedisUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.Duration; + +/** + * spring-cache 演示案例 + * + * @author Lion Li + */ +// 类级别 缓存统一配置 +//@CacheConfig(cacheNames = CacheNames.DEMO_CACHE) +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/cache") +public class RedisCacheController { + + /** + * 测试 @Cacheable + *

+ * 表示这个方法有了缓存的功能,方法的返回值会被缓存下来 + * 下一次调用该方法前,会去检查是否缓存中已经有值 + * 如果有就直接返回,不调用方法 + * 如果没有,就调用方法,然后把结果缓存起来 + * 这个注解「一般用在查询方法上」 + *

+ * 重点说明: 缓存注解严谨与其他筛选数据功能一起使用 + * 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题 + *

+ * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 + */ + @Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null") + @GetMapping("/test1") + public R test1(String key, String value) { + return R.ok("操作成功", value); + } + + /** + * 测试 @CachePut + *

+ * 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用 + * 它「通常用在新增或者实时更新方法上」 + *

+ * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 + */ + @CachePut(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") + @GetMapping("/test2") + public R test2(String key, String value) { + return R.ok("操作成功", value); + } + + /** + * 测试 @CacheEvict + *

+ * 使用了CacheEvict注解的方法,会清空指定缓存 + * 「一般用在删除的方法上」 + *

+ * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 + */ + @CacheEvict(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") + @GetMapping("/test3") + public R test3(String key, String value) { + return R.ok("操作成功", value); + } + + /** + * 测试设置过期时间 + * 手动设置过期时间10秒 + * 11秒后获取 判断是否相等 + */ + @GetMapping("/test6") + public R test6(String key, String value) { + RedisUtils.setCacheObject(key, value); + boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10)); +// System.out.println("***********" + flag); + ThreadUtil.sleep(11 * 1000); + Object obj = RedisUtils.getCacheObject(key); + return R.ok(value.equals(obj)); + } + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java new file mode 100644 index 0000000..bdbf033 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java @@ -0,0 +1,47 @@ +package org.dromara.demo.controller; + +import org.dromara.common.core.domain.R; +import org.dromara.common.redis.utils.RedisUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Redis 发布订阅 演示案例 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/redis/pubsub") +public class RedisPubSubController { + + /** + * 发布消息 + * + * @param key 通道Key + * @param value 发送内容 + */ + @GetMapping("/pub") + public R pub(String key, String value) { + RedisUtils.publish(key, value, consumer -> { + System.out.println("发布通道 => " + key + ", 发送值 => " + value); + }); + return R.ok("操作成功"); + } + + /** + * 订阅消息 + * + * @param key 通道Key + */ + @GetMapping("/sub") + public R sub(String key) { + RedisUtils.subscribe(key, String.class, msg -> { + System.out.println("订阅通道 => " + key + ", 接收值 => " + msg); + }); + return R.ok("操作成功"); + } + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java new file mode 100644 index 0000000..f31c540 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java @@ -0,0 +1,147 @@ +package org.dromara.demo.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.demo.domain.TestDemo; +import org.dromara.demo.domain.bo.TestDemoBo; +import org.dromara.demo.domain.bo.TestDemoImportVo; +import org.dromara.demo.domain.vo.TestDemoVo; +import org.dromara.demo.service.ITestDemoService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * 测试单表Controller + * + * @author Lion Li + * @date 2021-07-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/demo") +public class TestDemoController extends BaseController { + + private final ITestDemoService testDemoService; + + /** + * 查询测试单表列表 + */ + @SaCheckPermission("demo:demo:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { + return testDemoService.queryPageList(bo, pageQuery); + } + + /** + * 自定义分页查询 + */ + @SaCheckPermission("demo:demo:list") + @GetMapping("/page") + public TableDataInfo page(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { + return testDemoService.customPageList(bo, pageQuery); + } + + /** + * 导入数据 + * + * @param file 导入文件 + */ + @Log(title = "测试单表", businessType = BusinessType.IMPORT) + @SaCheckPermission("demo:demo:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file) throws Exception { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true); + List list = MapstructUtils.convert(excelResult.getList(), TestDemo.class); + testDemoService.saveBatch(list); + return R.ok(excelResult.getAnalysis()); + } + + /** + * 导出测试单表列表 + */ + @SaCheckPermission("demo:demo:export") + @Log(title = "测试单表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(@Validated TestDemoBo bo, HttpServletResponse response) { + List list = testDemoService.queryList(bo); + // 测试雪花id导出 +// for (TestDemoVo vo : list) { +// vo.setId(1234567891234567893L); +// } + ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response); + } + + /** + * 获取测试单表详细信息 + * + * @param id 测试ID + */ + @SaCheckPermission("demo:demo:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("id") Long id) { + return R.ok(testDemoService.queryById(id)); + } + + /** + * 新增测试单表 + */ + @SaCheckPermission("demo:demo:add") + @Log(title = "测试单表", businessType = BusinessType.INSERT) + @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}") + @PostMapping() + public R add(@RequestBody TestDemoBo bo) { + // 使用校验工具对标 @Validated(AddGroup.class) 注解 + // 用于在非 Controller 的地方校验对象 + ValidatorUtils.validate(bo, AddGroup.class); + return toAjax(testDemoService.insertByBo(bo)); + } + + /** + * 修改测试单表 + */ + @SaCheckPermission("demo:demo:edit") + @Log(title = "测试单表", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestDemoBo bo) { + return toAjax(testDemoService.updateByBo(bo)); + } + + /** + * 删除测试单表 + * + * @param ids 测试ID串 + */ + @SaCheckPermission("demo:demo:remove") + @Log(title = "测试单表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(testDemoService.deleteWithValidByIds(Arrays.asList(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java new file mode 100644 index 0000000..3fd124c --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java @@ -0,0 +1,160 @@ +package org.dromara.demo.controller; + +import cn.hutool.core.collection.CollUtil; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.demo.domain.vo.ExportDemoVo; +import org.dromara.demo.listener.ExportDemoListener; +import org.dromara.demo.service.IExportExcelService; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 测试Excel功能 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/excel") +public class TestExcelController { + + private final IExportExcelService exportExcelService; + + /** + * 单列表多数据 + */ + @GetMapping("/exportTemplateOne") + public void exportTemplateOne(HttpServletResponse response) { + Map map = new HashMap<>(); + map.put("title", "单列表多数据"); + map.put("test1", "数据测试1"); + map.put("test2", "数据测试2"); + map.put("test3", "数据测试3"); + map.put("test4", "数据测试4"); + map.put("testTest", "666"); + List list = new ArrayList<>(); + list.add(new TestObj("单列表测试1", "列表测试1", "列表测试2", "列表测试3", "列表测试4")); + list.add(new TestObj("单列表测试2", "列表测试5", "列表测试6", "列表测试7", "列表测试8")); + list.add(new TestObj("单列表测试3", "列表测试9", "列表测试10", "列表测试11", "列表测试12")); + ExcelUtil.exportTemplate(CollUtil.newArrayList(map, list), "单列表.xlsx", "excel/单列表.xlsx", response); + } + + /** + * 多列表多数据 + */ + @GetMapping("/exportTemplateMuliti") + public void exportTemplateMuliti(HttpServletResponse response) { + Map map = new HashMap<>(); + map.put("title1", "标题1"); + map.put("title2", "标题2"); + map.put("title3", "标题3"); + map.put("title4", "标题4"); + map.put("author", "Lion Li"); + List list1 = new ArrayList<>(); + list1.add(new TestObj1("list1测试1", "list1测试2", "list1测试3")); + list1.add(new TestObj1("list1测试4", "list1测试5", "list1测试6")); + list1.add(new TestObj1("list1测试7", "list1测试8", "list1测试9")); + List list2 = new ArrayList<>(); + list2.add(new TestObj1("list2测试1", "list2测试2", "list2测试3")); + list2.add(new TestObj1("list2测试4", "list2测试5", "list2测试6")); + List list3 = new ArrayList<>(); + list3.add(new TestObj1("list3测试1", "list3测试2", "list3测试3")); + List list4 = new ArrayList<>(); + list4.add(new TestObj1("list4测试1", "list4测试2", "list4测试3")); + list4.add(new TestObj1("list4测试4", "list4测试5", "list4测试6")); + list4.add(new TestObj1("list4测试7", "list4测试8", "list4测试9")); + list4.add(new TestObj1("list4测试10", "list4测试11", "list4测试12")); + Map multiListMap = new HashMap<>(); + multiListMap.put("map", map); + multiListMap.put("data1", list1); + multiListMap.put("data2", list2); + multiListMap.put("data3", list3); + multiListMap.put("data4", list4); + ExcelUtil.exportTemplateMultiList(multiListMap, "多列表.xlsx", "excel/多列表.xlsx", response); + } + + /** + * 导出下拉框 + * + * @param response / + */ + @GetMapping("/exportWithOptions") + public void exportWithOptions(HttpServletResponse response) { + exportExcelService.exportWithOptions(response); + } + + /** + * 多个sheet导出 + */ + @GetMapping("/exportTemplateMultiSheet") + public void exportTemplateMultiSheet(HttpServletResponse response) { + List list1 = new ArrayList<>(); + list1.add(new TestObj1("list1测试1", "list1测试2", "list1测试3")); + list1.add(new TestObj1("list1测试4", "list1测试5", "list1测试6")); + List list2 = new ArrayList<>(); + list2.add(new TestObj1("list2测试1", "list2测试2", "list2测试3")); + list2.add(new TestObj1("list2测试4", "list2测试5", "list2测试6")); + List list3 = new ArrayList<>(); + list3.add(new TestObj1("list3测试1", "list3测试2", "list3测试3")); + list3.add(new TestObj1("list3测试4", "list3测试5", "list3测试6")); + List list4 = new ArrayList<>(); + list4.add(new TestObj1("list4测试1", "list4测试2", "list4测试3")); + list4.add(new TestObj1("list4测试4", "list4测试5", "list4测试6")); + + List> list = new ArrayList<>(); + Map sheetMap1 = new HashMap<>(); + sheetMap1.put("data1", list1); + Map sheetMap2 = new HashMap<>(); + sheetMap2.put("data2", list2); + Map sheetMap3 = new HashMap<>(); + sheetMap3.put("data3", list3); + Map sheetMap4 = new HashMap<>(); + sheetMap4.put("data4", list4); + + list.add(sheetMap1); + list.add(sheetMap2); + list.add(sheetMap3); + list.add(sheetMap4); + ExcelUtil.exportTemplateMultiSheet(list, "多sheet列表", "excel/多sheet列表.xlsx", response); + } + + /** + * 导入表格 + */ + @PostMapping(value = "/importWithOptions", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public List importWithOptions(@RequestPart("file") MultipartFile file) throws Exception { + // 处理解析结果 + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), ExportDemoVo.class, new ExportDemoListener()); + return excelResult.getList(); + } + + @Data + @AllArgsConstructor + static class TestObj1 { + private String test1; + private String test2; + private String test3; + } + + @Data + @AllArgsConstructor + static class TestObj { + private String name; + private String list1; + private String list2; + private String list3; + private String list4; + } + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java new file mode 100644 index 0000000..5c55205 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java @@ -0,0 +1,107 @@ +package org.dromara.demo.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.demo.domain.bo.TestTreeBo; +import org.dromara.demo.domain.vo.TestTreeVo; +import org.dromara.demo.service.ITestTreeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +/** + * 测试树表Controller + * + * @author Lion Li + * @date 2021-07-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/tree") +public class TestTreeController extends BaseController { + + private final ITestTreeService testTreeService; + + /** + * 查询测试树表列表 + */ + @SaCheckPermission("demo:tree:list") + @GetMapping("/list") + public R> list(@Validated(QueryGroup.class) TestTreeBo bo) { + List list = testTreeService.queryList(bo); + return R.ok(list); + } + + /** + * 导出测试树表列表 + */ + @SaCheckPermission("demo:tree:export") + @Log(title = "测试树表", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public void export(@Validated TestTreeBo bo, HttpServletResponse response) { + List list = testTreeService.queryList(bo); + ExcelUtil.exportExcel(list, "测试树表", TestTreeVo.class, response); + } + + /** + * 获取测试树表详细信息 + * + * @param id 测试树ID + */ + @SaCheckPermission("demo:tree:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("id") Long id) { + return R.ok(testTreeService.queryById(id)); + } + + /** + * 新增测试树表 + */ + @SaCheckPermission("demo:tree:add") + @Log(title = "测试树表", businessType = BusinessType.INSERT) + @RepeatSubmit + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TestTreeBo bo) { + return toAjax(testTreeService.insertByBo(bo)); + } + + /** + * 修改测试树表 + */ + @SaCheckPermission("demo:tree:edit") + @Log(title = "测试树表", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestTreeBo bo) { + return toAjax(testTreeService.updateByBo(bo)); + } + + /** + * 删除测试树表 + * + * @param ids 测试树ID串 + */ + @SaCheckPermission("demo:tree:remove") + @Log(title = "测试树表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(testTreeService.deleteWithValidByIds(Arrays.asList(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java new file mode 100644 index 0000000..16c30f8 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java @@ -0,0 +1 @@ +package org.dromara.demo.controller; diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java new file mode 100644 index 0000000..d3af0c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java @@ -0,0 +1,68 @@ +package org.dromara.demo.domain; + +import com.baomidou.mybatisplus.annotation.*; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 测试单表对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_demo") +public class TestDemo extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 部门id + */ + private Long deptId; + + /** + * 用户id + */ + private Long userId; + + /** + * 排序号 + */ + @OrderBy(asc = false, sort = 1) + private Integer orderNum; + + /** + * key键 + */ + private String testKey; + + /** + * 值 + */ + private String value; + + /** + * 版本 + */ + @Version + private Long version; + + /** + * 删除标志 + */ + @TableLogic + private Long delFlag; + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java new file mode 100644 index 0000000..bdcd596 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java @@ -0,0 +1,29 @@ +package org.dromara.demo.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.encrypt.annotation.EncryptField; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_demo") +public class TestDemoEncrypt extends TestDemo { + + /** + * key键 + */ + // @EncryptField(algorithm=AlgorithmType.SM2, privateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgZSlOvw8FBiH+aFJWLYZP/VRjg9wjfRarTkGBZd/T3N+gCgYIKoEcz1UBgi2hRANCAAR5DGuQwJqkxnbCsP+iPSDoHWIF4RwcR5EsSvT8QPxO1wRkR2IhCkzvRb32x2CUgJFdvoqVqfApFDPZzShqzBwX", publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEeQxrkMCapMZ2wrD/oj0g6B1iBeEcHEeRLEr0/ED8TtcEZEdiIQpM70W99sdglICRXb6KlanwKRQz2c0oaswcFw==") + @EncryptField(algorithm = AlgorithmType.RSA, privateKey = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANBBEeueWlXlkkj2+WY5l+IWe42d8b5K28g+G/CFKC/yYAEHtqGlCsBOrb+YBkG9mPzmuYA/n9k0NFIc8E8yY5vZQaroyFBrTTWEzG9RY2f7Y3svVyybs6jpXSUs4xff8abo7wL1Y/wUaeatTViamxYnyTvdTmLm3d+JjRij68rxAgMBAAECgYAB0TnhXraSopwIVRfmboea1b0upl+BUdTJcmci412UjrKr5aE695ZLPkXbFXijVu7HJlyyv94NVUdaMACV7Ku/S2RuNB70M7YJm8rAjHFC3/i2ZeIM60h1Ziy4QKv0XM3pRATlDCDNhC1WUrtQCQSgU8kcp6eUUppruOqDzcY04QJBAPm9+sBP9CwDRgy3e5+V8aZtJkwDstb0lVVV/KY890cydVxiCwvX3fqVnxKMlb+x0YtH0sb9v+71xvK2lGobaRECQQDVePU6r/cCEfpc+nkWF6osAH1f8Mux3rYv2DoBGvaPzV2BGfsLed4neRfCwWNCKvGPCdW+L0xMJg8+RwaoBUPhAkAT5kViqXxFPYWJYd1h2+rDXhMdH3ZSlm6HvDBDdrwlWinr0Iwcx3iSjPV93uHXwm118aUj4fg3LDJMCKxOwBxhAkByrQXfvwOMYygBprRBf/j0plazoWFrbd6lGR0f1uI5IfNnFRPdeFw1DEINZ2Hw+6zEUF44SqRMC+4IYJNc02dBAkBCgy7RvfyV/A7N6kKXxTHauY0v6XwSSvpeKtRJkbIcRWOdIYvaHO9L7cklj3vIEdwjSUp9K4VTBYYlmAz1xh03", publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQQRHrnlpV5ZJI9vlmOZfiFnuNnfG+StvIPhvwhSgv8mABB7ahpQrATq2/mAZBvZj85rmAP5/ZNDRSHPBPMmOb2UGq6MhQa001hMxvUWNn+2N7L1csm7Oo6V0lLOMX3/Gm6O8C9WP8FGnmrU1YmpsWJ8k73U5i5t3fiY0Yo+vK8QIDAQAB") + private String testKey; + + /** + * 值 + */ + // @EncryptField // 什么也不写走默认yml配置 + // @EncryptField(algorithm = AlgorithmType.SM4, password = "10rfylhtccpuyke5") + @EncryptField(algorithm = AlgorithmType.AES, password = "10rfylhtccpuyke5") + private String value; + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java new file mode 100644 index 0000000..e7ea807 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java @@ -0,0 +1,111 @@ +package org.dromara.demo.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelNotation; +import org.dromara.common.excel.annotation.ExcelRequired; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.demo.domain.TestDemo; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 测试单表视图对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TestDemo.class) +public class TestDemoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 部门id + */ + @ExcelRequired + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 用户id + */ + @ExcelRequired + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 排序号 + */ + @ExcelRequired + @ExcelProperty(value = "排序号") + private Integer orderNum; + + /** + * key键 + */ + @ExcelNotation(value = "测试key") + @ExcelProperty(value = "key键") + private String testKey; + + /** + * 值 + */ + @ExcelNotation(value = "测试value") + @ExcelProperty(value = "值") + private String value; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 创建人 + */ + @ExcelProperty(value = "创建人") + private Long createBy; + + /** + * 创建人账号 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + @ExcelProperty(value = "创建人账号") + private String createByName; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + + /** + * 更新人 + */ + @ExcelProperty(value = "更新人") + private Long updateBy; + + /** + * 更新人账号 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "updateBy") + @ExcelProperty(value = "更新人账号") + private String updateByName; + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java new file mode 100644 index 0000000..19b2d52 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java @@ -0,0 +1,64 @@ +package org.dromara.demo.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.demo.domain.TestDemo; +import org.dromara.demo.domain.vo.TestDemoVo; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; + +/** + * 测试单表Mapper接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +public interface TestDemoMapper extends BaseMapperPlus { + + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + Page customPageList(@Param("page") Page page, @Param("ew") Wrapper wrapper); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + + @Override + @DataPermission(value = { + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }, joinStr = "AND") + List selectByIds(@Param(Constants.COLL) Collection idList); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int updateById(@Param(Constants.ENTITY) TestDemo entity); + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java new file mode 100644 index 0000000..e5f4c44 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java @@ -0,0 +1,21 @@ +package org.dromara.demo.mapper; + +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.demo.domain.TestTree; +import org.dromara.demo.domain.vo.TestTreeVo; + +/** + * 测试树表Mapper接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +@DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") +}) +public interface TestTreeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java new file mode 100644 index 0000000..ff1c4df --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java @@ -0,0 +1 @@ +package org.dromara.demo.mapper; diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java new file mode 100644 index 0000000..bca4192 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java @@ -0,0 +1,71 @@ +package org.dromara.demo.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.demo.domain.TestDemo; +import org.dromara.demo.domain.bo.TestDemoBo; +import org.dromara.demo.domain.vo.TestDemoVo; + +import java.util.Collection; +import java.util.List; + +/** + * 测试单表Service接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +public interface ITestDemoService { + + /** + * 查询单个 + * + * @return + */ + TestDemoVo queryById(Long id); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(TestDemoBo bo, PageQuery pageQuery); + + /** + * 自定义分页查询 + */ + TableDataInfo customPageList(TestDemoBo bo, PageQuery pageQuery); + + /** + * 查询列表 + */ + List queryList(TestDemoBo bo); + + /** + * 根据新增业务对象插入测试单表 + * + * @param bo 测试单表新增业务对象 + * @return + */ + Boolean insertByBo(TestDemoBo bo); + + /** + * 根据编辑业务对象修改测试单表 + * + * @param bo 测试单表编辑业务对象 + * @return + */ + Boolean updateByBo(TestDemoBo bo); + + /** + * 校验并删除数据 + * + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 批量保存 + */ + Boolean saveBatch(List list); +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java new file mode 100644 index 0000000..9155201 --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java @@ -0,0 +1,52 @@ +package org.dromara.demo.service; + +import org.dromara.demo.domain.bo.TestTreeBo; +import org.dromara.demo.domain.vo.TestTreeVo; + +import java.util.Collection; +import java.util.List; + +/** + * 测试树表Service接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +public interface ITestTreeService { + /** + * 查询单个 + * + * @return + */ + TestTreeVo queryById(Long id); + + /** + * 查询列表 + */ + List queryList(TestTreeBo bo); + + /** + * 根据新增业务对象插入测试树表 + * + * @param bo 测试树表新增业务对象 + * @return + */ + Boolean insertByBo(TestTreeBo bo); + + /** + * 根据编辑业务对象修改测试树表 + * + * @param bo 测试树表编辑业务对象 + * @return + */ + Boolean updateByBo(TestTreeBo bo); + + /** + * 校验并删除数据 + * + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java new file mode 100644 index 0000000..e4e548b --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java @@ -0,0 +1,88 @@ +package org.dromara.demo.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.demo.domain.TestTree; +import org.dromara.demo.domain.bo.TestTreeBo; +import org.dromara.demo.domain.vo.TestTreeVo; +import org.dromara.demo.mapper.TestTreeMapper; +import org.dromara.demo.service.ITestTreeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 测试树表Service业务层处理 + * + * @author Lion Li + * @date 2021-07-26 + */ +// @DS("slave") // 切换从库查询 +@RequiredArgsConstructor +@Service +public class TestTreeServiceImpl implements ITestTreeService { + + private final TestTreeMapper baseMapper; + + @Override + public TestTreeVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + // @DS("slave") // 切换从库查询 + @Override + public List queryList(TestTreeBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TestTreeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + lqw.orderByAsc(TestTree::getId); + return lqw; + } + + @Override + public Boolean insertByBo(TestTreeBo bo) { + TestTree add = MapstructUtils.convert(bo, TestTree.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + @Override + public Boolean updateByBo(TestTreeBo bo) { + TestTree update = MapstructUtils.convert(bo, TestTree.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(TestTree entity) { + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-demo/src/main/resources/excel/多列表.xlsx b/ruoyi-modules/ruoyi-demo/src/main/resources/excel/多列表.xlsx new file mode 100644 index 0000000..c7d11dc Binary files /dev/null and b/ruoyi-modules/ruoyi-demo/src/main/resources/excel/多列表.xlsx differ diff --git a/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/pom.xml b/ruoyi-modules/ruoyi-generator/pom.xml new file mode 100644 index 0000000..4906029 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/pom.xml @@ -0,0 +1,84 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + + ruoyi-generator + + + generator 代码生成 + + + + + + org.dromara + ruoyi-common-core + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-mybatis + + + + org.dromara + ruoyi-common-web + + + + org.dromara + ruoyi-common-log + + + + + org.apache.velocity + velocity-engine-core + + + + org.anyline + anyline-environment-spring-data-jdbc + ${anyline.version} + + + + org.anyline + anyline-data-jdbc-mysql + ${anyline.version} + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java new file mode 100644 index 0000000..b29f8c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java @@ -0,0 +1,73 @@ +package org.dromara.generator.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +/** + * 读取代码生成相关配置 + * + * @author ruoyi + */ +@Component +@ConfigurationProperties(prefix = "gen") +@PropertySource(value = {"classpath:generator.yml"}, encoding = "UTF-8") +public class GenConfig { + + /** + * 作者 + */ + public static String author; + + /** + * 生成包路径 + */ + public static String packageName; + + /** + * 自动去除表前缀,默认是false + */ + public static boolean autoRemovePre; + + /** + * 表前缀(类名不会包含表前缀) + */ + public static String tablePrefix; + + public static String getAuthor() { + return author; + } + + @Value("${author}") + public void setAuthor(String author) { + GenConfig.author = author; + } + + public static String getPackageName() { + return packageName; + } + + @Value("${packageName}") + public void setPackageName(String packageName) { + GenConfig.packageName = packageName; + } + + public static boolean getAutoRemovePre() { + return autoRemovePre; + } + + @Value("${autoRemovePre}") + public void setAutoRemovePre(boolean autoRemovePre) { + GenConfig.autoRemovePre = autoRemovePre; + } + + public static String getTablePrefix() { + return tablePrefix; + } + + @Value("${tablePrefix}") + public void setTablePrefix(String tablePrefix) { + GenConfig.tablePrefix = tablePrefix; + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java new file mode 100644 index 0000000..f2d7257 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java @@ -0,0 +1,196 @@ +package org.dromara.generator.domain; + +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.generator.constant.GenConstants; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +/** + * 业务表 gen_table + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gen_table") +public class GenTable extends BaseEntity { + + /** + * 编号 + */ + @TableId(value = "table_id") + private Long tableId; + + /** + * 数据源名称 + */ + @NotBlank(message = "数据源名称不能为空") + private String dataName; + + /** + * 表名称 + */ + @NotBlank(message = "表名称不能为空") + private String tableName; + + /** + * 表描述 + */ + @NotBlank(message = "表描述不能为空") + private String tableComment; + + /** + * 关联父表的表名 + */ + private String subTableName; + + /** + * 本表关联父表的外键名 + */ + private String subTableFkName; + + /** + * 实体类名称(首字母大写) + */ + @NotBlank(message = "实体类名称不能为空") + private String className; + + /** + * 使用的模板(crud单表操作 tree树表操作 sub主子表操作) + */ + private String tplCategory; + + /** + * 生成包路径 + */ + @NotBlank(message = "生成包路径不能为空") + private String packageName; + + /** + * 生成模块名 + */ + @NotBlank(message = "生成模块名不能为空") + private String moduleName; + + /** + * 生成业务名 + */ + @NotBlank(message = "生成业务名不能为空") + private String businessName; + + /** + * 生成功能名 + */ + @NotBlank(message = "生成功能名不能为空") + private String functionName; + + /** + * 生成作者 + */ + @NotBlank(message = "作者不能为空") + private String functionAuthor; + + /** + * 生成代码方式(0zip压缩包 1自定义路径) + */ + private String genType; + + /** + * 生成路径(不填默认项目路径) + */ + @TableField(updateStrategy = FieldStrategy.NOT_EMPTY) + private String genPath; + + /** + * 主键信息 + */ + @TableField(exist = false) + private GenTableColumn pkColumn; + + /** + * 表列信息 + */ + @Valid + @TableField(exist = false) + private List columns; + + /** + * 其它生成选项 + */ + private String options; + + /** + * 备注 + */ + private String remark; + + /** + * 树编码字段 + */ + @TableField(exist = false) + private String treeCode; + + /** + * 树父编码字段 + */ + @TableField(exist = false) + private String treeParentCode; + + /** + * 树名称字段 + */ + @TableField(exist = false) + private String treeName; + + /* + * 菜单id列表 + */ + @TableField(exist = false) + private List menuIds; + + /** + * 上级菜单ID字段 + */ + @TableField(exist = false) + private Long parentMenuId; + + /** + * 上级菜单名称字段 + */ + @TableField(exist = false) + private String parentMenuName; + + public boolean isTree() { + return isTree(this.tplCategory); + } + + public static boolean isTree(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); + } + + public boolean isCrud() { + return isCrud(this.tplCategory); + } + + public static boolean isCrud(String tplCategory) { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); + } + + public boolean isSuperColumn(String javaField) { + return isSuperColumn(this.tplCategory, javaField); + } + + public static boolean isSuperColumn(String tplCategory, String javaField) { + return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java new file mode 100644 index 0000000..996cf9b --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java @@ -0,0 +1,219 @@ +package org.dromara.generator.util; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.RegExUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.generator.config.GenConfig; +import org.dromara.generator.constant.GenConstants; +import org.dromara.generator.domain.GenTable; +import org.dromara.generator.domain.GenTableColumn; + +import java.util.Arrays; + +/** + * 代码生成器 工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class GenUtils { + + /** + * 初始化表信息 + */ + public static void initTable(GenTable genTable) { + genTable.setClassName(convertClassName(genTable.getTableName())); + genTable.setPackageName(GenConfig.getPackageName()); + genTable.setModuleName(getModuleName(GenConfig.getPackageName())); + genTable.setBusinessName(getBusinessName(genTable.getTableName())); + genTable.setFunctionName(replaceText(genTable.getTableComment())); + genTable.setFunctionAuthor(GenConfig.getAuthor()); + genTable.setCreateTime(null); + genTable.setUpdateTime(null); + } + + /** + * 初始化列属性字段 + */ + public static void initColumnField(GenTableColumn column, GenTable table) { + String dataType = getDbType(column.getColumnType()); + // 统一转小写 避免有些数据库默认大写问题 如果需要特别书写方式 请在实体类增加注解标注别名 + String columnName = column.getColumnName().toLowerCase(); + column.setTableId(table.getTableId()); + column.setCreateTime(null); + column.setUpdateTime(null); + // 设置java字段名 + column.setJavaField(StringUtils.toCamelCase(columnName)); + // 设置默认类型 + column.setJavaType(GenConstants.TYPE_STRING); + column.setQueryType(GenConstants.QUERY_EQ); + + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) { + // 字符串长度超过500设置为文本域 + Integer columnLength = getColumnLength(column.getColumnType()); + String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; + column.setHtmlType(htmlType); + } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) { + column.setJavaType(GenConstants.TYPE_DATE); + column.setHtmlType(GenConstants.HTML_DATETIME); + } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) { + column.setHtmlType(GenConstants.HTML_INPUT); + // 数据库的数字字段与java不匹配 且很多数据库的数字字段很模糊 例如oracle只有number没有细分 + // 所以默认数字类型全为Long可在界面上自行编辑想要的类型 有什么特殊需求也可以在这里特殊处理 + column.setJavaType(GenConstants.TYPE_LONG); + } + + // BO对象 默认插入勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) { + column.setIsInsert(GenConstants.REQUIRE); + } + // BO对象 默认编辑勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) { + column.setIsEdit(GenConstants.REQUIRE); + } + // VO对象 默认返回勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) { + column.setIsList(GenConstants.REQUIRE); + } + // BO对象 默认查询勾选 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) { + column.setIsQuery(GenConstants.REQUIRE); + } + + // 查询字段类型 + if (StringUtils.endsWithIgnoreCase(columnName, "name")) { + column.setQueryType(GenConstants.QUERY_LIKE); + } + // 状态字段设置单选框 + if (StringUtils.endsWithIgnoreCase(columnName, "status")) { + column.setHtmlType(GenConstants.HTML_RADIO); + } + // 类型&性别字段设置下拉框 + else if (StringUtils.endsWithIgnoreCase(columnName, "type") + || StringUtils.endsWithIgnoreCase(columnName, "sex")) { + column.setHtmlType(GenConstants.HTML_SELECT); + } + // 图片字段设置图片上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "image")) { + column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); + } + // 文件字段设置文件上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) { + column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) { + column.setHtmlType(GenConstants.HTML_EDITOR); + } + } + + /** + * 校验数组是否包含指定值 + * + * @param arr 数组 + * @param targetValue 值 + * @return 是否包含 + */ + public static boolean arraysContains(String[] arr, String targetValue) { + return Arrays.asList(arr).contains(targetValue); + } + + /** + * 获取模块名 + * + * @param packageName 包名 + * @return 模块名 + */ + public static String getModuleName(String packageName) { + int lastIndex = packageName.lastIndexOf("."); + int nameLength = packageName.length(); + return StringUtils.substring(packageName, lastIndex + 1, nameLength); + } + + /** + * 获取业务名 + * + * @param tableName 表名 + * @return 业务名 + */ + public static String getBusinessName(String tableName) { + int firstIndex = tableName.indexOf("_"); + int nameLength = tableName.length(); + String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength); + businessName = StringUtils.toCamelCase(businessName); + return businessName; + } + + /** + * 表名转换成Java类名 + * + * @param tableName 表名称 + * @return 类名 + */ + public static String convertClassName(String tableName) { + boolean autoRemovePre = GenConfig.getAutoRemovePre(); + String tablePrefix = GenConfig.getTablePrefix(); + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) { + String[] searchList = StringUtils.split(tablePrefix, StringUtils.SEPARATOR); + tableName = replaceFirst(tableName, searchList); + } + return StringUtils.convertToCamelCase(tableName); + } + + /** + * 批量替换前缀 + * + * @param replacementm 替换值 + * @param searchList 替换列表 + */ + public static String replaceFirst(String replacementm, String[] searchList) { + String text = replacementm; + for (String searchString : searchList) { + if (replacementm.startsWith(searchString)) { + text = replacementm.replaceFirst(searchString, StringUtils.EMPTY); + break; + } + } + return text; + } + + /** + * 关键字替换 + * + * @param text 需要被替换的名字 + * @return 替换后的名字 + */ + public static String replaceText(String text) { + return RegExUtils.replaceAll(text, "(?:表|若依)", ""); + } + + /** + * 获取数据库类型字段 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static String getDbType(String columnType) { + if (StringUtils.indexOf(columnType, "(") > 0) { + return StringUtils.substringBefore(columnType, "("); + } else { + return columnType; + } + } + + /** + * 获取字段长度 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static Integer getColumnLength(String columnType) { + if (StringUtils.indexOf(columnType, "(") > 0) { + String length = StringUtils.substringBetween(columnType, "(", ")"); + return Integer.valueOf(length); + } else { + return 0; + } + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java new file mode 100644 index 0000000..09e0121 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java @@ -0,0 +1,35 @@ +package org.dromara.generator.util; + +import org.dromara.common.core.constant.Constants; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.velocity.app.Velocity; + +import java.util.Properties; + +/** + * VelocityEngine工厂 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class VelocityInitializer { + + /** + * 初始化vm方法 + */ + public static void initVelocity() { + Properties p = new Properties(); + try { + // 加载classpath目录下的vm文件 + p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + // 定义字符集 + p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8); + // 初始化Velocity引擎,指定配置Properties + Velocity.init(p); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml b/ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml new file mode 100644 index 0000000..d779d97 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml @@ -0,0 +1,10 @@ +# 代码生成 +gen: + # 作者 + author: Lion Li + # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool + packageName: org.dromara.system + # 自动去除表前缀,默认是false + autoRemovePre: false + # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) + tablePrefix: sys_ diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm new file mode 100644 index 0000000..6438971 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm @@ -0,0 +1,115 @@ +package ${packageName}.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import ${packageName}.domain.vo.${ClassName}Vo; +import ${packageName}.domain.bo.${ClassName}Bo; +import ${packageName}.service.I${ClassName}Service; +#if($table.crud) +import org.dromara.common.mybatis.core.page.TableDataInfo; +#elseif($table.tree) +#end + +/** + * ${functionName} + * + * @author ${author} + * @date ${datetime} + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/${moduleName}/${businessName}") +public class ${ClassName}Controller extends BaseController { + + private final I${ClassName}Service ${className}Service; + + /** + * 查询${functionName}列表 + */ + @SaCheckPermission("${permissionPrefix}:list") + @GetMapping("/list") +#if($table.crud) + public TableDataInfo<${ClassName}Vo> list(${ClassName}Bo bo, PageQuery pageQuery) { + return ${className}Service.queryPageList(bo, pageQuery); + } +#elseif($table.tree) + public R> list(${ClassName}Bo bo) { + List<${ClassName}Vo> list = ${className}Service.queryList(bo); + return R.ok(list); + } +#end + + /** + * 导出${functionName}列表 + */ + @SaCheckPermission("${permissionPrefix}:export") + @Log(title = "${functionName}", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(${ClassName}Bo bo, HttpServletResponse response) { + List<${ClassName}Vo> list = ${className}Service.queryList(bo); + ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response); + } + + /** + * 获取${functionName}详细信息 + * + * @param ${pkColumn.javaField} 主键 + */ + @SaCheckPermission("${permissionPrefix}:query") + @GetMapping("/{${pkColumn.javaField}}") + public R<${ClassName}Vo> getInfo(@NotNull(message = "主键不能为空") + @PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) { + return R.ok(${className}Service.queryById(${pkColumn.javaField})); + } + + /** + * 新增${functionName} + */ + @SaCheckPermission("${permissionPrefix}:add") + @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) { + return toAjax(${className}Service.insertByBo(bo)); + } + + /** + * 修改${functionName} + */ + @SaCheckPermission("${permissionPrefix}:edit") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) { + return toAjax(${className}Service.updateByBo(bo)); + } + + /** + * 删除${functionName} + * + * @param ${pkColumn.javaField}s 主键串 + */ + @SaCheckPermission("${permissionPrefix}:remove") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @DeleteMapping("/{${pkColumn.javaField}s}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) { + return toAjax(${className}Service.deleteWithValidByIds(List.of(${pkColumn.javaField}s), true)); + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm new file mode 100644 index 0000000..35a468e --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm @@ -0,0 +1,64 @@ +export interface ${BusinessName}VO { +#foreach ($column in $columns) +#if($column.list) + /** + * $column.columnComment + */ + $column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#if($column.htmlType == "imageUpload") + /** + * ${column.columnComment}Url + */ + ${column.javaField}Url: string; +#end +#end +#end +#if ($table.tree) + /** + * 子对象 + */ + children: ${BusinessName}VO[]; +#end +} + +export interface ${BusinessName}Form extends BaseEntity { +#foreach ($column in $columns) +#if($column.insert || $column.edit) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end +} + +export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{ + +#foreach ($column in $columns) +#if($column.query) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end + /** + * 日期范围参数 + */ + params?: any; +} + + + diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/mapper/ShopOrderMapper.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/mapper/ShopOrderMapper.java new file mode 100644 index 0000000..d78275e --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/mapper/ShopOrderMapper.java @@ -0,0 +1,11 @@ +package org.dromara.job.mapper; + + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TShopOrder; +import org.dromara.zhishu.domain.vo.TShopOrderVo; + + +public interface ShopOrderMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java new file mode 100644 index 0000000..2f118b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java @@ -0,0 +1 @@ +package org.dromara.job; diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/service/IPddService.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/service/IPddService.java new file mode 100644 index 0000000..66f56bc --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/service/IPddService.java @@ -0,0 +1,14 @@ +package org.dromara.job.service; + +import com.google.gson.JsonArray; +import org.dromara.job.domains.ShopOrderVO; + +public interface IPddService { + + //历史订单 + public void getConfirmOrderList(ShopOrderVO shopOrderVO) throws Exception; + + //增量订单 + public void getNowOrderList(ShopOrderVO shopOrderVO) throws Exception; + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java new file mode 100644 index 0000000..93f61c6 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java @@ -0,0 +1,38 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.client.model.ExecuteResult; +import org.dromara.job.domains.ShopOrderVO; +import org.dromara.job.service.IPddService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author opensnail + * @date 2024-05-17 + */ + +@Component +@JobExecutor(name = "testJobExecutor") +public class TestAnnoJobExecutor { + + @Autowired + public IPddService pddService; + + //todo 拿不到未支付订单 + //同步三个月以内历史订单(根据成交时间) --根据成交时间同步订单(现在到三个月之内) + public ExecuteResult jobExecute(JobArgs jobArgs) throws Exception { + //todo 多店铺需要同步 + ShopOrderVO shopOrderVO = new ShopOrderVO(); + shopOrderVO.setMallId(146727039); + shopOrderVO.setShopName("古威教辅专营店"); + shopOrderVO.setAccessToken("be9ca8b801f74e32a969ca050194a0e17a86d7fd"); + pddService.getConfirmOrderList(shopOrderVO); + return ExecuteResult.success(shopOrderVO.getShopName()+"同步成功"); + } + + + + +} diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml new file mode 100644 index 0000000..9cfdd5c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/pom.xml @@ -0,0 +1,109 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + + ruoyi-system + + + system系统模块 + + + + + + org.dromara + ruoyi-common-core + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-mybatis + + + + org.dromara + ruoyi-common-translation + + + + + org.dromara + ruoyi-common-oss + + + + org.dromara + ruoyi-common-log + + + + + org.dromara + ruoyi-common-excel + + + + + org.dromara + ruoyi-common-sms + + + + org.dromara + ruoyi-common-tenant + + + + org.dromara + ruoyi-common-security + + + + org.dromara + ruoyi-common-web + + + + org.dromara + ruoyi-common-idempotent + + + + org.dromara + ruoyi-common-sensitive + + + + org.dromara + ruoyi-common-encrypt + + + + org.dromara + ruoyi-common-websocket + + + + org.dromara + ruoyi-common-sse + + + com.aizuda + snail-job-client-job-core + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java new file mode 100644 index 0000000..575aba6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java @@ -0,0 +1,75 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; +import org.dromara.system.service.ISysOperLogService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 操作日志记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController { + + private final ISysOperLogService operLogService; + + /** + * 获取操作日志记录列表 + */ + @SaCheckPermission("monitor:operlog:list") + @GetMapping("/list") + public TableDataInfo list(SysOperLogBo operLog, PageQuery pageQuery) { + return operLogService.selectPageOperLogList(operLog, pageQuery); + } + + /** + * 导出操作日志记录列表 + */ + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:operlog:export") + @PostMapping("/export") + public void export(SysOperLogBo operLog, HttpServletResponse response) { + List list = operLogService.selectOperLogList(operLog); + ExcelUtil.exportExcel(list, "操作日志", SysOperLogVo.class, response); + } + + /** + * 批量删除操作日志记录 + * @param operIds 日志ids + */ + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/{operIds}") + public R remove(@PathVariable Long[] operIds) { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + /** + * 清理操作日志记录 + */ + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/clean") + public R clean() { + operLogService.cleanOperLog(); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java new file mode 100644 index 0000000..b0281cf --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java @@ -0,0 +1,38 @@ +package org.dromara.system.controller.system; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.service.ISysSocialService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 社会化关系 + * + * @author thiszhc + * @date 2023-06-16 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/social") +public class SysSocialController extends BaseController { + + private final ISysSocialService socialUserService; + + /** + * 查询社会化关系列表 + */ + @GetMapping("/list") + public R> list() { + return R.ok(socialUserService.queryListByUserId(LoginHelper.getUserId())); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java new file mode 100644 index 0000000..9354059 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java @@ -0,0 +1,167 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import cn.dev33.satoken.annotation.SaMode; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysTenantPackageBo; +import org.dromara.system.domain.vo.SysTenantPackageVo; +import org.dromara.system.service.ISysTenantPackageService; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 租户套餐管理 + * + * @author Michelle.Chung + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/tenant/package") +@ConditionalOnProperty(value = "tenant.enable", havingValue = "true") +public class SysTenantPackageController extends BaseController { + + private final ISysTenantPackageService tenantPackageService; + + /** + * 查询租户套餐列表 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:list") + @GetMapping("/list") + public TableDataInfo list(SysTenantPackageBo bo, PageQuery pageQuery) { + return tenantPackageService.queryPageList(bo, pageQuery); + } + + /** + * 查询租户套餐下拉选列表 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:list") + @GetMapping("/selectList") + public R> selectList() { + return R.ok(tenantPackageService.selectList()); + } + + /** + * 导出租户套餐列表 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:export") + @Log(title = "租户套餐", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysTenantPackageBo bo, HttpServletResponse response) { + List list = tenantPackageService.queryList(bo); + ExcelUtil.exportExcel(list, "租户套餐", SysTenantPackageVo.class, response); + } + + /** + * 获取租户套餐详细信息 + * + * @param packageId 主键 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:query") + @GetMapping("/{packageId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long packageId) { + return R.ok(tenantPackageService.queryById(packageId)); + } + + /** + * 新增租户套餐 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:add") + @Log(title = "租户套餐", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) { + if (!tenantPackageService.checkPackageNameUnique(bo)) { + return R.fail("新增套餐'" + bo.getPackageName() + "'失败,套餐名称已存在"); + } + return toAjax(tenantPackageService.insertByBo(bo)); + } + + /** + * 修改租户套餐 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:edit") + @Log(title = "租户套餐", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) { + if (!tenantPackageService.checkPackageNameUnique(bo)) { + return R.fail("修改套餐'" + bo.getPackageName() + "'失败,套餐名称已存在"); + } + return toAjax(tenantPackageService.updateByBo(bo)); + } + + /** + * 状态修改 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:edit") + @Log(title = "租户套餐", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysTenantPackageBo bo) { + return toAjax(tenantPackageService.updatePackageStatus(bo)); + } + + /** + * 删除租户套餐 + * + * @param packageIds 主键串 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenantPackage:remove") + @Log(title = "租户套餐", businessType = BusinessType.DELETE) + @DeleteMapping("/{packageIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] packageIds) { + return toAjax(tenantPackageService.deleteWithValidByIds(List.of(packageIds), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java new file mode 100644 index 0000000..9d83736 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java @@ -0,0 +1,71 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.tenant.core.TenantEntity; + +/** + * 字典数据表 sys_dict_data + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_data") +public class SysDictData extends TenantEntity { + + /** + * 字典编码 + */ + @TableId(value = "dict_code") + private Long dictCode; + + /** + * 字典排序 + */ + private Integer dictSort; + + /** + * 字典标签 + */ + private String dictLabel; + + /** + * 字典键值 + */ + private String dictValue; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + private String cssClass; + + /** + * 表格字典样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 备注 + */ + private String remark; + + public boolean getDefault() { + return SystemConstants.YES.equals(this.isDefault); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java new file mode 100644 index 0000000..955af85 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java @@ -0,0 +1,41 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 字典类型表 sys_dict_type + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_type") +public class SysDictType extends TenantEntity { + + /** + * 字典主键 + */ + @TableId(value = "dict_id") + private Long dictId; + + /** + * 字典名称 + */ + private String dictName; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java new file mode 100644 index 0000000..c57dc0a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java @@ -0,0 +1,85 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 系统访问记录表 sys_logininfor + * + * @author Lion Li + */ + +@Data +@TableName("sys_logininfor") +public class SysLogininfor implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "info_id") + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录状态 0成功 1失败 + */ + private String status; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 提示消息 + */ + private String msg; + + /** + * 访问时间 + */ + private Date loginTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java new file mode 100644 index 0000000..bfcc2bc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java @@ -0,0 +1,51 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + + +/** + * 通知公告表 sys_notice + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_notice") +public class SysNotice extends TenantEntity { + + /** + * 公告ID + */ + @TableId(value = "notice_id") + private Long noticeId; + + /** + * 公告标题 + */ + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java new file mode 100644 index 0000000..af88898 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java @@ -0,0 +1,50 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * OSS对象存储对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss") +public class SysOss extends TenantEntity { + + /** + * 对象存储主键 + */ + @TableId(value = "oss_id") + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 服务商 + */ + private String service; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java new file mode 100644 index 0000000..4b67d63 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java @@ -0,0 +1,89 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 对象存储配置对象 sys_oss_config + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_oss_config") +public class SysOssConfig extends BaseEntity { + + /** + * 主键 + */ + @TableId(value = "oss_config_id") + private Long ossConfigId; + + /** + * 配置key + */ + private String configKey; + + /** + * accessKey + */ + private String accessKey; + + /** + * 秘钥 + */ + private String secretKey; + + /** + * 桶名称 + */ + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + private String endpoint; + + /** + * 自定义域名 + */ + private String domain; + + /** + * 是否https(0否 1是) + */ + private String isHttps; + + /** + * 域 + */ + private String region; + + /** + * 是否默认(0=是,1=否) + */ + private String status; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + private String accessPolicy; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/UserTransferDTO.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/UserTransferDTO.java new file mode 100644 index 0000000..f5553af --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/UserTransferDTO.java @@ -0,0 +1,55 @@ +package org.dromara.system.domain; + +import java.io.Serializable; + +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; + + +@Data +@NoArgsConstructor +public class UserTransferDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 源用户ID(扣款方) + */ + @NotNull(message = "源用户ID不能为空") + private Long fromUserId; + + /** + * 目标用户ID(收款方) + */ + @NotNull(message = "目标用户ID不能为空") + private Long toUserId; + + /** + * 转账金额(分) + */ + @NotNull(message = "转账金额不能为空") + @DecimalMin(value = "1", message = "转账金额必须大于0") + private BigDecimal amount; + + /** + * 转账类型:1-balance到freeze 2-freeze到balance + */ + @NotNull(message = "转账类型不能为空") + private Integer transferType; + + /** + * 备注 + */ + private String remark; + + /** + * 业务订单号(用于幂等性控制) + */ + private String orderNo; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java new file mode 100644 index 0000000..e5f5ffa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java @@ -0,0 +1,80 @@ +package org.dromara.system.domain.bo; + +import org.dromara.system.domain.SysClient; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.util.List; + +/** + * 授权管理业务对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysClient.class, reverseConvertGenerate = false) +public class SysClientBo extends BaseEntity { + + /** + * id + */ + @NotNull(message = "id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + @NotBlank(message = "客户端key不能为空", groups = { AddGroup.class, EditGroup.class }) + private String clientKey; + + /** + * 客户端秘钥 + */ + @NotBlank(message = "客户端秘钥不能为空", groups = { AddGroup.class, EditGroup.class }) + private String clientSecret; + + /** + * 授权类型 + */ + @NotNull(message = "授权类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private List grantTypeList; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java new file mode 100644 index 0000000..5f64d6f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java @@ -0,0 +1,76 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysDept; + +/** + * 部门业务对象 sys_dept + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDept.class, reverseConvertGenerate = false) +public class SysDeptBo extends BaseEntity { + + /** + * 部门id + */ + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 部门名称 + */ + @NotBlank(message = "部门名称不能为空") + @Size(min = 0, max = 30, message = "部门名称长度不能超过{max}个字符") + private String deptName; + + /** + * 部门类别编码 + */ + @Size(min = 0, max = 100, message = "部门类别编码长度不能超过{max}个字符") + private String deptCategory; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 负责人 + */ + private Long leader; + + /** + * 联系电话 + */ + @Size(min = 0, max = 11, message = "联系电话长度不能超过{max}个字符") + private String phone; + + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java new file mode 100644 index 0000000..fcc1ac1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java @@ -0,0 +1,50 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysDictType; + +/** + * 字典类型业务对象 sys_dict_type + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDictType.class, reverseConvertGenerate = false) +public class SysDictTypeBo extends BaseEntity { + + /** + * 字典主键 + */ + private Long dictId; + + /** + * 字典名称 + */ + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过{max}个字符") + private String dictName; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过{max}个字符") + @Pattern(regexp = RegexConstants.DICTIONARY_TYPE, message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + private String dictType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java new file mode 100644 index 0000000..cdcc575 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java @@ -0,0 +1,61 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.xss.Xss; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysNotice; + +/** + * 通知公告业务对象 sys_notice + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysNotice.class, reverseConvertGenerate = false) +public class SysNoticeBo extends BaseEntity { + + /** + * 公告ID + */ + private Long noticeId; + + /** + * 公告标题 + */ + @Xss(message = "公告标题不能包含脚本字符") + @NotBlank(message = "公告标题不能为空") + @Size(min = 0, max = 50, message = "公告标题不能超过{max}个字符") + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建人名称 + */ + private String createByName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java new file mode 100644 index 0000000..7cb3104 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java @@ -0,0 +1,49 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysOss; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * OSS对象存储分页查询对象 sys_oss + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysOss.class, reverseConvertGenerate = false) +public class SysOssBo extends BaseEntity { + + /** + * ossId + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 服务商 + */ + private String service; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java new file mode 100644 index 0000000..09805cd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java @@ -0,0 +1,75 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysPost; + +/** + * 岗位信息业务对象 sys_post + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysPost.class, reverseConvertGenerate = false) +public class SysPostBo extends BaseEntity { + + /** + * 岗位ID + */ + private Long postId; + + /** + * 部门id(单部门) + */ + @NotNull(message = "部门id不能为空") + private Long deptId; + + /** + * 归属部门id(部门树) + */ + private Long belongDeptId; + + /** + * 岗位编码 + */ + @NotBlank(message = "岗位编码不能为空") + @Size(min = 0, max = 64, message = "岗位编码长度不能超过{max}个字符") + private String postCode; + + /** + * 岗位名称 + */ + @NotBlank(message = "岗位名称不能为空") + @Size(min = 0, max = 50, message = "岗位名称长度不能超过{max}个字符") + private String postName; + + /** + * 岗位类别编码 + */ + @Size(min = 0, max = 100, message = "类别编码长度不能超过{max}个字符") + private String postCategory; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer postSort; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java new file mode 100644 index 0000000..cede1e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java @@ -0,0 +1,142 @@ +package org.dromara.system.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.tenant.core.TenantEntity; +import org.dromara.system.domain.SysSocial; + +/** + * 社会化关系业务对象 sys_social + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysSocial.class, reverseConvertGenerate = false) +public class SysSocialBo extends TenantEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 认证唯一ID + */ + @NotBlank(message = "认证唯一ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private String authId; + + /** + * 用户来源 + */ + @NotBlank(message = "用户来源不能为空", groups = { AddGroup.class, EditGroup.class }) + private String source; + + /** + * 用户的授权令牌 + */ + @NotBlank(message = "用户的授权令牌不能为空", groups = { AddGroup.class, EditGroup.class }) + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 平台唯一id + */ + private String openId; + + /** + * 用户的 ID + */ + @NotBlank(message = "用户的ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long userId; + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java new file mode 100644 index 0000000..eecbc9f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java @@ -0,0 +1,59 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.system.domain.SysTenantPackage; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMapping; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 租户套餐业务对象 sys_tenant_package + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysTenantPackage.class, reverseConvertGenerate = false) +public class SysTenantPackageBo extends BaseEntity { + + /** + * 租户套餐id + */ + @NotNull(message = "租户套餐id不能为空", groups = { EditGroup.class }) + private Long packageId; + + /** + * 套餐名称 + */ + @NotBlank(message = "套餐名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String packageName; + + /** + * 关联菜单id + */ + @AutoMapping(target = "menuIds", expression = "java(org.dromara.common.core.utils.StringUtils.join(source.getMenuIds(), \",\"))") + private Long[] menuIds; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单树选择项是否关联显示 + */ + private Boolean menuCheckStrictly; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java new file mode 100644 index 0000000..8615fcd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户密码修改bo + */ +@Data +public class SysUserPasswordBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 旧密码 + */ + @NotBlank(message = "旧密码不能为空") + private String oldPassword; + + /** + * 新密码 + */ + @NotBlank(message = "新密码不能为空") + private String newPassword; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java new file mode 100644 index 0000000..46c020b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java @@ -0,0 +1,18 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +/** + * 用户头像信息 + * + * @author Michelle.Chung + */ +@Data +public class AvatarVo { + + /** + * 头像地址 + */ + private String imgUrl; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java new file mode 100644 index 0000000..f827cba --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java @@ -0,0 +1,23 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * 缓存监控列表信息 + * + * @author Michelle.Chung + */ +@Data +public class CacheListInfoVo { + + private Properties info; + + private Long dbSize; + + private List> commandStats; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java new file mode 100644 index 0000000..afe7367 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java @@ -0,0 +1,73 @@ +package org.dromara.system.domain.vo; + +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysNotice; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 通知公告视图对象 sys_notice + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysNotice.class) +public class SysNoticeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 公告ID + */ + private Long noticeId; + + /** + * 公告标题 + */ + private String noticeTitle; + + /** + * 公告类型(1通知 2公告) + */ + private String noticeType; + + /** + * 公告内容 + */ + private String noticeContent; + + /** + * 公告状态(0正常 1关闭) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + private String createByName; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java new file mode 100644 index 0000000..d9eb71d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java @@ -0,0 +1,144 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysOperLog; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 操作日志记录视图对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysOperLog.class) +public class SysOperLogVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @ExcelProperty(value = "日志主键") + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 模块标题 + */ + @ExcelProperty(value = "操作模块") + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + @ExcelProperty(value = "业务类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_oper_type") + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + @ExcelProperty(value = "请求方法") + private String method; + + /** + * 请求方式 + */ + @ExcelProperty(value = "请求方式") + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + @ExcelProperty(value = "操作类别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=其它,1=后台用户,2=手机端用户") + private Integer operatorType; + + /** + * 操作人员 + */ + @ExcelProperty(value = "操作人员") + private String operName; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 请求URL + */ + @ExcelProperty(value = "请求地址") + private String operUrl; + + /** + * 主机地址 + */ + @ExcelProperty(value = "操作地址") + private String operIp; + + /** + * 操作地点 + */ + @ExcelProperty(value = "操作地点") + private String operLocation; + + /** + * 请求参数 + */ + @ExcelProperty(value = "请求参数") + private String operParam; + + /** + * 返回参数 + */ + @ExcelProperty(value = "返回参数") + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private Integer status; + + /** + * 错误消息 + */ + @ExcelProperty(value = "错误消息") + private String errorMsg; + + /** + * 操作时间 + */ + @ExcelProperty(value = "操作时间") + private Date operTime; + + /** + * 消耗时间 + */ + @ExcelProperty(value = "消耗时间") + private Long costTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java new file mode 100644 index 0000000..ffb2c6d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java @@ -0,0 +1,100 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysRole; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 角色信息视图对象 sys_role + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysRole.class) +public class SysRoleVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + @ExcelProperty(value = "角色序号") + private Long roleId; + + /** + * 角色名称 + */ + @ExcelProperty(value = "角色名称") + private String roleName; + + /** + * 角色权限字符串 + */ + @ExcelProperty(value = "角色权限") + private String roleKey; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "角色排序") + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + */ + @ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + @ExcelProperty(value = "菜单树选择项是否关联显示") + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + @ExcelProperty(value = "部门树选择项是否关联显示") + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + @ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 用户是否存在此角色标识 默认不存在 + */ + private boolean flag = false; + + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ID.equals(this.roleId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java new file mode 100644 index 0000000..948dbcc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java @@ -0,0 +1,144 @@ +package org.dromara.system.domain.vo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.system.domain.SysSocial; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 社会化关系视图对象 sys_social + * + * @author thiszhc + */ +@Data +@AutoMapper(target = SysSocial.class) +public class SysSocialVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 的唯一ID + */ + private String authId; + + /** + * 用户来源 + */ + private String source; + + /** + * 用户的授权令牌 + */ + private String accessToken; + + /** + * 用户的授权令牌的有效期,部分平台可能没有 + */ + private int expireIn; + + /** + * 刷新令牌,部分平台可能没有 + */ + private String refreshToken; + + /** + * 用户的 open id + */ + private String openId; + + /** + * 授权的第三方账号 + */ + private String userName; + + /** + * 授权的第三方昵称 + */ + private String nickName; + + /** + * 授权的第三方邮箱 + */ + private String email; + + /** + * 授权的第三方头像地址 + */ + private String avatar; + + + /** + * 平台的授权信息,部分平台可能没有 + */ + private String accessCode; + + /** + * 用户的 unionid + */ + private String unionId; + + /** + * 授予的权限,部分平台可能没有 + */ + private String scope; + + /** + * 个别平台的授权信息,部分平台可能没有 + */ + private String tokenType; + + /** + * id token,部分平台可能没有 + */ + private String idToken; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macAlgorithm; + + /** + * 小米平台用户的附带属性,部分平台可能没有 + */ + private String macKey; + + /** + * 用户的授权code,部分平台可能没有 + */ + private String code; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthToken; + + /** + * Twitter平台用户的附带属性,部分平台可能没有 + */ + private String oauthTokenSecret; + + /** + * 创建时间 + */ + private Date createTime; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java new file mode 100644 index 0000000..070334b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java @@ -0,0 +1,66 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.system.domain.SysTenantPackage; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 租户套餐视图对象 sys_tenant_package + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysTenantPackage.class) +public class SysTenantPackageVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户套餐id + */ + @ExcelProperty(value = "租户套餐id") + private Long packageId; + + /** + * 套餐名称 + */ + @ExcelProperty(value = "套餐名称") + private String packageName; + + /** + * 关联菜单id + */ + @ExcelProperty(value = "关联菜单id") + private String menuIds; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 菜单树选择项是否关联显示 + */ + @ExcelProperty(value = "菜单树选择项是否关联显示") + private Boolean menuCheckStrictly; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java new file mode 100644 index 0000000..e41355d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java @@ -0,0 +1,40 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 用户信息 + * + * @author Michelle.Chung + */ +@Data +public class SysUserInfoVo { + + /** + * 用户信息 + */ + private SysUserVo user; + + /** + * 角色ID列表 + */ + private List roleIds; + + /** + * 角色列表 + */ + private List roles; + + /** + * 岗位ID列表 + */ + private List postIds; + + /** + * 岗位列表 + */ + private List posts; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java new file mode 100644 index 0000000..48fa92a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java @@ -0,0 +1,30 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.Set; + +/** + * 登录用户信息 + * + * @author Michelle.Chung + */ +@Data +public class UserInfoVo { + + /** + * 用户基本信息 + */ + private SysUserVo user; + + /** + * 菜单权限 + */ + private Set permissions; + + /** + * 角色权限 + */ + private Set roles; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java new file mode 100644 index 0000000..0eaaee8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysConfig; +import org.dromara.system.domain.vo.SysConfigVo; + +/** + * 参数配置 数据层 + * + * @author Lion Li + */ +public interface SysConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java new file mode 100644 index 0000000..b69624c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java @@ -0,0 +1,78 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.vo.SysDeptVo; + +import java.util.List; + +/** + * 部门管理 数据层 + * + * @author Lion Li + */ +public interface SysDeptMapper extends BaseMapperPlus { + + /** + * 查询部门管理数据 + * + * @param queryWrapper 查询条件 + * @return 部门信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id") + }) + List selectDeptList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 分页查询部门管理数据 + * + * @param queryWrapper 查询条件 + * @return 部门信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + }) + Page selectPageDeptList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 统计指定部门ID的部门数量 + * + * @param deptId 部门ID + * @return 该部门ID的部门数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id") + }) + long countDeptById(Long deptId); + + /** + * 根据父部门ID查询其所有子部门的列表 + * + * @param parentId 父部门ID + * @return 包含子部门的列表 + */ + default List selectListByParentId(Long parentId) { + return this.selectList(new LambdaQueryWrapper() + .select(SysDept::getDeptId) + .apply(DataBaseHelper.findInSet(parentId, "ancestors"))); + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @param deptCheckStrictly 部门树选择项是否关联显示 + * @return 选中部门列表 + */ + List selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java new file mode 100644 index 0000000..85edd1d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysLogininfor; +import org.dromara.system.domain.vo.SysLogininforVo; + +/** + * 系统访问日志情况信息 数据层 + * + * @author Lion Li + */ +public interface SysLogininforMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java new file mode 100644 index 0000000..dbd3440 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java @@ -0,0 +1,76 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.vo.SysRoleVo; + +import java.util.List; + +/** + * 角色表 数据层 + * + * @author Lion Li + */ +public interface SysRoleMapper extends BaseMapperPlus { + + /** + * 分页查询角色列表 + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 包含角色信息的分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "r.create_by") + }) + Page selectPageRoleList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询角色数据 + * + * @param queryWrapper 查询条件 + * @return 角色数据集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "r.create_by") + }) + List selectRoleList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据角色ID查询角色信息 + * + * @param roleId 角色ID + * @return 对应的角色信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "r.create_by") + }) + SysRoleVo selectRoleById(Long roleId); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolePermissionByUserId(Long userId); + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesByUserId(Long userId); + + SysRole selectRoleByRoleKey(String roleKey); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java new file mode 100644 index 0000000..b942061 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysSocial; +import org.dromara.system.domain.vo.SysSocialVo; + +/** + * 社会化关系Mapper接口 + * + * @author thiszhc + */ +public interface SysSocialMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java new file mode 100644 index 0000000..2446733 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java @@ -0,0 +1,218 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.*; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysUserExportVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.domain.vo.UserInfoVo; + +import java.util.List; + +/** + * 用户表 数据层 + * + * @author Lion Li + */ +@Mapper +public interface SysUserMapper extends BaseMapperPlus { + + /** + * 分页查询用户列表,并进行数据权限控制 + * + * @param page 分页参数 + * @param queryWrapper 查询条件 + * @return 分页的用户信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "u.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectPageUserList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + + List selectUserWarehouseNameList(); + /** + * 查询用户列表,并进行数据权限控制 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + List selectUserList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询用户列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + List selectUserExportList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询已配用户角色列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectAllocatedList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param queryWrapper 查询条件 + * @return 用户信息集合信息 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "d.dept_id"), + @DataColumn(key = "userName", value = "u.user_id") + }) + Page selectUnallocatedList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据用户ID统计用户数量 + * + * @param userId 用户ID + * @return 用户数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + long countUserById(Long userId); + + /** + * 根据条件更新用户数据 + * + * @param user 要更新的用户实体 + * @param updateWrapper 更新条件封装器 + * @return 更新操作影响的行数 + */ + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper updateWrapper); + + /** + * 根据用户ID更新用户数据 + * + * @param user 要更新的用户实体 + * @return 更新操作影响的行数 + */ + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int updateById(@Param(Constants.ENTITY) SysUser user); + + + @Select("select * from sys_user where open_id = #{openid} and phonenumber = #{phoneNumber}") + SysUserVo selectVoListByOpenId(String openid,String phoneNumber); + + @Update("UPDATE sys_user SET open_id = #{openid} WHERE phonenumber = #{phoneNumber}") + boolean updateOpenIdByPhoneNumber(String phoneNumber, String openid); + + @Select("select * from sys_user where phonenumber = #{phoneNumber}") + SysUserVo selectListByPhonenumber(String phoneNumber); + + @Update("UPDATE sys_user SET open_id = #{openid} WHERE phonenumber = #{phonenumber}") + void insertUserOpenId(@Param("openid") String openid, @Param("phonenumber") String phonenumber); + + @Update("UPDATE sys_user SET balance = #{balance} WHERE user_id = #{userId}") + void editUserBalance(@Param("balance") String balance, @Param("userId") String userId); + + @Select("select user_id from sys_user where user_name=#{username}") + Long selectName(String username); + + @Insert("insert into sys_user_role(user_id,role_id) values(#{id},#{role})") + void insertRole(Long id, Long role); + + @Select("select user_name from sys_user") + List selectUserName(); + + String selectPhoneNumber(String phoneNumber); + + String CheckUserName(String username); + + SysUser selectUserByUserName(String userName); + + Long selectUserIdByUserName(String userName); + + SysUserVo selectUserByUserId(Long userId); + + SysUser queryUserByUserId(Long userId); + + SysUser selectUserById(Long userId); + + + + /** + * 从余额转到冻结资金 + * @param fromUserId 转出用户ID + * @param toUserId 转入用户ID + * @param amount 金额(分) + * @return 影响行数 + */ + int transferBalanceToFreeze(@Param("fromUserId") Long fromUserId, + @Param("toUserId") Long toUserId, + @Param("amount") Long amount); + + /** + * 从冻结资金转到余额 + * @param fromUserId 转出用户ID + * @param toUserId 转入用户ID + * @param amount 金额(分) + * @return 影响行数 + */ + int transferFreezeToBalance(@Param("fromUserId") Long fromUserId, + @Param("toUserId") Long toUserId, + @Param("amount") Long amount); + + /** + * 更新用户余额 + * @param userId 用户ID + * @param balance 新余额(分) + * @return 影响行数 + */ + int updateBalance(@Param("userId") Long userId,@Param("balance") Long balance); + + /** + * 检查用户余额是否足够 + * @param userId 用户ID + * @param amount 金额(分) + * @return 是否足够 + */ + int checkBalanceSufficient(@Param("userId") Long userId, + @Param("amount") Long amount); + + /** + * 检查用户冻结资金是否足够 + * @param userId 用户ID + * @param amount 金额(分) + * @return 是否足够 + */ + int checkFreezeSufficient(@Param("userId") Long userId, + @Param("amount") Long amount); + + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java new file mode 100644 index 0000000..07c1371 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUserPost; + +/** + * 用户与岗位关联表 数据层 + * + * @author Lion Li + */ +public interface SysUserPostMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java new file mode 100644 index 0000000..27dad7d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java @@ -0,0 +1,28 @@ +package org.dromara.system.runner; + +import org.dromara.system.service.ISysOssConfigService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * 初始化 system 模块对应业务数据 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class SystemApplicationRunner implements ApplicationRunner { + + private final ISysOssConfigService ossConfigService; + + @Override + public void run(ApplicationArguments args) throws Exception { + ossConfigService.init(); + log.info("初始化OSS配置成功"); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java new file mode 100644 index 0000000..0e697db --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java @@ -0,0 +1,76 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author Lion Li + */ +public interface ISysDictDataService { + + + TableDataInfo selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery); + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + List selectDictDataList(SysDictDataBo dictData); + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + String selectDictLabel(String dictType, String dictValue); + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + SysDictDataVo selectDictDataById(Long dictCode); + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + void deleteDictDataByIds(Long[] dictCodes); + + /** + * 新增保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + List insertDictData(SysDictDataBo bo); + + /** + * 修改保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + List updateDictData(SysDictDataBo bo); + + /** + * 校验字典键值是否唯一 + * + * @param dict 字典数据 + * @return 结果 + */ + boolean checkDictDataUnique(SysDictDataBo dict); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java new file mode 100644 index 0000000..057c068 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java @@ -0,0 +1,80 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssVo; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +/** + * 文件上传 服务层 + * + * @author Lion Li + */ +public interface ISysOssService { + + /** + * 查询OSS对象存储列表 + * + * @param sysOss OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ + TableDataInfo queryPageList(SysOssBo sysOss, PageQuery pageQuery); + + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ + List listByIds(Collection ossIds); + + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ + SysOssVo getById(Long ossId); + + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssVo upload(MultipartFile file); + + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + SysOssVo upload(File file); + + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + * @param response HttpServletResponse对象,用于设置响应头和向客户端发送文件内容 + */ + void download(Long ossId, HttpServletResponse response) throws IOException; + + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java new file mode 100644 index 0000000..d060b68 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java @@ -0,0 +1,62 @@ +package org.dromara.system.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysTenantPackageBo; +import org.dromara.system.domain.vo.SysTenantPackageVo; + +import java.util.Collection; +import java.util.List; + +/** + * 租户套餐Service接口 + * + * @author Michelle.Chung + */ +public interface ISysTenantPackageService { + + /** + * 查询租户套餐 + */ + SysTenantPackageVo queryById(Long packageId); + + /** + * 查询租户套餐列表 + */ + TableDataInfo queryPageList(SysTenantPackageBo bo, PageQuery pageQuery); + + /** + * 查询租户套餐已启用列表 + */ + List selectList(); + + /** + * 查询租户套餐列表 + */ + List queryList(SysTenantPackageBo bo); + + /** + * 新增租户套餐 + */ + Boolean insertByBo(SysTenantPackageBo bo); + + /** + * 修改租户套餐 + */ + Boolean updateByBo(SysTenantPackageBo bo); + + /** + * 校验套餐名称是否唯一 + */ + boolean checkPackageNameUnique(SysTenantPackageBo bo); + + /** + * 修改套餐状态 + */ + int updatePackageStatus(SysTenantPackageBo bo); + + /** + * 校验并批量删除租户套餐信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java new file mode 100644 index 0000000..ca062be --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,386 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.dto.DeptDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DeptService; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysDeptService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cache.annotation.Caching; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 部门管理 服务实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDeptServiceImpl implements ISysDeptService, DeptService { + + private final SysDeptMapper baseMapper; + private final SysRoleMapper roleMapper; + private final SysUserMapper userMapper; + + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + @Override + public List selectDeptList(SysDeptBo dept) { + LambdaQueryWrapper lqw = buildQueryWrapper(dept); + return baseMapper.selectDeptList(lqw); + } + + /** + * 查询部门树结构信息 + * + * @param bo 部门信息 + * @return 部门树信息集合 + */ + @Override + public List> selectDeptTreeList(SysDeptBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List depts = baseMapper.selectDeptList(lqw); + return buildDeptTreeSelect(depts); + } + + private LambdaQueryWrapper buildQueryWrapper(SysDeptBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysDept::getDelFlag, SystemConstants.NORMAL); + lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId()); + lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId()); + lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName()); + lqw.like(StringUtils.isNotBlank(bo.getDeptCategory()), SysDept::getDeptCategory, bo.getDeptCategory()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus()); + lqw.orderByAsc(SysDept::getAncestors); + lqw.orderByAsc(SysDept::getParentId); + lqw.orderByAsc(SysDept::getOrderNum); + lqw.orderByAsc(SysDept::getDeptId); + return lqw; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildDeptTreeSelect(List depts) { + if (CollUtil.isEmpty(depts)) { + return CollUtil.newArrayList(); + } + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (SysDeptVo d : depts) { + Long parentId = d.getParentId(); + SysDeptVo sysDeptVo = StreamUtils.findFirst(depts, it -> it.getDeptId().longValue() == parentId); + if (ObjectUtil.isNull(sysDeptVo)) { + List> trees = TreeBuildUtils.build(depts, parentId, (dept, tree) -> + tree.setId(dept.getDeptId()) + .setParentId(dept.getParentId()) + .setName(dept.getDeptName()) + .setWeight(dept.getOrderNum()) + .putExtra("disabled", SystemConstants.DISABLE.equals(dept.getStatus()))); + Tree tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId()); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + @Override + public List selectDeptListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + return baseMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly()); + } + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DEPT, key = "#deptId") + @Override + public SysDeptVo selectDeptById(Long deptId) { + SysDeptVo dept = baseMapper.selectVoById(deptId); + if (ObjectUtil.isNull(dept)) { + return null; + } + SysDeptVo parentDept = baseMapper.selectVoOne(new LambdaQueryWrapper() + .select(SysDept::getDeptName).eq(SysDept::getDeptId, dept.getParentId())); + dept.setParentName(ObjectUtils.notNullGetter(parentDept, SysDeptVo::getDeptName)); + return dept; + } + + @Override + public List selectDeptByIds(List deptIds) { + return baseMapper.selectDeptList(new LambdaQueryWrapper() + .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getLeader) + .eq(SysDept::getStatus, SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(deptIds), SysDept::getDeptId, deptIds)); + } + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + @Override + public String selectDeptNameByIds(String deptIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(deptIds, Convert::toLong)) { + SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(id); + if (ObjectUtil.isNotNull(vo)) { + list.add(vo.getDeptName()); + } + } + return String.join(StringUtils.SEPARATOR, list); + } + + /** + * 根据部门ID查询部门负责人 + * + * @param deptId 部门ID,用于指定需要查询的部门 + * @return 返回该部门的负责人ID + */ + @Override + public Long selectDeptLeaderById(Long deptId) { + SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(deptId); + return vo.getLeader(); + } + + /** + * 查询部门 + * + * @return 部门列表 + */ + @Override + public List selectDeptsByList() { + List list = baseMapper.selectDeptList(new LambdaQueryWrapper() + .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId) + .eq(SysDept::getStatus, SystemConstants.NORMAL)); + return BeanUtil.copyToList(list, DeptDTO.class); + } + + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + @Override + public long selectNormalChildrenDeptById(Long deptId) { + return baseMapper.selectCount(new LambdaQueryWrapper() + .eq(SysDept::getStatus, SystemConstants.NORMAL) + .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); + } + + /** + * 是否存在子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + @Override + public boolean hasChildByDeptId(Long deptId) { + return baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDept::getParentId, deptId)); + } + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkDeptExistUser(Long deptId) { + return userMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getDeptId, deptId)); + } + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + @Override + public boolean checkDeptNameUnique(SysDeptBo dept) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDept::getDeptName, dept.getDeptName()) + .eq(SysDept::getParentId, dept.getParentId()) + .ne(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId())); + return !exist; + } + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + @Override + public void checkDeptDataScope(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (baseMapper.countDeptById(deptId) == 0) { + throw new ServiceException("没有权限访问部门数据!"); + } + } + + /** + * 新增保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) + @Override + public int insertDept(SysDeptBo bo) { + SysDept info = baseMapper.selectById(bo.getParentId()); + // 如果父节点不为正常状态,则不允许新增子节点 + if (!SystemConstants.NORMAL.equals(info.getStatus())) { + throw new ServiceException("部门停用,不允许新增"); + } + SysDept dept = MapstructUtils.convert(bo, SysDept.class); + dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId()); + return baseMapper.insert(dept); + } + + /** + * 修改保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + @Caching(evict = { + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#bo.deptId"), + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) + }) + @Override + @Transactional(rollbackFor = Exception.class) + public int updateDept(SysDeptBo bo) { + SysDept dept = MapstructUtils.convert(bo, SysDept.class); + SysDept oldDept = baseMapper.selectById(dept.getDeptId()); + if (ObjectUtil.isNull(oldDept)) { + throw new ServiceException("部门不存在,无法修改"); + } + if (!oldDept.getParentId().equals(dept.getParentId())) { + // 如果是新父部门 则校验是否具有新父部门权限 避免越权 + this.checkDeptDataScope(dept.getParentId()); + SysDept newParentDept = baseMapper.selectById(dept.getParentId()); + if (ObjectUtil.isNotNull(newParentDept)) { + String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId(); + String oldAncestors = oldDept.getAncestors(); + dept.setAncestors(newAncestors); + updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors); + } + } else { + dept.setAncestors(oldDept.getAncestors()); + } + int result = baseMapper.updateById(dept); + if (SystemConstants.NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors()) + && !StringUtils.equals(SystemConstants.NORMAL, dept.getAncestors())) { + // 如果该部门是启用状态,则启用该部门的所有上级部门 + updateParentDeptStatusNormal(dept); + } + return result; + } + + /** + * 修改该部门的父级部门状态 + * + * @param dept 当前部门 + */ + private void updateParentDeptStatusNormal(SysDept dept) { + String ancestors = dept.getAncestors(); + Long[] deptIds = Convert.toLongArray(ancestors); + baseMapper.update(null, new LambdaUpdateWrapper() + .set(SysDept::getStatus, SystemConstants.NORMAL) + .in(SysDept::getDeptId, Arrays.asList(deptIds))); + } + + /** + * 修改子元素关系 + * + * @param deptId 被修改的部门ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + private void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) { + List children = baseMapper.selectList(new LambdaQueryWrapper() + .apply(DataBaseHelper.findInSet(deptId, "ancestors"))); + List list = new ArrayList<>(); + for (SysDept child : children) { + SysDept dept = new SysDept(); + dept.setDeptId(child.getDeptId()); + dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + list.add(dept); + } + if (CollUtil.isNotEmpty(list)) { + if (baseMapper.updateBatchById(list)) { + list.forEach(dept -> CacheUtils.evict(CacheNames.SYS_DEPT, dept.getDeptId())); + } + } + } + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + @Caching(evict = { + @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId"), + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId") + }) + @Override + public int deleteDeptById(Long deptId) { + return baseMapper.deleteById(deptId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java new file mode 100644 index 0000000..19a3ff5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java @@ -0,0 +1,124 @@ +package org.dromara.system.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysNotice; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysNoticeMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysNoticeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +/** + * 公告 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysNoticeServiceImpl implements ISysNoticeService { + + private final SysNoticeMapper baseMapper; + private final SysUserMapper userMapper; + + @Override + public TableDataInfo selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(notice); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + @Override + public SysNoticeVo selectNoticeById(Long noticeId) { + return baseMapper.selectVoById(noticeId); + } + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + @Override + public List selectNoticeList(SysNoticeBo notice) { + LambdaQueryWrapper lqw = buildQueryWrapper(notice); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysNoticeBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getNoticeTitle()), SysNotice::getNoticeTitle, bo.getNoticeTitle()); + lqw.eq(StringUtils.isNotBlank(bo.getNoticeType()), SysNotice::getNoticeType, bo.getNoticeType()); + if (StringUtils.isNotBlank(bo.getCreateByName())) { + SysUserVo sysUser = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, bo.getCreateByName())); + lqw.eq(SysNotice::getCreateBy, ObjectUtils.notNullGetter(sysUser, SysUserVo::getUserId)); + } + lqw.orderByAsc(SysNotice::getNoticeId); + return lqw; + } + + /** + * 新增公告 + * + * @param bo 公告信息 + * @return 结果 + */ + @Override + public int insertNotice(SysNoticeBo bo) { + SysNotice notice = MapstructUtils.convert(bo, SysNotice.class); + return baseMapper.insert(notice); + } + + /** + * 修改公告 + * + * @param bo 公告信息 + * @return 结果 + */ + @Override + public int updateNotice(SysNoticeBo bo) { + SysNotice notice = MapstructUtils.convert(bo, SysNotice.class); + return baseMapper.updateById(notice); + } + + /** + * 删除公告对象 + * + * @param noticeId 公告ID + * @return 结果 + */ + @Override + public int deleteNoticeById(Long noticeId) { + return baseMapper.deleteById(noticeId); + } + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + @Override + public int deleteNoticeByIds(Long[] noticeIds) { + return baseMapper.deleteByIds(Arrays.asList(noticeIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java new file mode 100644 index 0000000..27c2f32 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java @@ -0,0 +1,134 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ArrayUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysOperLog; +import org.dromara.system.domain.bo.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; +import org.dromara.system.mapper.SysOperLogMapper; +import org.dromara.system.service.ISysOperLogService; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 操作日志 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysOperLogServiceImpl implements ISysOperLogService { + + private final SysOperLogMapper baseMapper; + + /** + * 操作日志记录 + * + * @param operLogEvent 操作日志事件 + */ + @Async + @EventListener + public void recordOper(OperLogEvent operLogEvent) { + SysOperLogBo operLog = MapstructUtils.convert(operLogEvent, SysOperLogBo.class); + // 远程查询操作地点 + operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); + insertOperlog(operLog); + } + + @Override + public TableDataInfo selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(operLog); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + lqw.orderByDesc(SysOperLog::getOperId); + } + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + private LambdaQueryWrapper buildQueryWrapper(SysOperLogBo operLog) { + Map params = operLog.getParams(); + return new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp()) + .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()) + .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, + SysOperLog::getBusinessType, operLog.getBusinessType()) + .func(f -> { + if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) { + f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes())); + } + }) + .eq(operLog.getStatus() != null, + SysOperLog::getStatus, operLog.getStatus()) + .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime")); + } + + /** + * 新增操作日志 + * + * @param bo 操作日志对象 + */ + @Override + public void insertOperlog(SysOperLogBo bo) { + SysOperLog operLog = MapstructUtils.convert(bo, SysOperLog.class); + operLog.setOperTime(new Date()); + baseMapper.insert(operLog); + } + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + @Override + public List selectOperLogList(SysOperLogBo operLog) { + LambdaQueryWrapper lqw = buildQueryWrapper(operLog); + return baseMapper.selectVoList(lqw.orderByDesc(SysOperLog::getOperId)); + } + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + @Override + public int deleteOperLogByIds(Long[] operIds) { + return baseMapper.deleteByIds(Arrays.asList(operIds)); + } + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + @Override + public SysOperLogVo selectOperLogById(Long operId) { + return baseMapper.selectVoById(operId); + } + + /** + * 清空操作日志 + */ + @Override + public void cleanOperLog() { + baseMapper.delete(new LambdaQueryWrapper<>()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java new file mode 100644 index 0000000..9852821 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java @@ -0,0 +1,61 @@ +package org.dromara.system.service.impl; + +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.service.ISysMenuService; +import org.dromara.system.service.ISysPermissionService; +import org.dromara.system.service.ISysRoleService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.HashSet; +import java.util.Set; + +/** + * 用户权限处理 + * + * @author ruoyi + */ +@RequiredArgsConstructor +@Service +public class SysPermissionServiceImpl implements ISysPermissionService { + + private final ISysRoleService roleService; + private final ISysMenuService menuService; + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + @Override + public Set getRolePermission(Long userId) { + Set roles = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + roles.add(TenantConstants.SUPER_ADMIN_ROLE_KEY); + } else { + roles.addAll(roleService.selectRolePermissionByUserId(userId)); + } + return roles; + } + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + @Override + public Set getMenuPermission(Long userId) { + Set perms = new HashSet<>(); + // 管理员拥有所有权限 + if (LoginHelper.isSuperAdmin(userId)) { + perms.add("*:*:*"); + } else { + perms.addAll(menuService.selectMenuPermsByUserId(userId)); + } + return perms; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java new file mode 100644 index 0000000..0a2e485 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,552 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.RoleService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleDept; +import org.dromara.system.domain.SysRoleMenu; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.mapper.SysRoleDeptMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysRoleMenuMapper; +import org.dromara.system.mapper.SysUserRoleMapper; +import org.dromara.system.service.ISysRoleService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 角色 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysRoleServiceImpl implements ISysRoleService, RoleService { + + private final SysRoleMapper baseMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysRoleDeptMapper roleDeptMapper; + + @Override + public TableDataInfo selectPageRoleList(SysRoleBo role, PageQuery pageQuery) { + Page page = baseMapper.selectPageRoleList(pageQuery.build(), this.buildQueryWrapper(role)); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + @Override + public List selectRoleList(SysRoleBo role) { + return baseMapper.selectRoleList(this.buildQueryWrapper(role)); + } + + private Wrapper buildQueryWrapper(SysRoleBo bo) { + Map params = bo.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("r.del_flag", SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(bo.getRoleId()), "r.role_id", bo.getRoleId()) + .like(StringUtils.isNotBlank(bo.getRoleName()), "r.role_name", bo.getRoleName()) + .eq(StringUtils.isNotBlank(bo.getStatus()), "r.status", bo.getStatus()) + .like(StringUtils.isNotBlank(bo.getRoleKey()), "r.role_key", bo.getRoleKey()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "r.create_time", params.get("beginTime"), params.get("endTime")) + .orderByAsc("r.role_sort").orderByAsc("r.create_time"); + return wrapper; + } + + /** + * 根据用户ID查询角色 + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesByUserId(Long userId) { + return baseMapper.selectRolesByUserId(userId); + } + + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + @Override + public List selectRolesAuthByUserId(Long userId) { + List userRoles = baseMapper.selectRolesByUserId(userId); + List roles = selectRoleAll(); + // 使用HashSet提高查找效率 + Set userRoleIds = StreamUtils.toSet(userRoles, SysRoleVo::getRoleId); + for (SysRoleVo role : roles) { + if (userRoleIds.contains(role.getRoleId())) { + role.setFlag(true); + } + } + return roles; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectRolePermissionByUserId(Long userId) { + List perms = baseMapper.selectRolesByUserId(userId); + Set permsSet = new HashSet<>(); + for (SysRoleVo perm : perms) { + if (ObjectUtil.isNotNull(perm)) { + permsSet.addAll(StringUtils.splitList(perm.getRoleKey().trim())); + } + } + return permsSet; + } + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + @Override + public List selectRoleAll() { + return this.selectRoleList(new SysRoleBo()); + } + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + @Override + public List selectRoleListByUserId(Long userId) { + List list = baseMapper.selectRolesByUserId(userId); + return StreamUtils.toList(list, SysRoleVo::getRoleId); + } + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + @Override + public SysRoleVo selectRoleById(Long roleId) { + return baseMapper.selectRoleById(roleId); + } + + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + @Override + public List selectRoleByIds(List roleIds) { + return baseMapper.selectRoleList(new QueryWrapper() + .eq("r.status", SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(roleIds), "r.role_id", roleIds)); + } + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleNameUnique(SysRoleBo role) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysRole::getRoleName, role.getRoleName()) + .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId())); + return !exist; + } + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + @Override + public boolean checkRoleKeyUnique(SysRoleBo role) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysRole::getRoleKey, role.getRoleKey()) + .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId())); + return !exist; + } + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + @Override + public void checkRoleAllowed(SysRoleBo role) { + if (ObjectUtil.isNotNull(role.getRoleId()) && LoginHelper.isSuperAdmin(role.getRoleId())) { + throw new ServiceException("不允许操作超级管理员角色"); + } + String[] keys = new String[]{TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.TENANT_ADMIN_ROLE_KEY}; + // 新增不允许使用 管理员标识符 + if (ObjectUtil.isNull(role.getRoleId()) + && StringUtils.equalsAny(role.getRoleKey(), keys)) { + throw new ServiceException("不允许使用系统内置管理员角色标识符!"); + } + // 修改不允许修改 管理员标识符 + if (ObjectUtil.isNotNull(role.getRoleId())) { + SysRole sysRole = baseMapper.selectById(role.getRoleId()); + // 如果标识符不相等 判断为修改了管理员标识符 + if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) { + if (StringUtils.equalsAny(sysRole.getRoleKey(), keys)) { + throw new ServiceException("不允许修改系统内置管理员角色标识符!"); + } else if (StringUtils.equalsAny(role.getRoleKey(), keys)) { + throw new ServiceException("不允许使用系统内置管理员角色标识符!"); + } + } + } + } + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + @Override + public void checkRoleDataScope(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + List roles = this.selectRoleList(new SysRoleBo(roleId)); + if (CollUtil.isEmpty(roles)) { + throw new ServiceException("没有权限访问角色数据!"); + } + + } + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + @Override + public long countUserRoleByRoleId(Long roleId) { + return userRoleMapper.selectCount(new LambdaQueryWrapper().eq(SysUserRole::getRoleId, roleId)); + } + + /** + * 新增保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertRole(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + // 新增角色信息 + baseMapper.insert(role); + bo.setRoleId(role.getRoleId()); + return insertRoleMenu(bo); + } + + /** + * 修改保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateRole(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + + if (SystemConstants.DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } + // 修改角色信息 + baseMapper.updateById(role); + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, role.getRoleId())); + return insertRoleMenu(bo); + } + + /** + * 修改角色状态 + * + * @param roleId 角色ID + * @param status 角色状态 + * @return 结果 + */ + @Override + public int updateRoleStatus(Long roleId, String status) { + if (SystemConstants.DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException("角色已分配,不能禁用!"); + } + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysRole::getStatus, status) + .eq(SysRole::getRoleId, roleId)); + } + + /** + * 修改数据权限信息 + * + * @param bo 角色信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#bo.roleId") + @Override + @Transactional(rollbackFor = Exception.class) + public int authDataScope(SysRoleBo bo) { + SysRole role = MapstructUtils.convert(bo, SysRole.class); + // 修改角色信息 + baseMapper.updateById(role); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().eq(SysRoleDept::getRoleId, role.getRoleId())); + // 新增角色和部门信息(数据权限) + return insertRoleDept(bo); + } + + /** + * 新增角色菜单信息 + * + * @param role 角色对象 + */ + private int insertRoleMenu(SysRoleBo role) { + int rows = 1; + // 新增用户与角色管理 + List list = new ArrayList<>(); + for (Long menuId : role.getMenuIds()) { + SysRoleMenu rm = new SysRoleMenu(); + rm.setRoleId(role.getRoleId()); + rm.setMenuId(menuId); + list.add(rm); + } + if (list.size() > 0) { + rows = roleMenuMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + + /** + * 新增角色部门信息(数据权限) + * + * @param role 角色对象 + */ + private int insertRoleDept(SysRoleBo role) { + int rows = 1; + // 新增角色与部门(数据权限)管理 + List list = new ArrayList<>(); + for (Long deptId : role.getDeptIds()) { + SysRoleDept rd = new SysRoleDept(); + rd.setRoleId(role.getRoleId()); + rd.setDeptId(deptId); + list.add(rd); + } + if (list.size() > 0) { + rows = roleDeptMapper.insertBatch(list) ? list.size() : 0; + } + return rows; + } + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId") + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleById(Long roleId) { + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, roleId)); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().eq(SysRoleDept::getRoleId, roleId)); + return baseMapper.deleteById(roleId); + } + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_ROLE_CUSTOM, allEntries = true) + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteRoleByIds(Long[] roleIds) { + for (Long roleId : roleIds) { + SysRole role = baseMapper.selectById(roleId); + checkRoleAllowed(BeanUtil.toBean(role, SysRoleBo.class)); + checkRoleDataScope(roleId); + if (countUserRoleByRoleId(roleId) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除!", role.getRoleName())); + } + } + List ids = Arrays.asList(roleIds); + // 删除角色与菜单关联 + roleMenuMapper.delete(new LambdaQueryWrapper().in(SysRoleMenu::getRoleId, ids)); + // 删除角色与部门关联 + roleDeptMapper.delete(new LambdaQueryWrapper().in(SysRoleDept::getRoleId, ids)); + return baseMapper.deleteByIds(ids); + } + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + @Override + public int deleteAuthUser(SysUserRole userRole) { + int rows = userRoleMapper.delete(new LambdaQueryWrapper() + .eq(SysUserRole::getRoleId, userRole.getRoleId()) + .eq(SysUserRole::getUserId, userRole.getUserId())); + if (rows > 0) { + cleanOnlineUser(List.of(userRole.getUserId())); + } + return rows; + } + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + @Override + public int deleteAuthUsers(Long roleId, Long[] userIds) { + List ids = List.of(userIds); + int rows = userRoleMapper.delete(new LambdaQueryWrapper() + .eq(SysUserRole::getRoleId, roleId) + .in(SysUserRole::getUserId, ids)); + if (rows > 0) { + cleanOnlineUser(ids); + } + return rows; + } + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要授权的用户数据ID + * @return 结果 + */ + @Override + public int insertAuthUsers(Long roleId, Long[] userIds) { + // 新增用户与角色管理 + int rows = 1; + List ids = List.of(userIds); + List list = StreamUtils.toList(ids, userId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + if (CollUtil.isNotEmpty(list)) { + rows = userRoleMapper.insertBatch(list) ? list.size() : 0; + } + if (rows > 0) { + cleanOnlineUser(ids); + } + return rows; + } + + @Override + public void cleanOnlineUserByRole(Long roleId) { + // 如果角色未绑定用户 直接返回 + Long num = userRoleMapper.selectCount(new LambdaQueryWrapper().eq(SysUserRole::getRoleId, roleId)); + if (num == 0) { + return; + } + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (ObjectUtil.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoles())) { + return; + } + if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } + + @Override + public void cleanOnlineUser(List userIds) { + List keys = StpUtil.searchTokenValue("", 0, -1, false); + if (CollUtil.isEmpty(keys)) { + return; + } + // 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作 + keys.parallelStream().forEach(key -> { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + return; + } + LoginUser loginUser = LoginHelper.getLoginUser(token); + if (ObjectUtil.isNull(loginUser)) { + return; + } + if (userIds.contains(loginUser.getUserId())) { + try { + StpUtil.logoutByTokenValue(token); + } catch (NotLoginException ignored) { + } + } + }); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java new file mode 100644 index 0000000..9c54cbc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java @@ -0,0 +1,112 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.domain.SysSocial; +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.mapper.SysSocialMapper; +import org.dromara.system.service.ISysSocialService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 社会化关系Service业务层处理 + * + * @author thiszhc + * @date 2023-06-12 + */ +@RequiredArgsConstructor +@Service +public class SysSocialServiceImpl implements ISysSocialService { + + private final SysSocialMapper baseMapper; + + + /** + * 查询社会化关系 + */ + @Override + public SysSocialVo queryById(String id) { + return baseMapper.selectVoById(id); + } + + /** + * 授权列表 + */ + @Override + public List queryList(SysSocialBo bo) { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .eq(ObjectUtil.isNotNull(bo.getUserId()), SysSocial::getUserId, bo.getUserId()) + .eq(StringUtils.isNotBlank(bo.getAuthId()), SysSocial::getAuthId, bo.getAuthId()) + .eq(StringUtils.isNotBlank(bo.getSource()), SysSocial::getSource, bo.getSource()); + return baseMapper.selectVoList(lqw); + } + + @Override + public List queryListByUserId(Long userId) { + return baseMapper.selectVoList(new LambdaQueryWrapper().eq(SysSocial::getUserId, userId)); + } + + + /** + * 新增社会化关系 + */ + @Override + public Boolean insertByBo(SysSocialBo bo) { + SysSocial add = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + if (add != null) { + bo.setId(add.getId()); + } else { + return false; + } + } + return flag; + } + + /** + * 更新社会化关系 + */ + @Override + public Boolean updateByBo(SysSocialBo bo) { + SysSocial update = MapstructUtils.convert(bo, SysSocial.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysSocial entity) { + //TODO 做一些数据校验,如唯一约束 + } + + + /** + * 删除社会化关系 + */ + @Override + public Boolean deleteWithValidById(Long id) { + return baseMapper.deleteById(id) > 0; + } + + + /** + * 根据 authId 查询用户信息 + * + * @param authId 认证id + * @return 授权信息 + */ + @Override + public List selectByAuthId(String authId) { + return baseMapper.selectVoList(new LambdaQueryWrapper().eq(SysSocial::getAuthId, authId)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java new file mode 100644 index 0000000..cab0d61 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java @@ -0,0 +1,774 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.*; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.*; +import org.dromara.system.mapper.*; +import org.dromara.system.service.ISysUserService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +/** + * 用户 业务层处理 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysUserServiceImpl implements ISysUserService, UserService { + + private final SysUserMapper baseMapper; + private final SysDeptMapper deptMapper; + private final SysRoleMapper roleMapper; + private final SysPostMapper postMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysUserPostMapper userPostMapper; + + @Override + public TableDataInfo selectPageUserList(SysUserBo user, PageQuery pageQuery) { + Page page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user)); + return TableDataInfo.build(page); + } + + @Override + public List selectUserWarehouseNameList(){ + return baseMapper.selectUserWarehouseNameList(); + } + + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public List selectUserExportList(SysUserBo user) { + return baseMapper.selectUserExportList(this.buildQueryWrapper(user)); + } + + private Wrapper buildQueryWrapper(SysUserBo user) { + Map params = user.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "u.create_time", params.get("beginTime"), params.get("endTime")) + .and(ObjectUtil.isNotNull(user.getDeptId()), w -> { + List deptList = deptMapper.selectListByParentId(user.getDeptId()); + List ids = StreamUtils.toList(deptList, SysDept::getDeptId); + ids.add(user.getDeptId()); + w.in("u.dept_id", ids); + }).orderByAsc("u.user_id"); + + // 根据 role_key 过滤用户(EXISTS 子查询,不会重复) + if (StringUtils.isNotBlank(user.getRoleKey())) { + wrapper.exists("SELECT 1 FROM sys_user_role ur " + + "INNER JOIN sys_role r ON ur.role_id = r.role_id " + + "WHERE ur.user_id = u.user_id " + + "AND r.role_key = '" + user.getRoleKey() + "'"); + } + + if (StringUtils.isNotBlank(user.getExcludeUserIds())) { + wrapper.notIn("u.user_id", StringUtils.splitTo(user.getExcludeUserIds(), Convert::toLong)); + } + + return wrapper; + } + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public TableDataInfo selectAllocatedList(SysUserBo user, PageQuery pageQuery) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId()) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .orderByAsc("u.user_id"); + Page page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + @Override + public TableDataInfo selectUnallocatedList(SysUserBo user, PageQuery pageQuery) { + List userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId()); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id")) + .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds) + .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) + .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()) + .orderByAsc("u.user_id"); + Page page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper); + return TableDataInfo.build(page); + } + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserByUserName(String userName) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, userName)); + } + + /** + * 通过手机号查询用户 + * + * @param phoneNumber 手机号 + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserByPhonenumber(String phoneNumber) { + return baseMapper.selectListByPhonenumber(phoneNumber); + } + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + @Override + public SysUserVo selectUserById(Long userId) { + SysUserVo user = baseMapper.selectVoById(userId); + //校验仓库名称是否为空 + if (ObjectUtil.isNull(user)) { + return user; + } +// if(StringUtils.isEmpty(user.getWarehouseName())){ +// //如果仓库名称为空,则赋值默认库存名称 +// SysUserBo sysUserBo = new SysUserBo(); +// sysUserBo.setUserId(user.getUserId()); +// sysUserBo.setNickName(user.getNickName()); +// sysUserBo.setPhonenumber(user.getPhonenumber()); +// sysUserBo.setEmail(user.getEmail()); +// sysUserBo.setSex(user.getSex()); +// sysUserBo.setWarehouseName("默认仓库名称"+UUID.randomUUID()); +// updateUserProfile(sysUserBo); +// } + user.setRoles(roleMapper.selectRolesByUserId(user.getUserId())); + return user; + } + + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + @Override + public List selectUserByIds(List userIds, Long deptId) { + return baseMapper.selectUserList(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .eq(ObjectUtil.isNotNull(deptId), SysUser::getDeptId, deptId) + .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds)); + } + + /** + * 查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserRoleGroup(Long userId) { + List list = roleMapper.selectRolesByUserId(userId); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysRoleVo::getRoleName); + } + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + public String selectUserPostGroup(Long userId) { + List list = postMapper.selectPostsByUserId(userId); + if (CollUtil.isEmpty(list)) { + return StringUtils.EMPTY; + } + return StreamUtils.join(list, SysPostVo::getPostName); + } + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean checkUserNameUnique(SysUserBo user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getUserName, user.getUserName()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkPhoneUnique(SysUserBo user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getPhonenumber, user.getPhonenumber()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + */ + @Override + public boolean checkEmailUnique(SysUserBo user) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getEmail, user.getEmail()) + .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId())); + return !exist; + } + + /** + * 校验用户是否允许操作 + * + * @param userId 用户ID + */ + @Override + public void checkUserAllowed(Long userId) { + if (ObjectUtil.isNotNull(userId) && LoginHelper.isSuperAdmin(userId)) { + throw new ServiceException("不允许操作超级管理员用户"); + } + } + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + @Override + public void checkUserDataScope(Long userId) { + if (ObjectUtil.isNull(userId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (baseMapper.countUserById(userId) == 0) { + throw new ServiceException("没有权限访问用户数据!"); + } + } + + /** + * 新增保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int insertUser(SysUserBo user) { + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + // 新增用户信息 + int rows = baseMapper.insert(sysUser); + user.setUserId(sysUser.getUserId()); + // 新增用户岗位关联 + insertUserPost(user, false); + // 新增用户与角色管理 + insertUserRole(user, false); + return rows; + } + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + public boolean registerUser(SysUserBo user, String tenantId) { + user.setCreateBy(0L); + user.setUpdateBy(0L); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + sysUser.setTenantId(tenantId); + return baseMapper.insert(sysUser) > 0; + } + + /** + * 修改保存用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + @Override + @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId") + @Transactional(rollbackFor = Exception.class) + public int updateUser(SysUserBo user) { + // 新增用户与角色管理 + insertUserRole(user, true); + // 新增用户与岗位管理 + insertUserPost(user, true); + SysUser sysUser = MapstructUtils.convert(user, SysUser.class); + // 防止错误更新后导致的数据误删除 + int flag = baseMapper.updateById(sysUser); + if (flag < 1) { + throw new ServiceException("修改用户" + user.getUserName() + "信息失败"); + } + return flag; + } + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void insertUserAuth(Long userId, Long[] roleIds) { + insertUserRole(userId, roleIds, true); + } + + /** + * 修改用户状态 + * + * @param userId 用户ID + * @param status 帐号状态 + * @return 结果 + */ + @Override + public int updateUserStatus(Long userId, String status) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getStatus, status) + .eq(SysUser::getUserId, userId)); + } + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_NICKNAME, key = "#user.userId") + @Override + public int updateUserProfile(SysUserBo user) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName()) + .set(SysUser::getPhonenumber, user.getPhonenumber()) + .set(SysUser::getEmail, user.getEmail()) + .set(SysUser::getSex, user.getSex()) + .set(SysUser::getWarehouseName,user.getWarehouseName()) + .eq(SysUser::getUserId, user.getUserId())); + } + + /** + * 修改用户头像 + * + * @param userId 用户ID + * @param avatar 头像地址 + * @return 结果 + */ + @Override + public boolean updateUserAvatar(Long userId, Long avatar) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getAvatar, avatar) + .eq(SysUser::getUserId, userId)) > 0; + } + + /** + * 重置用户密码 + * + * @param userId 用户ID + * @param password 密码 + * @return 结果 + */ + @Override + public int resetUserPwd(Long userId, String password) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysUser::getPassword, password) + .eq(SysUser::getUserId, userId)); + } + + /** + * 新增用户角色信息 + * + * @param user 用户对象 + * @param clear 清除已存在的关联数据 + */ + private void insertUserRole(SysUserBo user, boolean clear) { + this.insertUserRole(user.getUserId(), user.getRoleIds(), clear); + } + + /** + * 新增用户岗位信息 + * + * @param user 用户对象 + * @param clear 清除已存在的关联数据 + */ + private void insertUserPost(SysUserBo user, boolean clear) { + Long[] posts = user.getPostIds(); + if (ArrayUtil.isNotEmpty(posts)) { + if (clear) { + // 删除用户与岗位关联 + userPostMapper.delete(new LambdaQueryWrapper().eq(SysUserPost::getUserId, user.getUserId())); + } + // 新增用户与岗位管理 + List list = StreamUtils.toList(List.of(posts), postId -> { + SysUserPost up = new SysUserPost(); + up.setUserId(user.getUserId()); + up.setPostId(postId); + return up; + }); + userPostMapper.insertBatch(list); + } + } + + /** + * 新增用户角色信息 + * + * @param userId 用户ID + * @param roleIds 角色组 + * @param clear 清除已存在的关联数据 + */ + private void insertUserRole(Long userId, Long[] roleIds, boolean clear) { + if (ArrayUtil.isNotEmpty(roleIds)) { + List roleList = new ArrayList<>(List.of(roleIds)); + if (!LoginHelper.isSuperAdmin(userId)) { + roleList.remove(SystemConstants.SUPER_ADMIN_ID); + } + // 判断是否具有此角色的操作权限 + List roles = roleMapper.selectRoleList( + new QueryWrapper().in("r.role_id", roleList)); + if (CollUtil.isEmpty(roles)) { + throw new ServiceException("没有权限访问角色的数据"); + } + if (clear) { + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); + } + // 新增用户与角色管理 + List list = StreamUtils.toList(roleList, roleId -> { + SysUserRole ur = new SysUserRole(); + ur.setUserId(userId); + ur.setRoleId(roleId); + return ur; + }); + userRoleMapper.insertBatch(list); + } + } + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserById(Long userId) { + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().eq(SysUserRole::getUserId, userId)); + // 删除用户与岗位表 + userPostMapper.delete(new LambdaQueryWrapper().eq(SysUserPost::getUserId, userId)); + // 防止更新失败导致的数据删除 + int flag = baseMapper.deleteById(userId); + if (flag < 1) { + throw new ServiceException("删除用户失败!"); + } + return flag; + } + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int deleteUserByIds(Long[] userIds) { + for (Long userId : userIds) { + checkUserAllowed(userId); + checkUserDataScope(userId); + } + List ids = List.of(userIds); + // 删除用户与角色关联 + userRoleMapper.delete(new LambdaQueryWrapper().in(SysUserRole::getUserId, ids)); + // 删除用户与岗位表 + userPostMapper.delete(new LambdaQueryWrapper().in(SysUserPost::getUserId, ids)); + // 防止更新失败导致的数据删除 + int flag = baseMapper.deleteByIds(ids); + if (flag < 1) { + throw new ServiceException("删除用户失败!"); + } + return flag; + } + + /** + * 通过部门id查询当前部门所有用户 + * + * @param deptId 部门ID + * @return 用户信息集合信息 + */ + @Override + public List selectUserListByDept(Long deptId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(SysUser::getDeptId, deptId); + lqw.orderByAsc(SysUser::getUserId); + return baseMapper.selectVoList(lqw); + } + + + @Override + public SysUserVo selectUserByOpenid(String openid, String phoneNumber) { + return baseMapper.selectVoListByOpenId(openid,phoneNumber); + } + + + @Override + public boolean updateOpenIdByPhoneNumber(String phoneNumber, String openid) { + return baseMapper.updateOpenIdByPhoneNumber(phoneNumber,openid); + } + + + @Override + public void insertUserOpenId(String openid, String phonenumber) { + baseMapper.insertUserOpenId(openid,phonenumber); + } + + @Override + public List selectUserName() { + return baseMapper.selectUserName(); + } + + @Override + public SysUserVo selectUserByUserId(Long userId) { + return baseMapper.selectUserByUserId(userId); + } + + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId") + @Override + public String selectUserNameById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getUserName).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getUserName); + } + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + @Override + @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId") + public String selectNicknameById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getNickName).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getNickName); + } + + /** + * 通过用户ID查询用户账户 + * + * @param userIds 用户ID 多个用逗号隔开 + * @return 用户账户 + */ + @Override + public String selectNicknameByIds(String userIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(userIds, Convert::toLong)) { + String nickname = SpringUtils.getAopProxy(this).selectNicknameById(id); + if (StringUtils.isNotBlank(nickname)) { + list.add(nickname); + } + } + return String.join(StringUtils.SEPARATOR, list); + } + + /** + * 通过用户ID查询用户手机号 + * + * @param userId 用户id + * @return 用户手机号 + */ + @Override + public String selectPhonenumberById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getPhonenumber).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getPhonenumber); + } + + /** + * 通过用户ID查询用户邮箱 + * + * @param userId 用户id + * @return 用户邮箱 + */ + @Override + public String selectEmailById(Long userId) { + SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysUser::getEmail).eq(SysUser::getUserId, userId)); + return ObjectUtils.notNullGetter(sysUser, SysUser::getEmail); + } + + /** + * 通过用户ID查询用户列表 + * + * @param userIds 用户ids + * @return 用户列表 + */ + @Override + public List selectListByIds(List userIds) { + if (CollUtil.isEmpty(userIds)) { + return List.of(); + } + List list = baseMapper.selectVoList(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .in(SysUser::getUserId, userIds)); + return BeanUtil.copyToList(list, UserDTO.class); + } + + /** + * 通过角色ID查询用户ID + * + * @param roleIds 角色ids + * @return 用户ids + */ + @Override + public List selectUserIdsByRoleIds(List roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return List.of(); + } + List userRoles = userRoleMapper.selectList( + new LambdaQueryWrapper().in(SysUserRole::getRoleId, roleIds)); + return StreamUtils.toList(userRoles, SysUserRole::getUserId); + } + + /** + * 通过角色ID查询用户 + * + * @param roleIds 角色ids + * @return 用户 + */ + @Override + public List selectUsersByRoleIds(List roleIds) { + if (CollUtil.isEmpty(roleIds)) { + return List.of(); + } + + // 通过角色ID获取用户角色信息 + List userRoles = userRoleMapper.selectList( + new LambdaQueryWrapper().in(SysUserRole::getRoleId, roleIds)); + + // 获取用户ID列表 + Set userIds = StreamUtils.toSet(userRoles, SysUserRole::getUserId); + + return selectListByIds(new ArrayList<>(userIds)); + } + + /** + * 通过部门ID查询用户 + * + * @param deptIds 部门ids + * @return 用户 + */ + @Override + public List selectUsersByDeptIds(List deptIds) { + if (CollUtil.isEmpty(deptIds)) { + return List.of(); + } + List list = baseMapper.selectVoList(new LambdaQueryWrapper() + .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName, SysUser::getEmail, SysUser::getPhonenumber) + .eq(SysUser::getStatus, SystemConstants.NORMAL) + .in(SysUser::getDeptId, deptIds)); + return BeanUtil.copyToList(list, UserDTO.class); + } + + /** + * 通过岗位ID查询用户 + * + * @param postIds 岗位ids + * @return 用户 + */ + @Override + public List selectUsersByPostIds(List postIds) { + if (CollUtil.isEmpty(postIds)) { + return List.of(); + } + + // 通过岗位ID获取用户岗位信息 + List userPosts = userPostMapper.selectList( + new LambdaQueryWrapper().in(SysUserPost::getPostId, postIds)); + + // 获取用户ID列表 + Set userIds = StreamUtils.toSet(userPosts, SysUserPost::getUserId); + + return selectListByIds(new ArrayList<>(userIds)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml new file mode 100644 index 0000000..e542a10 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml new file mode 100644 index 0000000..6975da4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml new file mode 100644 index 0000000..9dd3f2e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml new file mode 100644 index 0000000..43f494d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml new file mode 100644 index 0000000..0d96e13 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml new file mode 100644 index 0000000..79cf4c5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml new file mode 100644 index 0000000..e9f2496 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java new file mode 100644 index 0000000..1b10eb8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java @@ -0,0 +1,66 @@ +package org.dromara.workflow.common.constant; + + +/** + * 工作流常量 + * + * @author may + */ +public interface FlowConstant { + + /** + * 流程发起人 + */ + String INITIATOR = "initiator"; + + /** + * 流程实例id + */ + String PROCESS_INSTANCE_ID = "processInstanceId"; + + /** + * 业务id + */ + String BUSINESS_ID = "businessId"; + + /** + * 任务id + */ + String TASK_ID = "taskId"; + + /** + * 委托 + */ + String DELEGATE_TASK = "delegateTask"; + + /** + * 转办 + */ + String TRANSFER_TASK = "transferTask"; + + /** + * 加签 + */ + String ADD_SIGNATURE = "addSignature"; + + /** + * 减签 + */ + String REDUCTION_SIGNATURE = "reductionSignature"; + + /** + * 流程分类Id转名称 + */ + String CATEGORY_ID_TO_NAME = "category_id_to_name"; + + /** + * 流程分类名称 + */ + String FLOW_CATEGORY_NAME = "flow_category_name#30d"; + + /** + * 默认租户OA申请分类id + */ + Long FLOW_CATEGORY_ID = 100L; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java new file mode 100644 index 0000000..60be92f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java @@ -0,0 +1,109 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 任务分配人枚举 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum TaskAssigneeEnum { + + /** + * 用户 + */ + USER("用户", ""), + + /** + * 角色 + */ + ROLE("角色", "role:"), + + /** + * 部门 + */ + DEPT("部门", "dept:"), + + /** + * 岗位 + */ + POST("岗位", "post:"); + + private final String desc; + private final String code; + + /** + * 根据描述获取对应的枚举类型 + *

+ * 通过传入描述,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。 + *

+ * + * @param desc 描述,用于匹配对应的枚举项 + * @return TaskAssigneeEnum 返回对应的枚举类型 + * @throws ServiceException 如果未找到匹配的枚举项 + */ + public static TaskAssigneeEnum fromDesc(String desc) { + for (TaskAssigneeEnum type : values()) { + if (type.getDesc().equals(desc)) { + return type; + } + } + throw new ServiceException("未知的办理人类型: " + desc); + } + + /** + * 根据代码获取对应的枚举类型 + *

+ * 通过传入代码,查找并返回匹配的枚举项。如果未找到匹配项,会抛出 {@link ServiceException}。 + *

+ * + * @param code 代码,用于匹配对应的枚举项 + * @return TaskAssigneeEnum 返回对应的枚举类型 + * @throws IllegalArgumentException 如果未找到匹配的枚举项 + */ + public static TaskAssigneeEnum fromCode(String code) { + for (TaskAssigneeEnum type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + throw new ServiceException("未知的办理人类型代码: " + code); + } + + /** + * 获取所有办理人类型的描述列表 + *

+ * 获取当前枚举类所有项的描述字段列表,通常用于展示选择项。 + *

+ * + * @return List 返回所有办理人类型的描述列表 + */ + public static List getAssigneeTypeList() { + return Arrays.stream(values()) + .map(TaskAssigneeEnum::getDesc) + .collect(Collectors.toList()); + } + + /** + * 获取所有办理人类型的代码列表 + *

+ * 获取当前枚举类所有项的代码字段列表,通常用于程序内部逻辑的判断。 + *

+ * + * @return List 返回所有办理人类型的代码列表 + */ + public static List getAssigneeCodeList() { + return Arrays.stream(values()) + .map(TaskAssigneeEnum::getCode) + .collect(Collectors.toList()); + } +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java new file mode 100644 index 0000000..86ac1ac --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java @@ -0,0 +1,58 @@ +package org.dromara.workflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 流程分类对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("flow_category") +public class FlowCategory extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程分类ID + */ + @TableId(value = "category_id") + private Long categoryId; + + /** + * 父流程分类id + */ + private Long parentId; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 流程分类名称 + */ + private String categoryName; + + /** + * 显示顺序 + */ + private Long orderNum; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java new file mode 100644 index 0000000..31742ea --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 撤销任务请求对象 + * + * @author may + */ +@Data +public class FlowCancelBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotBlank(message = "业务ID不能为空", groups = AddGroup.class) + private String businessId; + + /** + * 办理意见 + */ + private String message; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java new file mode 100644 index 0000000..a45e521 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java @@ -0,0 +1,30 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 抄送 + * + * @author may + */ +@Data +public class FlowCopyBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户名称 + */ + private String userName; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java new file mode 100644 index 0000000..ea21a81 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.domain.bo; + + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 启动流程对象 + * + * @author may + */ +@Data +public class StartProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 业务唯一值id + */ + @NotBlank(message = "业务ID不能为空", groups = {AddGroup.class}) + private String businessId; + + /** + * 流程定义编码 + */ + @NotBlank(message = "流程定义编码不能为空", groups = {AddGroup.class}) + private String flowCode; + + /** + * 流程变量,前端会提交一个元素{'entity': {业务详情数据对象}} + */ + private Map variables; + + public Map getVariables() { + if (variables == null) { + return new HashMap<>(16); + } + variables.entrySet().removeIf(entry -> Objects.isNull(entry.getValue())); + return variables; + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java new file mode 100644 index 0000000..b4de76e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowVariableVo.java @@ -0,0 +1,28 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程变量 + * + * @author may + */ +@Data +public class FlowVariableVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 变量key + */ + private String key; + + /** + * 变量值 + */ + private String value; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java new file mode 100644 index 0000000..b187854 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java @@ -0,0 +1,130 @@ +package org.dromara.workflow.listener; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Definition; +import org.dromara.warm.flow.core.entity.Instance; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.listener.GlobalListener; +import org.dromara.warm.flow.core.listener.ListenerVariable; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 全局任务办理监听 + * + * @author may + */ +@ConditionalOnEnable +@Component +@Slf4j +@RequiredArgsConstructor +public class WorkflowGlobalListener implements GlobalListener { + + private final IFlwTaskService taskService; + private final IFlwInstanceService instanceService; + private final FlowProcessEventHandler flowProcessEventHandler; + + /** + * 创建监听器,任务创建时执行 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void create(ListenerVariable listenerVariable) { + Instance instance = listenerVariable.getInstance(); + Definition definition = listenerVariable.getDefinition(); + String businessId = instance.getBusinessId(); + String flowStatus = instance.getFlowStatus(); + Task task = listenerVariable.getTask(); + if (task != null && BusinessStatusEnum.WAITING.getStatus().equals(flowStatus)) { + // 判断流程状态(发布审批中事件) + flowProcessEventHandler.processTaskHandler(definition.getFlowCode(), task.getNodeCode(), task.getId(), businessId); + } + } + + /** + * 开始监听器,任务开始办理时执行 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void start(ListenerVariable listenerVariable) { + } + + /** + * 分派监听器,动态修改代办任务信息 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void assignment(ListenerVariable listenerVariable) { + } + + /** + * 完成监听器,当前任务完成后执行 + * + * @param listenerVariable 监听器变量 + */ + @Override + public void finish(ListenerVariable listenerVariable) { + Instance instance = listenerVariable.getInstance(); + Definition definition = listenerVariable.getDefinition(); + String businessId = instance.getBusinessId(); + String flowStatus = instance.getFlowStatus(); + Map params = new HashMap<>(); + FlowParams flowParams = listenerVariable.getFlowParams(); + if (ObjectUtil.isNotNull(flowParams)) { + // 历史任务扩展(通常为附件) + params.put("hisTaskExt", flowParams.getHisTaskExt()); + // 办理人 + params.put("handler", flowParams.getHandler()); + // 办理意见 + params.put("message", flowParams.getMessage()); + } + // 判断流程状态(发布:撤销,退回,作废,终止,已完成事件) + String status = determineFlowStatus(instance, flowStatus); + if (StringUtils.isNotBlank(status)) { + flowProcessEventHandler.processHandler(definition.getFlowCode(), businessId, status, params, false); + } + } + + /** + * 根据流程实例和当前流程状态确定最终状态 + * + * @param instance 流程实例 + * @param flowStatus 流程实例当前状态 + * @return 流程最终状态 + */ + private String determineFlowStatus(Instance instance, String flowStatus) { + if (StringUtils.isNotBlank(flowStatus) && BusinessStatusEnum.initialState(flowStatus)) { + log.info("流程实例当前状态: {}", flowStatus); + return flowStatus; + } else { + Long instanceId = instance.getId(); + List flowTasks = taskService.selectByInstId(instanceId); + if (CollUtil.isEmpty(flowTasks)) { + String status = BusinessStatusEnum.FINISH.getStatus(); + // 更新流程状态为已完成 + instanceService.updateStatus(instanceId, status); + log.info("流程已结束,状态更新为: {}", status); + return status; + } + return null; + } + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java new file mode 100644 index 0000000..92809c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java @@ -0,0 +1,27 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; + +/** + * 实例信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwInstanceMapper { + + /** + * 流程实例信息 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page selectInstanceList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java new file mode 100644 index 0000000..fd86c82 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java @@ -0,0 +1,57 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; +import org.dromara.workflow.domain.bo.FlowTaskBo; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; + +import java.util.List; + + +/** + * 任务信息Mapper接口 + * + * @author may + * @date 2024-03-02 + */ +public interface FlwTaskMapper { + + /** + * 获取待办信息 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getListRunTask(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 获取待办信息 + * + * @param queryWrapper 条件 + * @return 结果 + */ + List getListRunTask(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 获取已办 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getListFinishTask(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 查询当前用户的抄送 + * + * @param page 分页 + * @param queryWrapper 条件 + * @return 结果 + */ + Page getTaskCopyByPage(@Param("page") Page page, @Param(Constants.WRAPPER) QueryWrapper queryWrapper); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java new file mode 100644 index 0000000..1a2d29f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java @@ -0,0 +1,79 @@ +package org.dromara.workflow.service; + +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * 流程定义 服务层 + * + * @author may + */ +public interface IFlwDefinitionService { + + /** + * 查询流程定义列表 + * + * @param flowDefinition 参数 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + TableDataInfo queryList(FlowDefinition flowDefinition, PageQuery pageQuery); + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinition 参数 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + TableDataInfo unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery); + + + /** + * 发布流程定义 + * + * @param id 流程定义id + * @return 结果 + */ + boolean publish(Long id); + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + void exportDef(Long id, HttpServletResponse response) throws IOException; + + /** + * 导入流程定义 + * + * @param file 文件 + * @param category 分类 + * @return 结果 + */ + boolean importJson(MultipartFile file, String category); + + /** + * 删除流程定义 + * + * @param ids 流程定义id + * @return 结果 + */ + boolean removeDef(List ids); + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + void syncDef(String tenantId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java new file mode 100644 index 0000000..11034e7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java @@ -0,0 +1,191 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; + +import java.util.List; +import java.util.Map; + +/** + * 任务 服务层 + * + * @author may + */ +public interface IFlwTaskService { + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + * @return 结果 + */ + StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo); + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + * @return 结果 + */ + boolean completeTask(CompleteTaskBo completeTaskBo); + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询当前租户所有待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery); + + /** + * 修改任务办理人 + * + * @param taskIdList 任务id + * @param userId 用户id + * @return 结果 + */ + boolean updateAssignee(List taskIdList, String userId); + + /** + * 驳回审批 + * + * @param bo 参数 + * @return 结果 + */ + boolean backProcess(BackProcessBo bo); + + /** + * 获取可驳回的前置节点 + * + * @param definitionId 流程定义id + * @param nowNodeCode 当前节点 + * @return 结果 + */ + List getBackTaskNode(Long definitionId, String nowNodeCode); + + /** + * 终止任务 + * + * @param bo 参数 + * @return 结果 + */ + boolean terminationTask(FlowTerminationBo bo); + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 结果 + */ + List selectByIdList(List taskIdList); + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 结果 + */ + FlowTaskVo selectById(Long taskId); + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 结果 + */ + List selectHisTaskByIdList(List taskIdList); + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 结果 + */ + FlowHisTask selectHisTaskById(Long taskId); + + /** + * 按照实例id查询任务 + * + * @param instanceIdList 流程实例id + * @return 结果 + */ + List selectByInstIdList(List instanceIdList); + + /** + * 按照实例id查询任务 + * + * @param instanceId 流程实例id + * @return 结果 + */ + List selectByInstId(Long instanceId); + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + * @return 结果 + */ + boolean taskOperation(TaskOperationBo bo, String taskOperation); + + /** + * 获取任务所有办理人 + * + * @param taskIdList 任务id + * @return 结果 + */ + Map> currentTaskAllUser(List taskIdList); + + /** + * 获取当前任务的所有办理人 + * + * @param taskId 任务id + * @return 结果 + */ + List currentTaskAllUser(Long taskId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java new file mode 100644 index 0000000..db1b7b7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java @@ -0,0 +1,269 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * 流程分类Service业务层处理 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +public class FlwCategoryServiceImpl implements IFlwCategoryService { + + private final DefService defService; + private final FlwCategoryMapper baseMapper; + + /** + * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 + */ + @Override + public FlowCategoryVo queryById(Long categoryId) { + FlowCategoryVo category = baseMapper.selectVoById(categoryId); + if (ObjectUtil.isNull(category)) { + return null; + } + FlowCategoryVo parentCategory = baseMapper.selectVoOne(new LambdaQueryWrapper() + .select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, category.getParentId())); + category.setParentName(ObjectUtils.notNullGetter(parentCategory, FlowCategoryVo::getCategoryName)); + return category; + } + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryId 流程分类ID + * @return 流程分类名称 + */ + @Cacheable(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId") + @Override + public String selectCategoryNameById(Long categoryId) { + if (ObjectUtil.isNull(categoryId)) { + return null; + } + FlowCategory category = baseMapper.selectOne(new LambdaQueryWrapper() + .select(FlowCategory::getCategoryName).eq(FlowCategory::getCategoryId, categoryId)); + return ObjectUtils.notNullGetter(category, FlowCategory::getCategoryName); + } + + /** + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 + */ + @Override + public List queryList(FlowCategoryBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + /** + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 + */ + @Override + public List> selectCategoryTreeList(FlowCategoryBo category) { + LambdaQueryWrapper lqw = buildQueryWrapper(category); + List categorys = baseMapper.selectVoList(lqw); + if (CollUtil.isEmpty(categorys)) { + return CollUtil.newArrayList(); + } + // 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点 + List> treeList = CollUtil.newArrayList(); + for (FlowCategoryVo d : categorys) { + String parentId = d.getParentId().toString(); + FlowCategoryVo categoryVo = StreamUtils.findFirst(categorys, it -> it.getCategoryId().toString().equals(parentId)); + if (ObjectUtil.isNull(categoryVo)) { + List> trees = TreeBuildUtils.build(categorys, parentId, (dept, tree) -> + tree.setId(dept.getCategoryId().toString()) + .setParentId(dept.getParentId().toString()) + .setName(dept.getCategoryName()) + .setWeight(dept.getOrderNum())); + Tree tree = StreamUtils.findFirst(trees, it -> it.getId().equals(d.getCategoryId().toString())); + treeList.add(tree); + } + } + return treeList; + } + + /** + * 校验流程分类是否有数据权限 + * + * @param categoryId 流程分类ID + */ + @Override + public void checkCategoryDataScope(Long categoryId) { + if (ObjectUtil.isNull(categoryId)) { + return; + } + if (LoginHelper.isSuperAdmin()) { + return; + } + if (baseMapper.countCategoryById(categoryId) == 0) { + throw new ServiceException("没有权限访问流程分类数据!"); + } + } + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + @Override + public boolean checkCategoryNameUnique(FlowCategoryBo category) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowCategory::getCategoryName, category.getCategoryName()) + .eq(FlowCategory::getParentId, category.getParentId()) + .ne(ObjectUtil.isNotNull(category.getCategoryId()), FlowCategory::getCategoryId, category.getCategoryId())); + return !exist; + } + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + @Override + public boolean checkCategoryExistDefinition(Long categoryId) { + FlowDefinition definition = new FlowDefinition(); + definition.setCategory(categoryId.toString()); + return defService.exists(definition); + } + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + @Override + public boolean hasChildByCategoryId(Long categoryId) { + return baseMapper.exists(new LambdaQueryWrapper() + .eq(FlowCategory::getParentId, categoryId)); + } + + private LambdaQueryWrapper buildQueryWrapper(FlowCategoryBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(FlowCategory::getDelFlag, SystemConstants.NORMAL); + lqw.eq(ObjectUtil.isNotNull(bo.getCategoryId()), FlowCategory::getCategoryId, bo.getCategoryId()); + lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), FlowCategory::getParentId, bo.getParentId()); + lqw.like(StringUtils.isNotBlank(bo.getCategoryName()), FlowCategory::getCategoryName, bo.getCategoryName()); + lqw.orderByAsc(FlowCategory::getAncestors); + lqw.orderByAsc(FlowCategory::getParentId); + lqw.orderByAsc(FlowCategory::getOrderNum); + lqw.orderByAsc(FlowCategory::getCategoryId); + return lqw; + } + + /** + * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 + */ + @Override + public int insertByBo(FlowCategoryBo bo) { + FlowCategory info = baseMapper.selectById(bo.getParentId()); + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + category.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + category.getParentId()); + return baseMapper.insert(category); + } + + /** + * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 + */ + @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#bo.categoryId") + @Override + public int updateByBo(FlowCategoryBo bo) { + FlowCategory category = MapstructUtils.convert(bo, FlowCategory.class); + FlowCategory oldCategory = baseMapper.selectById(category.getCategoryId()); + if (ObjectUtil.isNull(oldCategory)) { + throw new ServiceException("流程分类不存在,无法修改"); + } + if (!oldCategory.getParentId().equals(category.getParentId())) { + // 如果是新父流程分类 则校验是否具有新父流程分类权限 避免越权 + this.checkCategoryDataScope(category.getParentId()); + FlowCategory newParentCategory = baseMapper.selectById(category.getParentId()); + if (ObjectUtil.isNotNull(newParentCategory)) { + String newAncestors = newParentCategory.getAncestors() + StringUtils.SEPARATOR + newParentCategory.getCategoryId(); + String oldAncestors = oldCategory.getAncestors(); + category.setAncestors(newAncestors); + updateCategoryChildren(category.getCategoryId(), newAncestors, oldAncestors); + } + } else { + category.setAncestors(oldCategory.getAncestors()); + } + return baseMapper.updateById(category); + } + + /** + * 修改子元素关系 + * + * @param categoryId 被修改的流程分类ID + * @param newAncestors 新的父ID集合 + * @param oldAncestors 旧的父ID集合 + */ + private void updateCategoryChildren(Long categoryId, String newAncestors, String oldAncestors) { + List children = baseMapper.selectList(new LambdaQueryWrapper() + .apply(DataBaseHelper.findInSet(categoryId, "ancestors"))); + List list = new ArrayList<>(); + for (FlowCategory child : children) { + FlowCategory category = new FlowCategory(); + category.setCategoryId(child.getCategoryId()); + category.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + list.add(category); + } + if (CollUtil.isNotEmpty(list)) { + baseMapper.updateBatchById(list); + } + } + + /** + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 + */ + @CacheEvict(cacheNames = FlowConstant.FLOW_CATEGORY_NAME, key = "#categoryId") + @Override + public int deleteWithValidById(Long categoryId) { + return baseMapper.deleteById(categoryId); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java new file mode 100644 index 0000000..5877bb5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java @@ -0,0 +1,165 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.DeptDTO; +import org.dromara.common.core.domain.dto.TaskAssigneeDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.domain.model.TaskAssigneeBody; +import org.dromara.common.core.enums.FormatsType; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DeptService; +import org.dromara.common.core.service.TaskAssigneeService; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.ui.dto.HandlerFunDto; +import org.dromara.warm.flow.ui.dto.HandlerQuery; +import org.dromara.warm.flow.ui.dto.TreeFunDto; +import org.dromara.warm.flow.ui.service.HandlerSelectService; +import org.dromara.warm.flow.ui.vo.HandlerSelectVo; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskAssigneeEnum; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * 流程设计器-获取办理人权限设置列表 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, HandlerSelectService { + + private static final String DEFAULT_GROUP_NAME = "默认分组"; + private final TaskAssigneeService taskAssigneeService; + private final UserService userService; + private final DeptService deptService; + + /** + * 获取办理人权限设置列表tabs页签 + * + * @return tabs页签 + */ + @Override + public List getHandlerType() { + return TaskAssigneeEnum.getAssigneeTypeList(); + } + + /** + * 获取办理列表, 同时构建左侧部门树状结构 + * + * @param query 查询条件 + * @return HandlerSelectVo + */ + @Override + public HandlerSelectVo getHandlerSelect(HandlerQuery query) { + // 获取任务办理类型 + TaskAssigneeEnum type = TaskAssigneeEnum.fromDesc(query.getHandlerType()); + // 转换查询条件为 TaskAssigneeBody + TaskAssigneeBody taskQuery = BeanUtil.toBean(query, TaskAssigneeBody.class); + + // 统一查询并构建业务数据 + TaskAssigneeDTO dto = fetchTaskAssigneeData(type, taskQuery); + List depts = fetchDeptData(type); + + return getHandlerSelectVo(buildHandlerData(dto, type), buildDeptTree(depts)); + } + + /** + * 根据任务办理类型查询对应的数据 + */ + private TaskAssigneeDTO fetchTaskAssigneeData(TaskAssigneeEnum type, TaskAssigneeBody taskQuery) { + return switch (type) { + case USER -> taskAssigneeService.selectUsersByTaskAssigneeList(taskQuery); + case ROLE -> taskAssigneeService.selectRolesByTaskAssigneeList(taskQuery); + case DEPT -> taskAssigneeService.selectDeptsByTaskAssigneeList(taskQuery); + case POST -> taskAssigneeService.selectPostsByTaskAssigneeList(taskQuery); + default -> throw new ServiceException("Unsupported handler type"); + }; + } + + /** + * 根据任务办理类型获取部门数据 + */ + private List fetchDeptData(TaskAssigneeEnum type) { + if (type == TaskAssigneeEnum.USER || type == TaskAssigneeEnum.DEPT || type == TaskAssigneeEnum.POST) { + return deptService.selectDeptsByList(); + } + return new ArrayList<>(); + } + + /** + * 构建部门树状结构 + */ + private TreeFunDto buildDeptTree(List depts) { + return new TreeFunDto<>(depts) + .setId(dept -> String.valueOf(dept.getDeptId())) + .setName(DeptDTO::getDeptName) + .setParentId(dept -> String.valueOf(dept.getParentId())); + } + + /** + * 构建任务办理人数据 + */ + private HandlerFunDto buildHandlerData(TaskAssigneeDTO dto, TaskAssigneeEnum type) { + return new HandlerFunDto<>(dto.getList(), dto.getTotal()) + .setStorageId(assignee -> type.getCode() + assignee.getStorageId()) + .setHandlerCode(assignee -> StringUtils.blankToDefault(assignee.getHandlerCode(), "无")) + .setHandlerName(assignee -> StringUtils.blankToDefault(assignee.getHandlerName(), "无")) + .setGroupName(assignee -> StringUtils.defaultIfBlank( + Optional.ofNullable(assignee.getGroupName()) + .map(deptService::selectDeptNameByIds) + .orElse(DEFAULT_GROUP_NAME), DEFAULT_GROUP_NAME)) + .setCreateTime(assignee -> DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, assignee.getCreateTime())); + } + + /** + * 根据存储标识符(storageId)解析分配类型和ID,并获取对应的用户列表 + * + * @param storageId 包含分配类型和ID的字符串(例如 "user:123" 或 "role:456") + * @return 与分配类型和ID匹配的用户列表,如果格式无效则返回空列表 + */ + @Override + public List fetchUsersByStorageId(String storageId) { + List list = new ArrayList<>(); + for (String str : storageId.split(StrUtil.COMMA)) { + String[] parts = str.split(StrUtil.COLON, 2); + if (parts.length < 2) { + list.addAll(getUsersByType(TaskAssigneeEnum.USER, List.of(Long.valueOf(parts[0])))); + } else { + list.addAll(getUsersByType(TaskAssigneeEnum.fromCode(parts[0] + StrUtil.COLON), List.of(Long.valueOf(parts[1])))); + } + } + return list; + } + + /** + * 根据指定的任务分配类型(TaskAssigneeEnum)和 ID 列表,获取对应的用户信息列表 + * + * @param type 任务分配类型,表示用户、角色、部门或其他(TaskAssigneeEnum 枚举值) + * @param ids 与指定分配类型关联的 ID 列表(例如用户ID、角色ID、部门ID等) + * @return 返回包含用户信息的列表。如果类型为用户(USER),则通过用户ID列表查询; + * 如果类型为角色(ROLE),则通过角色ID列表查询; + * 如果类型为部门(DEPT),则通过部门ID列表查询; + * 如果类型为岗位(POST)或无法识别的类型,则返回空列表 + */ + private List getUsersByType(TaskAssigneeEnum type, List ids) { + return switch (type) { + case USER -> userService.selectListByIds(ids); + case ROLE -> userService.selectUsersByRoleIds(ids); + case DEPT -> userService.selectUsersByDeptIds(ids); + case POST -> userService.selectUsersByPostIds(ids); + }; + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java new file mode 100644 index 0000000..2c43173 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java @@ -0,0 +1,188 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.event.ProcessDeleteEvent; +import org.dromara.common.core.domain.event.ProcessEvent; +import org.dromara.common.core.domain.event.ProcessTaskEvent; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.mapper.TestLeaveMapper; +import org.dromara.workflow.service.ITestLeaveService; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +/** + * 请假Service业务层处理 + * + * @author may + * @date 2023-07-21 + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +@Slf4j +public class TestLeaveServiceImpl implements ITestLeaveService { + + private final TestLeaveMapper baseMapper; + private final WorkflowService workflowService; + + /** + * 查询请假 + */ + @Override + public TestLeaveVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 查询请假列表 + */ + @Override + public TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询请假列表 + */ + @Override + public List queryList(TestLeaveBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TestLeaveBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getLeaveType()), TestLeave::getLeaveType, bo.getLeaveType()); + lqw.ge(bo.getStartLeaveDays() != null, TestLeave::getLeaveDays, bo.getStartLeaveDays()); + lqw.le(bo.getEndLeaveDays() != null, TestLeave::getLeaveDays, bo.getEndLeaveDays()); + lqw.orderByDesc(BaseEntity::getCreateTime); + return lqw; + } + + /** + * 新增请假 + */ + @Override + public TestLeaveVo insertByBo(TestLeaveBo bo) { + long day = DateUtil.betweenDay(bo.getStartDate(), bo.getEndDate(), true); + // 截止日期也算一天 + bo.setLeaveDays((int) day + 1); + TestLeave add = MapstructUtils.convert(bo, TestLeave.class); + if (StringUtils.isBlank(add.getStatus())) { + add.setStatus(BusinessStatusEnum.DRAFT.getStatus()); + } + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return MapstructUtils.convert(add, TestLeaveVo.class); + } + + /** + * 修改请假 + */ + @Override + public TestLeaveVo updateByBo(TestLeaveBo bo) { + TestLeave update = MapstructUtils.convert(bo, TestLeave.class); + baseMapper.updateById(update); + return MapstructUtils.convert(update, TestLeaveVo.class); + } + + /** + * 批量删除请假 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(List ids) { + workflowService.deleteInstance(ids); + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等) + * 正常使用只需#processEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processEvent 参数 + */ + @EventListener(condition = "#processEvent.flowCode.startsWith('leave')") + public void processHandler(ProcessEvent processEvent) { + log.info("当前任务执行了{}", processEvent.toString()); + TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId())); + testLeave.setStatus(processEvent.getStatus()); + // 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程 + Map params = processEvent.getParams(); + if (MapUtil.isNotEmpty(params)) { + // 历史任务扩展(通常为附件) + String hisTaskExt = Convert.toStr(params.get("hisTaskExt")); + // 办理人 + String handler = Convert.toStr(params.get("handler")); + // 办理意见 + String message = Convert.toStr(params.get("message")); + } + if (processEvent.isSubmit()) { + testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); + } + baseMapper.updateById(testLeave); + } + + /** + * 执行办理任务监听 + * 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断 + * 在方法中判断流程节点key + * if ("xxx".equals(processTaskEvent.getNodeCode())) { + * //执行业务逻辑 + * } + * + * @param processTaskEvent 参数 + */ + @EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave')") + public void processTaskHandler(ProcessTaskEvent processTaskEvent) { + log.info("当前任务执行了{}", processTaskEvent.toString()); + TestLeave testLeave = baseMapper.selectById(Long.valueOf(processTaskEvent.getBusinessId())); + testLeave.setStatus(BusinessStatusEnum.WAITING.getStatus()); + baseMapper.updateById(testLeave); + } + + /** + * 监听删除流程事件 + * 正常使用只需#processDeleteEvent.flowCode=='leave1' + * 示例为了方便则使用startsWith匹配了全部示例key + * + * @param processDeleteEvent 参数 + */ + @EventListener(condition = "#processDeleteEvent.flowCode.startsWith('leave')") + public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) { + log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString()); + TestLeave testLeave = baseMapper.selectById(Long.valueOf(processDeleteEvent.getBusinessId())); + if (ObjectUtil.isNull(testLeave)) { + return; + } + baseMapper.deleteById(testLeave.getId()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml new file mode 100644 index 0000000..d52f6b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/annotation/LogRecord.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/annotation/LogRecord.java new file mode 100644 index 0000000..16211b5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/annotation/LogRecord.java @@ -0,0 +1,13 @@ +package org.dromara.zhishu.annotation; + +import java.lang.annotation.*; + +/** + * 日志记录注解 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface LogRecord { + boolean logResult() default false; // 是否记录返回结果 +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/EmployeeController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/EmployeeController.java new file mode 100644 index 0000000..7ee27c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/EmployeeController.java @@ -0,0 +1,63 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.vo.EmployeeVo; +import org.dromara.zhishu.service.impl.EmployeeServiceImpl; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/employee/api") +public class EmployeeController { + + private final EmployeeServiceImpl employeeService; + + @SaIgnore + @GetMapping("/list") + public R> getEmployeeList() { + String userId = LoginHelper.getUserIdStr(); + List employeeList = employeeService.getEmployeeList(userId); + Map data = new HashMap<>(); + data.put("rows", employeeList); + data.put("total", employeeList.size()); + return R.ok("获取成功", data); + } + + @SaIgnore + @GetMapping("/add/{id}/{name}") + public R addEmployee(@PathVariable("id") String id, + @PathVariable("name") String name) { + String userId = LoginHelper.getUserIdStr(); + Boolean result = employeeService.addEmployee(id, name, userId); + return result ? R.ok() : R.fail(); + } + + @SaIgnore + @GetMapping("/update/{id}/{name}") + public R updateEmployee(@PathVariable("id") String id, + @PathVariable("name") String name) { + String userId = LoginHelper.getUserIdStr(); + Boolean result = employeeService.updateEmployee(id, name, userId); + return result ? R.ok() : R.fail(); + } + + + @SaIgnore + @GetMapping("/del/{id}") + public R delEmployee(@PathVariable("id") String id) { + String userId = LoginHelper.getUserIdStr(); + Boolean result = employeeService.delEmployee(id, userId); + return result ? R.ok() : R.fail(); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ErpGoodsOrderController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ErpGoodsOrderController.java new file mode 100644 index 0000000..8514fba --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ErpGoodsOrderController.java @@ -0,0 +1,320 @@ +package org.dromara.zhishu.controller; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.dtflys.forest.annotation.Post; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.zhishu.domain.ErpGoodsOrder; +import org.dromara.zhishu.domain.GoodsDto; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.bo.ErpGoodsOrderBo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.vo.ErpGoodsOrderVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.ITaskService; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.dromara.zhishu.util.DateUtilsUtils; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.MapUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 平台订单 + * + * @author yxy + * @date 2025-12-10 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/erpGoodsOrder") +public class ErpGoodsOrderController extends BaseController { + + private final ISysDictDataService dictDataService; + private final IShopService shopService; + private final ITaskService taskService; + private final IZhishuShopGoodsService zhishuShopGoodsService; + + /** + * 查询平台订单列表 + */ + @SaCheckPermission("zhishu:erpGoodsOrder:list") + @GetMapping("/list") + public TableDataInfo list(ErpGoodsOrderBo bo, PageQuery pageQuery) { + Map params = new HashMap<>(); + params.put("pageNum",pageQuery.getPageNum()); + params.put("pageSize",pageQuery.getPageSize()); + + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + params.put("createdBy",userId); + } + + if (bo.getOrderStatus() != null){ + params.put("orderStatus",bo.getOrderStatus()); + } + + if (bo.getConfirmStatus() != null){ + params.put("confirmStatus",bo.getConfirmStatus()); + } + + if (bo.getAfterSalesStatus() != null){ + params.put("afterSalesStatus",bo.getAfterSalesStatus()); + } + + if (bo.getShopType() != null){ + params.put("shopType",bo.getShopType()); + } + + if (bo.getTrackingNumber() != null){ + params.put("trackingNumber",bo.getTrackingNumber()); + } + if (StringUtils.isNotEmpty(bo.getOrderSn())){ + params.put("orderSn",bo.getOrderSn()); + } + if (bo.getShopErpId() != null){ + params.put("shopErpId",bo.getShopErpId()); + } + if (StringUtils.isNotEmpty(bo.getItemList())){ + params.put("itemList",bo.getItemList()); + } + if(!bo.getParams().isEmpty()){ + params.put("startTime",bo.getParams().get("startTime")); + params.put("endTime",bo.getParams().get("endTime")); + } + String OrderExternalGoodsVoListStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/getListPage",params); + Map dataMap = JsonUtil.transferToObj(OrderExternalGoodsVoListStr,Map.class); + List orderExternalGoodsVoList = (List) dataMap.get("data"); + for (Object object : orderExternalGoodsVoList){ + Map orderExternalGoodsVo = (Map) object; + String erpGoodsId = orderExternalGoodsVo.get("erpGoodsId") == null ? "" : orderExternalGoodsVo.get("erpGoodsId").toString(); + + if (StringUtils.isNotEmpty(erpGoodsId)){ + // 获取货号 + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.queryById(erpGoodsId); + System.out.println(zhishuShopGoodsVo); + if (zhishuShopGoodsVo != null){ + orderExternalGoodsVo.put("artNo",zhishuShopGoodsVo.getArtNo()); + orderExternalGoodsVo.put("originalArtNo",zhishuShopGoodsVo.getOriginalArtNo()); + }else{ + orderExternalGoodsVo.put("artNo",""); + orderExternalGoodsVo.put("originalArtNo",""); + } + } + + } + int total = (int) dataMap.get("total"); + Page result = new Page<>(pageQuery.getPageNum(),pageQuery.getPageSize(),total); + result.setRecords(orderExternalGoodsVoList); + return TableDataInfo.build(result); + } + + /** + * 匹配商品 + * @return + */ + @GetMapping("/matchGoods") + public List matchGoods(String orderId){ + String matchGoodsStr = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/getZhishuShopGoods?orderId="+orderId); + List matchGoodsList = JsonUtil.transferToObj(matchGoodsStr,List.class); + return matchGoodsList; + } + + @PostMapping("/submitIssue") + public Map submitIssue(@RequestBody Map data){ + String log = InterfaceUtils.getInterfacePost(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/externalOrderOperation",data); + Map map = new HashMap(); + map.put("code",200); + if(log.contains("已执行商品库存扣减并执行库存同步")){ + map.put("msg","下发成功"); + }else{ + map.put("msg",log); + } + return map; + } + + @GetMapping("/getErpOrderLog") + public List getErpOrderLog(String orderNo){ + String erpOrderLogListStr = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/getErpOrderLog?orderNo="+orderNo); + List erpOrderLogList = JsonUtil.transferToObj(erpOrderLogListStr,List.class); + return erpOrderLogList; + } + + /** + * 添加线下订单 + * @param erpGoodsOrder + * @return + */ + @PostMapping("/addErpGoodsOrder") + @SaIgnore + public R addErpGoodsOrder(@RequestBody ErpGoodsOrder erpGoodsOrder){ + Long userId = erpGoodsOrder.getCreatedBy() == null ? LoginHelper.getUserId() : erpGoodsOrder.getCreatedBy(); +// System.out.println(erpGoodsOrder); + //生成订单 + for (ZhishuShopGoodsVo zhishuShopGoods : erpGoodsOrder.getZhishuShopGoodsList()){ + ErpGoodsOrder order = new ErpGoodsOrder(); + order.setOrderSn(erpGoodsOrder.getOrderSn()); + //99 代表自营书品 + order.setShopType(99L); + order.setShopId(99L); + order.setShopErpId(99L); + order.setShopErpName("线下订单"); + GoodsDto goodsDto = new GoodsDto(); + // 商品编号 + goodsDto.setGoodsId(zhishuShopGoods.getId()); + // 商品名称 + goodsDto.setGoodsName(zhishuShopGoods.getGoodsName()); + // 商品数量 + goodsDto.setGoodsCount(zhishuShopGoods.getUpdateInventory()); + // 商品销售价格 + goodsDto.setGoodsPrice(zhishuShopGoods.getPrice().toString()); + // 商品规格 + goodsDto.setGoodsSpec(""); + // 商品图片 + List goodsImgs = new ArrayList<>(); + goodsImgs.add(zhishuShopGoods.getBookPic()); + goodsDto.setGoodsImgs(goodsImgs); + // 商家外部编码 + goodsDto.setOuterGoodsId(zhishuShopGoods.getArtNo()); + // 闲管家商品id + goodsDto.setOuterId(""); + // 规格编码 + goodsDto.setSkuId(""); + order.setItemList(JsonUtil.transferToJson(goodsDto)); + // 金额 + if(erpGoodsOrder.getPayAmount() != null){ + Long payAmount = new BigDecimal(erpGoodsOrder.getPayAmount()).multiply(new BigDecimal(100)).longValue(); + order.setOrderTotal(payAmount); + order.setGoodsAmount(payAmount); + order.setPayAmount(payAmount); + } + order.setCreatedBy(userId); + + //省 + if (StringUtils.isNotEmpty(erpGoodsOrder.getProvince())){ + order.setProvince(erpGoodsOrder.getProvince()); + } + //市 + if (StringUtils.isNotEmpty(erpGoodsOrder.getCity())){ + order.setCity(erpGoodsOrder.getCity()); + } + // 收件地国家或地区 + if (StringUtils.isNotEmpty(erpGoodsOrder.getCountry())){ + order.setCountry(erpGoodsOrder.getCountry()); + } + // 区县 + if (StringUtils.isNotEmpty(erpGoodsOrder.getTown())){ + order.setTown(erpGoodsOrder.getTown()); + } + //订单状态 + order.setOrderStatus(6L); + //售后状态 + order.setAfterSalesStatus(0L); + //成交状态 + order.setConfirmStatus(1L); + //手续费 + order.setShippingAt(0L); + //下发状态 + order.setIsIssue(1L); + //是否可视化 + order.setIsShow(0L); + int inventory = new BigDecimal(zhishuShopGoods.getInventory()).subtract(new BigDecimal(zhishuShopGoods.getUpdateInventory())).intValue(); + Map map = new HashMap(); + map.put("erpGoodsOrderStr",JsonUtil.transferToJson(order)); + String result = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/addErpGoodsOrder",map); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + Map dataMap = (Map) resultMap.get("data"); + Map synchronizeStockMap = new HashMap(); + synchronizeStockMap.put("shopGoodsId",zhishuShopGoods.getId()); + synchronizeStockMap.put("erpOrderId",dataMap.get("id").toString()); + synchronizeStockMap.put("inventory",inventory + ""); + InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/synchronizeStock",synchronizeStockMap); + } + return R.ok(); + } + + + /** + * 生成仓库订单售后 + * @param erpGoodsOrder + * @return + */ + @PostMapping("/submitAfterSales") + public R submitAfterSales(@RequestBody ErpGoodsOrder erpGoodsOrder){ + + Map map = new HashMap(); + + String erpAssReason; + if(!erpGoodsOrder.getErpAssReason().equals("99")){ + erpAssReason = dictDataService.selectDictLabel("t_after_sales_reason",erpGoodsOrder.getErpAssReason()); + }else{ + erpAssReason = "其他原因:"+erpGoodsOrder.getErpAssReasonOther(); + } + + erpGoodsOrder.setErpAssReason(erpAssReason); + + map.put("id",erpGoodsOrder.getId().toString()); + map.put("erpAfterSalesStatus",erpGoodsOrder.getErpAfterSalesStatus() + ""); + map.put("erpAssReason",erpGoodsOrder.getErpAssReason()); + map.put("erpAssRemark",erpGoodsOrder.getErpAssRemark()); + + String result = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/submitAfterSales", map); + + System.out.println(result); + + return R.ok(); + } + + /** + * 手动订单库存同步操作 + */ + @PostMapping("/manualOrder") + public R manualOrder(String shopIds){ + String startDate = DateUtilsUtils.getDateTimeWithOffset(-1); + String endDate = DateUtilsUtils.getDateTimeWithOffset(0); + String[] shopIdsArr = shopIds.split(","); + for (String shopId : shopIdsArr){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + // 存储任务信息 + taskBo.setTaskType("MANUAL_ORDER"); + taskBo.setFileName("手动订单同步库存任务"); + taskBo.setShopIds(shopVo.getId().toString()); // 只设置单个 shopId + taskBo.setShopNames(shopVo.getShopName()); // 只设置单个 shopName + taskBo.setDataNum(0L); // 单个店铺的数据量(不需要乘以店铺数量) + taskBo.setTaskStatus("0"); + taskBo.setCreateBy(shopVo.getCreateBy()); + taskService.insertByBo(taskBo); + Map params = new HashMap(); + params.put("shopId",shopVo.getId().toString()); + params.put("taskId",taskBo.getId().toString()); + params.put("startUpdateTime",startDate); + params.put("endUpdateTime",endDate); + String result = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/manualOrder",params); + } + + return R.ok("任务创建成功"); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/FastMailController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/FastMailController.java new file mode 100644 index 0000000..934fb45 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/FastMailController.java @@ -0,0 +1,216 @@ +package org.dromara.zhishu.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.pdd.pop.sdk.common.util.JsonUtil; +import com.pdd.pop.sdk.http.PopClient; +import com.pdd.pop.sdk.http.PopHttpClient; +import com.pdd.pop.sdk.http.api.pop.request.PddLogisticsCompaniesGetRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddLogisticsCompaniesGetResponse; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.vo.FastMailVo; +import org.dromara.zhishu.domain.bo.FastMailBo; +import org.dromara.zhishu.service.IFastMailService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 快递打单账号管理 + * + * @author yxy + * @date 2025-06-06 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/fastMail") +public class FastMailController extends BaseController { + + private final IFastMailService fastMailService; + private final IShopService shopService; + private final ISysDictDataService dictDataService; + + /** + * 查询快递打单账号管理列表 + */ + @SaCheckPermission("zhishu:fastMail:list") + @GetMapping("/list") + public TableDataInfo list(FastMailBo bo, PageQuery pageQuery) { + return fastMailService.queryPageList(bo, pageQuery); + } + + @SaCheckPermission("zhishu:fastMail:list") + @GetMapping("/listNoPage") + public List listNoPage(FastMailBo bo) { + return fastMailService.queryList(bo); + } + + + @SaIgnore + @GetMapping("/listApi") + public R> listApi(Long shopId) { + if (shopId == null){ + return R.fail("shopId不能为空"); + } + ShopVo shopVo = shopService.queryById(shopId); + if (shopVo == null){ + return R.fail("未获取到列表信息"); + } + return R.ok(fastMailService.queryListApi(shopVo.getCreateBy())); + } + + /** + * 导出快递打单账号管理列表 + */ + @SaCheckPermission("zhishu:fastMail:export") + @Log(title = "快递打单账号管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FastMailBo bo, HttpServletResponse response) { + List list = fastMailService.queryList(bo); + ExcelUtil.exportExcel(list, "快递打单账号管理", FastMailVo.class, response); + } + + /** + * 获取快递打单账号管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:fastMail:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(fastMailService.queryById(id)); + } + + /** + * 新增快递打单账号管理 + */ + @SaCheckPermission("zhishu:fastMail:add") + @Log(title = "快递打单账号管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FastMailBo bo) { + return fastMailService.insertByBo(bo); + } + + /** + * 修改快递打单账号管理 + */ + @SaCheckPermission("zhishu:fastMail:edit") + @Log(title = "快递打单账号管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FastMailBo bo) { + return fastMailService.updateByBo(bo); + } + + /** + * 删除快递打单账号管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:fastMail:remove") + @Log(title = "快递打单账号管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(fastMailService.deleteWithValidByIds(List.of(ids), true)); + } + + @GetMapping("/getPddFastMail") + public R getPddFastMail(String shopId){ + ShopVo shop = shopService.queryById(Long.parseLong(shopId)); + Map params = new HashMap(); + params.put("shopType",shop.getShopType()); + params.put("token", shop.getToken()); + String res = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/getFastMail", params); + if(res.contains("已过期")){ + R.fail("店铺已过期,请重新授权"); + } + Map resMap = JsonUtil.transferToObj(res, Map.class); + Map pddWaybillSearchResponse = (Map) resMap.get("pdd_waybill_search_response"); + if (pddWaybillSearchResponse != null){ + // 清空当前用户下的所有拼多多面单 + fastMailService.deleteByFastMailType(LoginHelper.getUserId(),"2"); + // 快递列表 + List waybillApplySubscriptionCols = (List) pddWaybillSearchResponse.get("waybill_apply_subscription_cols"); + for (int i = 0; i < waybillApplySubscriptionCols.size(); i++){ + // 快递数据 + Map waybillApplySubscriptionCol = (Map) waybillApplySubscriptionCols.get(i); + // 快递类型 + String wpCode = (String) waybillApplySubscriptionCol.get("wp_code"); + // 快递网点列表 + List branchAccountCols = (List) waybillApplySubscriptionCol.get("branch_account_cols"); + for (int j = 0; j < branchAccountCols.size(); j++){ + // 网点数据 + Map branchAccountCol = (Map) branchAccountCols.get(j); + String branchCode = ""; + String branchName = ""; + if (wpCode.equals("YZXB")){ + branchName = "中国邮政"; + }else{ + // 网点Code + branchCode = branchAccountCol.get("branch_code").toString(); + // 网点名称 + branchName = branchAccountCol.get("branch_name").toString(); + } + + // 已用面单数量 + String allocatedQuantity = branchAccountCol.get("allocated_quantity").toString(); + // 取消面单数量 + String cancelQuantity = branchAccountCol.get("cancel_quantity").toString(); + // 电子面单余额数量 + String quantity = branchAccountCol.get("quantity").toString(); + // 已回收用面单数量 + String recycledQuantity = branchAccountCol.get("recycled_quantity").toString(); + List shippAddressCols = (List) branchAccountCol.get("shipp_address_cols"); + for (int k = 0; k < shippAddressCols.size(); k++){ + // 当前网点下的发货地址 + Map shippAddressCol = (Map) shippAddressCols.get(k); + // 封装数据 + shippAddressCol.put("branchCode", branchCode); + shippAddressCol.put("branchName", branchName); + shippAddressCol.put("allocatedQuantity", allocatedQuantity); + shippAddressCol.put("cancelQuantity", cancelQuantity); + shippAddressCol.put("quantity", quantity); + shippAddressCol.put("recycledQuantity", recycledQuantity); + shippAddressCol.put("mallId",shop.getMallId().toString()); + shippAddressCol.put("token", shop.getToken()); + FastMailBo fastMailBo = new FastMailBo(); + fastMailBo.setType(wpCode); + fastMailBo.setFastMailType("2"); + fastMailBo.setPartnerId(branchName); + fastMailBo.setRemark(JsonUtil.transferToJson(shippAddressCol)); + fastMailService.insertByBo(fastMailBo); + } + } + } + } + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/GoodsAutoFailController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/GoodsAutoFailController.java new file mode 100644 index 0000000..b956cc3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/GoodsAutoFailController.java @@ -0,0 +1,105 @@ +package org.dromara.zhishu.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.vo.GoodsAutoFailVo; +import org.dromara.zhishu.domain.bo.GoodsAutoFailBo; +import org.dromara.zhishu.service.IGoodsAutoFailService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 自动发布失败 + * + * @author yxy + * @date 2025-09-29 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/goodsAutoFail") +public class GoodsAutoFailController extends BaseController { + + private final IGoodsAutoFailService goodsAutoFailService; + + /** + * 查询自动发布失败列表 + */ + @SaCheckPermission("zhishu:goodsAutoFail:list") + @GetMapping("/list") + public TableDataInfo list(GoodsAutoFailBo bo, PageQuery pageQuery) { + return goodsAutoFailService.queryPageList(bo, pageQuery); + } + + /** + * 导出自动发布失败列表 + */ + @SaCheckPermission("zhishu:goodsAutoFail:export") + @Log(title = "自动发布失败", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(GoodsAutoFailBo bo, HttpServletResponse response) { + List list = goodsAutoFailService.queryList(bo); + ExcelUtil.exportExcel(list, "自动发布失败", GoodsAutoFailVo.class, response); + } + + /** + * 获取自动发布失败详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:goodsAutoFail:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(goodsAutoFailService.queryById(id)); + } + + /** + * 新增自动发布失败 + */ + @SaCheckPermission("zhishu:goodsAutoFail:add") + @Log(title = "自动发布失败", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody GoodsAutoFailBo bo) { + return toAjax(goodsAutoFailService.insertByBo(bo)); + } + + /** + * 修改自动发布失败 + */ + @SaCheckPermission("zhishu:goodsAutoFail:edit") + @Log(title = "自动发布失败", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody GoodsAutoFailBo bo) { + return toAjax(goodsAutoFailService.updateByBo(bo)); + } + + /** + * 删除自动发布失败 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:goodsAutoFail:remove") + @Log(title = "自动发布失败", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(goodsAutoFailService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ImageController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ImageController.java new file mode 100644 index 0000000..961e745 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ImageController.java @@ -0,0 +1,107 @@ +package org.dromara.zhishu.controller; + + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.util.AliOssUtils; +import org.dromara.zhishu.util.FileUtil; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UploadUtil; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.HashMap; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/image") +public class ImageController { + + private final ISysConfigService configService; + + @GetMapping("/getImage") + public String getImage(String fileName){ + return AliOssUtils.getImagePath(fileName); + } + + /** + * 用于获取中心书库图片,根据书名进行MD5加密生成文件夹 + * bookInfoImages 为固定文件夹 + * @param fileName + * @param bookName + * @return + */ + @GetMapping("/getImageMd5") + public String getImageMd5(String fileName,String bookName){ + String result = UploadUtil.getMd5FirstChart(bookName); + fileName = "bookInfoImages/"+result+"/"+fileName; + return AliOssUtils.getImagePath(fileName); + } + + @PostMapping(value = "/shopDetailUpload") + public R shopDetailUpload(@RequestPart("file") MultipartFile file) { + return imageInPdd(file); + } + + @PostMapping(value = "/specUpload") + public R specUpload(@RequestPart("file") MultipartFile file) { + return imageInPdd(file); + } + + @PostMapping("/zhishuShopGoodsImageUpload") + public R zhishuShopGoodsImageUpload(@RequestParam("file") MultipartFile file) { + return imageInPdd(file); + } + + @PostMapping("/userUpload") + public R userUpload(@RequestParam("file") MultipartFile file) { + return imageInPdd(file); + } + + + public R imageInPdd(MultipartFile file){ + String accessToken = configService.selectConfigByKey("image.token"); + + Resource fileResource = null; + try{ + fileResource = new ByteArrayResource(file.getBytes()) { + @Override + public String getFilename() { + return file.getOriginalFilename(); + } + }; + } catch (Exception e) { + throw new RuntimeException(e); + } + + Map pddMap = new HashMap(); + pddMap.put("token",accessToken); + pddMap.put("file",fileResource); + + Map map = InterfaceUtils.postFormObject("http://175.27.224.66:8069", "/upload", pddMap); + + if(map.get("message").toString().contains("上传成功")){ + String imageUrl = map.get("image_url").toString(); + String serviceUrl = map.get("service_url").toString(); + if(serviceUrl.contains("https://")){ + map.put("url",serviceUrl); + }else if(imageUrl.contains("https://")){ + String pddImage = InterfaceUtils.getInterface("http://175.27.224.66:8070","/upload?token="+accessToken+"&imageURL="+imageUrl); + //调用pdd图片上传接口 + map.put("url",pddImage); + }else{ + map.put("message","图片上传失败"); + } + } + + return R.ok(map); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/KongfzShopController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/KongfzShopController.java new file mode 100644 index 0000000..2b2e137 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/KongfzShopController.java @@ -0,0 +1,240 @@ +package org.dromara.zhishu.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import kotlin.Result; +import org.apache.poi.hpsf.Decimal; +import org.dromara.zhishu.domain.dto.KongfzRequestDto; +import org.dromara.zhishu.service.impl.KongfzItemService; +import org.dromara.zhishu.util.HttpUtils; +import org.dromara.zhishu.util.KongfzApiUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/kongfz/shop") +public class KongfzShopController { + + private static final String API_URL = "https://api.kongfz.com/router/rest"; + @Value("${kongfz.appId}") + private String appId; + @Value("${kongfz.appSecret}") + private String appSecret; + @Value("${kongfz.accessToken}") + private String accessToken; + + @Autowired + private KongfzItemService kongfzItemService; + /** + * 获取店铺基本信息 + */ + @PostMapping("/shopInfo/get") + public String getShopInfo()throws Exception{ + Map params = new HashMap<>(); + params.put("method","kongfz.shop.simple.get"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("signMethod","md5"); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.getShopInfo(params); + } + /** + * 上架商品 + * @param itemId + * @return + */ + @PostMapping("/item/listing") + public String listingItem(@RequestParam Integer itemId) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.listing"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("signMethod","md5"); + params.put("itemId",String.valueOf(itemId)); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.listing(params); + } + + /** + * 下架商品 + */ + @PostMapping("/item/delisting") + public String delistingItem(@RequestParam Integer itemId) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.listing"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("signMethod","md5"); + params.put("itemId",String.valueOf(itemId)); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.delisting(params); + } + + /** + * 查询店铺商品列表 + */ + @PostMapping("/item/list") + public String list(@RequestParam Integer itemId) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.list"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("signMethod","md5"); + params.put("itemId",String.valueOf(itemId)); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.shopList(params); + } + + /** + * 修改商品库存 + */ + @PostMapping("/item/number/update") + public String numberUpdate(@RequestParam Integer itemId,@RequestParam Integer number) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.number.update"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("itemId",String.valueOf(itemId)); + params.put("number",String.valueOf(number)); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.updateItemNumber(params); + } + + /** + * 修改商品价格 + */ + @PostMapping("/item/price/update") + public String priceUpdate(@RequestParam Integer itemId,@RequestParam Integer price,@RequestParam Integer discount) throws Exception { + Map params = new HashMap<>(); + params.put("mthod","kongfz.shop.item.price.update"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("itemId",String.valueOf(itemId)); + params.put("price",String.valueOf(price)); + params.put("discount",String.valueOf(discount)); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.updateItemPrice(params); + } + + /** + * 修改商品名称 + */ + @PostMapping("/item/itemName/update") + public String itemNameUpdate(@RequestParam Integer itemId,@RequestParam String itemName) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.itemname.update"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("itemId",String.valueOf(itemId)); + params.put("itemName",itemName); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.updateItemName(params); + } + + /** + * 修改商品货号 + */ + @PostMapping("/item/itemsn/update") + public String itemsnUpdate(@RequestParam Integer itemId,@RequestParam String itemsn) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.itemsn.update"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("itemId",String.valueOf(itemId)); + params.put("itemsn",itemsn); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.updateItemsn(params); + } + + /** + * 删除商品到回收站 + */ + @PostMapping("/item/delete") + public String delete(@RequestParam Integer itemId) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.delete"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("itemId",String.valueOf(itemId)); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.deleteItem(params); + } + + /** + * 添加批量删除商品任务 + */ + @PostMapping("/item/batch/delete") + public String batchDelete(@RequestParam Integer itemId) throws Exception { + Map params = new HashMap<>(); + params.put("method","kongfz.shop.item.batch.delete"); + params.put("datetime",KongfzApiUtils.getCurrentDateTime()); + params.put("appId",appId); + params.put("appSecret",appSecret); + params.put("accessToken",accessToken); + params.put("v","1.0"); + params.put("itemId",String.valueOf(itemId)); + String sign = KongfzApiUtils.generateSign(params,"secret_key"); + params.put("sign",sign); + params.put("simplify","0"); + return kongfzItemService.batchDeleteItem(params); + } + + + + + + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PriceTemplateController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PriceTemplateController.java new file mode 100644 index 0000000..815c81c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PriceTemplateController.java @@ -0,0 +1,160 @@ +package org.dromara.zhishu.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.zhishu.domain.dto.request.CalculatePriceByTemplateRequest; +import org.dromara.zhishu.domain.dto.response.CalculatePriceByTemplateResponse; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IShopDetailService; +import org.dromara.zhishu.service.IShopService; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.vo.PriceTemplateVo; +import org.dromara.zhishu.domain.bo.PriceTemplateBo; +import org.dromara.zhishu.service.IPriceTemplateService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 价格模板 + * + * @author yxy + * @date 2025-03-17 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/priceTemplate") +public class PriceTemplateController extends BaseController { + + private final IPriceTemplateService priceTemplateService; + + private final IShopDetailService shopDetailService; + + private final IShopService shopService; + + /** + * 查询价格模板列表 + */ + @SaCheckPermission("zhishu:priceTemplate:list") + @GetMapping("/list") + public TableDataInfo list(PriceTemplateBo bo, PageQuery pageQuery) { + return priceTemplateService.queryPageList(bo, pageQuery); + } + + @SaCheckPermission("zhishu:priceTemplate:list") + @GetMapping("/listNoPage") + public List listNoPage(PriceTemplateBo bo) { + return priceTemplateService.queryList(bo); + } + + @GetMapping("/getPriceTemplateByShopId") + @SaIgnore + public Map getPriceTemplateByShopId(Long shopId) { + + ShopVo shopVo = shopService.queryById(shopId); + ShopDetailVo shopDetailVo = shopDetailService.queryByShopId(shopId); + Map map = new HashMap(); + if(shopDetailVo.getSaleTemplateId() == null){ + map.put("code","500"); + map.put("msg","店铺未设置价格模板"); + return map; + } + PriceTemplateVo priceTemplateVo = priceTemplateService.queryById(shopDetailVo.getSaleTemplateId()); + + if(priceTemplateVo == null){ + map.put("code","500"); + map.put("msg","未查询到店铺价格模板"); + return map; + } + map.put("code","200"); + map.put("msg","查询成功"); + map.put("data",priceTemplateVo); + map.put("token",shopVo.getToken()); + return map; + } + + /** + * 导出价格模板列表 + */ + @SaCheckPermission("zhishu:priceTemplate:export") + @Log(title = "价格模板", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PriceTemplateBo bo, HttpServletResponse response) { + List list = priceTemplateService.queryList(bo); + ExcelUtil.exportExcel(list, "价格模板", PriceTemplateVo.class, response); + } + + /** + * 获取价格模板详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:priceTemplate:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(priceTemplateService.queryById(id)); + } + + /** + * 新增价格模板 + */ + @SaCheckPermission("zhishu:priceTemplate:add") + @Log(title = "价格模板", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody PriceTemplateBo bo) { + return toAjax(priceTemplateService.insertByBo(bo)); + } + + /** + * 修改价格模板 + */ + @SaCheckPermission("zhishu:priceTemplate:edit") + @Log(title = "价格模板", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody PriceTemplateBo bo) { + return toAjax(priceTemplateService.updateByBo(bo)); + } + + /** + * 删除价格模板 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:priceTemplate:remove") + @Log(title = "价格模板", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(priceTemplateService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 按照价格模板计算价格 + */ + @SaIgnore + @PostMapping("/calculatePriceByTemplate") + public R> calculatePriceByTemplate(@NotEmpty(message = "价格计算请求不能为空") @RequestBody List requests) { + List list = priceTemplateService.getPriceByPlatformId(requests); + return R.ok(list); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ServiceController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ServiceController.java new file mode 100644 index 0000000..d10c6c6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ServiceController.java @@ -0,0 +1,148 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.dtflys.forest.annotation.Post; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.mapper.SysUserRoleMapper; +import org.dromara.system.service.ISysRoleService; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.zhishu.domain.vo.UserRechargeVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.IUserRechargeService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * 订阅服务控制层 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/service") +public class ServiceController { + + private final IShopService shopService; + + private final IUserRechargeService userRechargeService; + + private final ISysRoleService sysRoleService; + + private final SysUserRoleMapper sysUserRoleMapper; + + + @GetMapping("/getAllServices") + public Map getAllServices(String type){ + String result = InterfaceUtils.getInterface(UrlUtil.getServiceGoUrl(),"/api/getAllServices?type="+type); + Map map = JsonUtil.transferToObj(result, Map.class); + return map; + } + + /** + * 订阅服务成功 + * @param wxPayOrderId 微信支付订单id + * @param shopId 店铺id + * @param serviceId 订阅服务id + * @param type 服务类型 + * @return + */ + @PostMapping("/payServiceSuccess") + public R payServiceSuccess(String wxPayOrderId,String shopId,String serviceId,String type){ + + ShopBo shopBo = new ShopBo(); + shopBo.setId(Long.parseLong(shopId)); + shopBo.setIsExpiration("1"); + shopService.updateByBo(shopBo); + //获取微信订单信息 + UserRechargeVo userRechargeVo = userRechargeService.queryById(Long.parseLong(wxPayOrderId)); + + //创建订单信息 + Map createOrderMap = new HashMap(); + + createOrderMap.put("orderType",type); + createOrderMap.put("userId",shopId); + createOrderMap.put("goodsId",serviceId); + createOrderMap.put("count","1"); + + String result = InterfaceUtils.postForm(UrlUtil.getServiceGoUrl(),"/api/orders/createOrder",createOrderMap); + + Map resultMap = JsonUtil.transferToObj(result, Map.class); + + Map dataMap = (Map) resultMap.get("data"); + + String orderId = dataMap.get("orderId").toString(); + + //调用订单付款接口 + Map orderForPay = new HashMap(); + orderForPay.put("orderId",orderId); + orderForPay.put("userId",shopId); + orderForPay.put("orderInfo",userRechargeVo.getAllDataStr()); + + InterfaceUtils.postForm(UrlUtil.getServiceGoUrl(),"/api/orders/orderForPay",orderForPay); + + return R.ok(); + } + + /** + * 咸鱼功能订阅成功 + */ + @PostMapping("/payServiceXySuccess") + public R payServiceXySuccess(String wxPayOrderId){ + //获取当前用户 + String userId = LoginHelper.getUserId().toString(); + //获取权限用户 + SysRoleBo roleBo = new SysRoleBo(); + roleBo.setRoleKey("xyRoot"); + SysRoleVo roleVo = sysRoleService.selectRoleList(roleBo).get(0); + //给这个用户增加角色 + sysUserRoleMapper.insertUserRole(Long.parseLong(userId), roleVo.getRoleId()); + + /** + * 修改缓存数据 + */ + LoginUser loginUser = LoginHelper.getLoginUser(); + loginUser.getMenuPermission().add("zhishu:shop:xy"); + LoginHelper.editLoginUser(loginUser); + + //获取微信订单信息 + UserRechargeVo userRechargeVo = userRechargeService.queryById(Long.parseLong(wxPayOrderId)); + + //创建订单信息 + Map createOrderMap = new HashMap(); + + createOrderMap.put("orderType","xyRoot"); + createOrderMap.put("userId",userId); + createOrderMap.put("goodsId","83"); + createOrderMap.put("count","1"); + + String result = InterfaceUtils.postForm(UrlUtil.getServiceGoUrl(),"/api/orders/createOrder",createOrderMap); + + Map resultMap = JsonUtil.transferToObj(result, Map.class); + + Map dataMap = (Map) resultMap.get("data"); + + String orderId = dataMap.get("orderId").toString(); + + //调用订单付款接口 + Map orderForPay = new HashMap(); + orderForPay.put("orderId",orderId); + orderForPay.put("userId",userId); + orderForPay.put("orderInfo",userRechargeVo.getAllDataStr()); + InterfaceUtils.postForm(UrlUtil.getServiceGoUrl(),"/api/orders/orderForPay",orderForPay); + + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsController.java new file mode 100644 index 0000000..3ff1180 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsController.java @@ -0,0 +1,99 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.pdd.pop.sdk.common.util.JsonUtil; +import com.pdd.pop.sdk.common.util.StringUtils; +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.domain.dto.ShopGoodsDto; +import org.dromara.zhishu.domain.dto.TShopGoodsPublishedDto; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.ShopGoodsService; +import org.dromara.zhishu.service.TShopGoodsPublishedService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 新入库系统存入店铺表 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/filterSet") +public class ShopGoodsController { + + private final ShopGoodsService shopGoodsService; + private final IShopService shopService; + private final TShopGoodsPublishedService tShopGoodsPublishedService; + + @PostMapping("/save") + @SaIgnore + public Map save(String data) { + + Map dataMap = JsonUtil.transferToObj(data, Map.class); + String shopIds = dataMap.get("shopIds").toString(); + List shopGoodsDtoList = (List) dataMap.get("data"); + String msg = ""; + String[] shopIdArr = shopIds.split(","); + for (String shopId : shopIdArr) { + if (StringUtils.isEmpty(shopId)) { + continue; + } + Long erpShopIdLong = Long.parseLong(shopId); + // 1. 处理原商品表 + String tableName = "t_shop_goods_" + shopId; + Boolean bool = shopGoodsService.checkTableExists(tableName); + if (!bool) { + shopGoodsService.createTable(tableName); + } + // 插入原始数据 + int successNum = shopGoodsService.batchInsert(tableName, shopGoodsDtoList); + // 查询店铺信息 + ShopVo shopVo = shopService.queryById(erpShopIdLong); + // 整合新表数据 + List publishedList = new ArrayList<>(); + for (Map goodsMap : shopGoodsDtoList) { + TShopGoodsPublishedDto publishedDto = new TShopGoodsPublishedDto(); + // 设置店铺相关字段 + publishedDto.setShopId(shopVo.getMallId()); + publishedDto.setShopName(shopVo.getShopAliasName()); + publishedDto.setErpShopId(shopVo.getId()); + publishedDto.setErpShopName(shopVo.getShopName()); + // 解析 productId + Long productId = Long.parseLong(goodsMap.get("productId").toString()); + publishedDto.setProductId(productId); + // 解析 warehouse_id + Long warehouseId = Long.parseLong(goodsMap.get("warehouseId").toString()); + publishedDto.setWarehouseId(warehouseId); + Long trilateralId = Long.parseLong(goodsMap.get("trilateralId").toString()); + publishedDto.setTrilateralId(trilateralId); + + publishedList.add(publishedDto); + + } + // 5. 批量插入新表 + if (!publishedList.isEmpty()) { + int publishedSuccessNum = tShopGoodsPublishedService.batchInsert(publishedList); + msg += "店铺:" + shopId + + "; 原始表插入成功:" + successNum + + "; 总接收条数:" + shopGoodsDtoList.size() + + "; 发布表插入成功:" + publishedSuccessNum + + "; 有效数据:" + publishedList.size() + ";"; + } else { + msg += "店铺:" + shopId + + "; 原始表插入成功:" + successNum + + "; 总接收条数:" + shopGoodsDtoList.size() + + "; 发布表无有效数据;"; + } + } + Map map = new HashMap(); + map.put("code", "200"); + map.put("msg", msg); + return map; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopImgController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopImgController.java new file mode 100644 index 0000000..58c7cf0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopImgController.java @@ -0,0 +1,121 @@ +package org.dromara.zhishu.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.zhishu.util.AliOssUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.vo.ShopImgVo; +import org.dromara.zhishu.domain.bo.ShopImgBo; +import org.dromara.zhishu.service.IShopImgService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 店铺图片 + * + * @author yxy + * @date 2025-03-17 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopImg") +public class ShopImgController extends BaseController { + + private final IShopImgService shopImgService; + + /** + * 查询店铺图片列表 + */ + @GetMapping("/list") + public TableDataInfo list(ShopImgBo bo, PageQuery pageQuery) { + return shopImgService.queryPageList(bo, pageQuery); + } + + /** + * 根据店铺id获取店铺图片 + * @param bo + * @return + */ + @GetMapping("/listByPid/{pid}") + public R> listByPid(@PathVariable Long pid){ + ShopImgBo bo = new ShopImgBo(); + bo.setPid(pid); + List shopImgVoList = shopImgService.queryList(bo); +// for(ShopImgVo shopImgVo : shopImgVoList){ +// shopImgVo.setAbsolutePath(AliOssUtils.getImagePath(shopImgVo.getAbsolutePath())); +// } + return R.ok(shopImgVoList); + } + + /** + * 导出店铺图片列表 + */ + @Log(title = "店铺图片", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ShopImgBo bo, HttpServletResponse response) { + List list = shopImgService.queryList(bo); + ExcelUtil.exportExcel(list, "店铺图片", ShopImgVo.class, response); + } + + /** + * 获取店铺图片详细信息 + * + * @param id 主键 + */ + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(shopImgService.queryById(id)); + } + + /** + * 新增店铺图片 + */ + @Log(title = "店铺图片", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ShopImgBo bo) { + Boolean bool = shopImgService.insertByBo(bo); + if (bool){ + return R.ok(bo); + }else{ + return R.fail("上传图片失败,请刷新页面重新上传"); + } + } + + /** + * 修改店铺图片 + */ + @Log(title = "店铺图片", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ShopImgBo bo) { + return toAjax(shopImgService.updateByBo(bo)); + } + + /** + * 删除店铺图片 + * + * @param ids 主键串 + */ + @Log(title = "店铺图片", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(shopImgService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SpecController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SpecController.java new file mode 100644 index 0000000..9345c29 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SpecController.java @@ -0,0 +1,130 @@ +package org.dromara.zhishu.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cn.hutool.core.util.ObjectUtil; +import com.pdd.pop.sdk.http.api.pop.response.PddGoodsSpecIdGetResponse; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.util.PddUtils; +import org.dromara.zhishu.util.UploadUtil; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.vo.SpecVo; +import org.dromara.zhishu.domain.bo.SpecBo; +import org.dromara.zhishu.service.ISpecService; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; + +/** + * 自定义规格设置 + * + * @author yxy + * @date 2025-03-27 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/spec") +public class SpecController extends BaseController { + + private final ISpecService specService; + private final IShopService shopService; + /** + * 查询自定义规格设置列表 + */ + @SaCheckPermission("zhishu:spec:list") + @GetMapping("/list") + public TableDataInfo list(SpecBo bo, PageQuery pageQuery) { + return specService.queryPageList(bo, pageQuery); + } + + /** + * 导出自定义规格设置列表 + */ + @SaCheckPermission("zhishu:spec:export") + @Log(title = "自定义规格设置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SpecBo bo, HttpServletResponse response) { + List list = specService.queryList(bo); + ExcelUtil.exportExcel(list, "自定义规格设置", SpecVo.class, response); + } + + /** + * 获取自定义规格设置详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:spec:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(specService.queryById(id)); + } + + @GetMapping("/getInfoByShopId/{shopId}") + public R getInfoByShopId(@PathVariable Long shopId) { + return R.ok(specService.selectVoByShopId(shopId)); + } + + /** + * 新增自定义规格设置 + */ + @SaCheckPermission("zhishu:spec:add") + @Log(title = "自定义规格设置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SpecBo bo) { + return toAjax(specService.insertByBo(bo)); + } + + /** + * 修改自定义规格设置 + */ + @SaCheckPermission("zhishu:spec:edit") + @Log(title = "自定义规格设置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SpecBo bo) { + ShopVo shopVo = shopService.queryById(bo.getShopId()); + PddGoodsSpecIdGetResponse.GoodsSpecIdGetResponse specIdGetResponse = PddUtils.getGoodsSpecId(shopVo.getToken(),bo.getSpecTypeName()); + if (specIdGetResponse == null){ + R.fail("自定义规格异常,请联系客服"); + }else{ + bo.setSpecTypeId(specIdGetResponse.getSpecId()+""); + } + return toAjax(specService.updateByBo(bo)); + } + + /** + * 删除自定义规格设置 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:spec:remove") + @Log(title = "自定义规格设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(specService.deleteWithValidByIds(List.of(ids), true)); + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SubAccountController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SubAccountController.java new file mode 100644 index 0000000..82ba290 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SubAccountController.java @@ -0,0 +1,314 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.session.SaSession; +import cn.dev33.satoken.stp.StpUtil; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 子账号管理 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/subAccount") +public class SubAccountController { + + private final ISysUserService userService; + + + @GetMapping("/getSubAccountList") + public R getSubAccountList(String pageNum, String pageSize){ + LoginUser loginUser = LoginHelper.getLoginUser(); + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + Map queryParams = new HashMap<>(); + queryParams.put("fid", loginUser.getUserId().toString()); + queryParams.put("app_key", "psi"); + queryParams.put("client_id", "psi"); + queryParams.put("timestamp", (System.currentTimeMillis() / 1000)+""); + queryParams.put("sign_method", "md5"); + queryParams.put("page", pageNum); + queryParams.put("page_size", pageSize); + String result = InterfaceUtils.getWithSign(UrlUtil.getNewWarehouse()+"/api/admin/employee/list", queryParams,warehouseLoginUser.get("token").toString(),"md5"); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + if (resultMap.get("code").toString().equals("200")){ + Map data = (Map) resultMap.get("data"); + List list = data.get("list") != null ? (List) data.get("list") : new ArrayList(); + Map map = new HashMap(); + map.put("list",list); + map.put("total",data.get("total")); + return R.ok("获取列表成功",map); + }else{ + return R.fail("获取列表失败"); + } + } + + @GetMapping("/getLevelConfig") + public List getLevelConfig(){ + LoginUser loginUser = LoginHelper.getLoginUser(); + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + Map queryParams = new HashMap<>(); + queryParams.put("level","0"); + queryParams.put("app_key", "psi"); + queryParams.put("client_id", "psi"); + queryParams.put("timestamp", (System.currentTimeMillis() / 1000)+""); + queryParams.put("sign_method", "md5"); + String result = InterfaceUtils.getWithSign(UrlUtil.getNewWarehouse()+"/api/admin/employee/level_config", queryParams,warehouseLoginUser.get("token").toString(),"md5"); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + List dataList = (List) resultMap.get("data"); + return dataList; + } + + + /** + * 新增店铺主表 + */ + @PostMapping("/add") + public R add(@RequestBody Map data) { + LoginUser loginUser = LoginHelper.getLoginUser(); + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + data.put("from","ERP"); + data.put("fid",warehouseLoginUser.get("id").toString()); + data.put("about_id",loginUser.getUserId().toString()); + String res = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/employee/reg",data); + Map resultMap = JsonUtil.transferToObj(res,Map.class); + if (!resultMap.get("code").toString().equals("200")){ + String msg = resultMap.get("msg").toString(); + return R.fail(msg); + } + return R.ok(); + } + + /** + * 设置代理等级 + * @return + */ + @PostMapping("/setLevel") + public R setLevel(@RequestBody Map data ){ + LoginUser loginUser = LoginHelper.getLoginUser(); + SysUserVo userVo = userService.selectUserById(loginUser.getUserId()); + BigDecimal balance = userVo.getBalance(); + + BigDecimal price = new BigDecimal(data.get("price").toString()); + + if (balance.compareTo(price) < 0){ + // 余额不足 + return R.fail("余额不足"); + } + + String level = data.get("level").toString(); + String operationType = data.get("operationType").toString(); + String duration = data.get("duration").toString(); + + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + String empId = warehouseLoginUser.get("id").toString(); + + Map setLevelMap = new HashMap(); + setLevelMap.put("emp_id",empId); + setLevelMap.put("level",level); + setLevelMap.put("pay_time",(System.currentTimeMillis() / 1000)+""); + setLevelMap.put("operation_type",operationType); + setLevelMap.put("duration",duration); + setLevelMap.put("app_key","psi"); + setLevelMap.put("client_id","psi"); + setLevelMap.put("timestamp",(System.currentTimeMillis() / 1000)+""); + setLevelMap.put("sign_method","md5"); + + String result = InterfaceUtils.postFormWithSign(UrlUtil.getNewWarehouse()+"/api/admin/employee/set_level", null ,setLevelMap,warehouseLoginUser.get("token").toString(),"md5"); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + if (resultMap.get("code").toString().equals("200")){ + // 重新保存用户信息 + warehouseLoginUser.put("level_info",level); + loginUser.setWarehouseLoginUser(warehouseLoginUser); + SaSession tokenSession = StpUtil.getTokenSession(); + tokenSession.set(LoginHelper.LOGIN_USER_KEY, loginUser); + return R.ok("开通成功"); + } + return R.fail(resultMap.get("msg").toString()); + } + + + @GetMapping("/getPdaConfig") + public Map getPdaConfig(String empId){ + LoginUser loginUser = LoginHelper.getLoginUser(); + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + + Map queryParams = new HashMap<>(); + queryParams.put("app_key", "psi"); + queryParams.put("client_id", "psi"); + queryParams.put("timestamp", (System.currentTimeMillis() / 1000)+""); + queryParams.put("sign_method", "md5"); + queryParams.put("emp_id",empId); + String result = InterfaceUtils.getWithSign(UrlUtil.getNewWarehouse()+"/api/employee/get_pda_config", queryParams,warehouseLoginUser.get("token").toString(),"md5"); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + return resultMap; + } + + /** + * 设置子账号配置信息 + */ + @PostMapping("/setPdaConfig") + public R setPdaConfig(@RequestBody Map map) { + LoginUser loginUser = LoginHelper.getLoginUser(); + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + + // 打印接收到的参数(用于调试) + System.out.println(map); + + // 构建请求参数 + Map requestParams = new HashMap<>(); + + // 基础配置 - 直接使用下划线命名的参数 + requestParams.put("emp_id", map.get("emp_id").toString()); + requestParams.put("show_price", map.get("show_price").toString()); + requestParams.put("show_category", map.get("show_category").toString()); + requestParams.put("compare_count", map.get("compare_count").toString()); + requestParams.put("compare_count_editable", map.get("compare_count_editable").toString()); + requestParams.put("price_compare", map.get("price_compare").toString()); + requestParams.put("price_value", map.get("price_value").toString()); + requestParams.put("price_editable", map.get("price_editable").toString()); + requestParams.put("sell_count_compare", map.get("sell_count_compare").toString()); + requestParams.put("sell_count_value", map.get("sell_count_value").toString()); + requestParams.put("sell_count_editable", map.get("sell_count_editable").toString()); + requestParams.put("buy_count_compare", map.get("buy_count_compare").toString()); + requestParams.put("buy_count_value", map.get("buy_count_value").toString()); + requestParams.put("buy_count_editable", map.get("buy_count_editable").toString()); + requestParams.put("condition", map.get("condition").toString()); + requestParams.put("condition_editable", map.get("condition_editable").toString()); + + // 精品配置 + requestParams.put("jingpin_enabled", map.get("jingpin_enabled").toString()); + requestParams.put("jingpin_price_compare", map.get("jingpin_price_compare").toString()); + requestParams.put("jingpin_price_value", map.get("jingpin_price_value").toString()); + requestParams.put("jingpin_price_editable", map.get("jingpin_price_editable").toString()); + requestParams.put("jingpin_sell_count_compare", map.get("jingpin_sell_count_compare").toString()); + requestParams.put("jingpin_sell_count_value", map.get("jingpin_sell_count_value").toString()); + requestParams.put("jingpin_sell_count_editable", map.get("jingpin_sell_count_editable").toString()); + requestParams.put("jingpin_buy_count_compare", map.get("jingpin_buy_count_compare").toString()); + requestParams.put("jingpin_buy_count_value", map.get("jingpin_buy_count_value").toString()); + requestParams.put("jingpin_buy_count_editable", map.get("jingpin_buy_count_editable").toString()); + requestParams.put("show_cache",map.get("show_cache").toString()); + + // 添加签名相关参数 + requestParams.put("app_key", "psi"); + requestParams.put("client_id", "psi"); + requestParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + requestParams.put("sign_method", "md5"); + + // 调用远程接口 + String result = InterfaceUtils.postFormWithSign( + UrlUtil.getNewWarehouse() + "/api/employee/set_pda_config", + null, + requestParams, + warehouseLoginUser.get("token").toString(), + "md5" + ); + + Map resultMap = JsonUtil.transferToObj(result, Map.class); + if (resultMap.get("code").toString().equals("200")) { + return R.ok("设置成功"); + } else { + return R.fail(resultMap.get("msg").toString()); + } + } + + + @PostMapping("/updatePasswrod") + public R updatePasswrod(@RequestBody Map map){ + + String id = map.get("id").toString(); + String password = map.get("password").toString(); + + LoginUser loginUser = LoginHelper.getLoginUser(); + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + + + Map requestParams = new HashMap<>(); + + requestParams.put("id",id); + requestParams.put("about_id",loginUser.getUserId().toString()); + requestParams.put("password",password); + requestParams.put("app_key", "psi"); + requestParams.put("client_id", "psi"); + requestParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + requestParams.put("sign_method", "md5"); + + // 调用远程接口 + String result = InterfaceUtils.postFormWithSign( + UrlUtil.getNewWarehouse() + "/api/admin/employee/update", + null, + requestParams, + warehouseLoginUser.get("token").toString(), + "md5" + ); + + Map resultMap = JsonUtil.transferToObj(result, Map.class); + if (resultMap.get("code").toString().equals("200")) { + return R.ok("设置成功"); + } else { + String msg = resultMap.get("msg").toString(); + if (msg.contains("Password") && msg.contains("min")){ + return R.fail("密码长度限制最少六位,请重新设置密码"); + } + return R.fail(resultMap.get("msg").toString()); + } + } + + @PostMapping("/updateExpireTime") + public R updateExpireTime(@RequestBody Map map){ + + String id = map.get("id").toString(); + String expireTime = map.get("expire_time").toString(); + + LoginUser loginUser = LoginHelper.getLoginUser(); + Map warehouseLoginUser = loginUser.getWarehouseLoginUser(); + + + Map requestParams = new HashMap<>(); + + requestParams.put("id",id); + requestParams.put("about_id",loginUser.getUserId().toString()); + requestParams.put("expire_time",expireTime); + requestParams.put("app_key", "psi"); + requestParams.put("client_id", "psi"); + requestParams.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000)); + requestParams.put("sign_method", "md5"); + + // 调用远程接口 + String result = InterfaceUtils.postFormWithSign( + UrlUtil.getNewWarehouse() + "/api/admin/employee/update_expire_time", + null, + requestParams, + warehouseLoginUser.get("token").toString(), + "md5" + ); + + Map resultMap = JsonUtil.transferToObj(result, Map.class); + if (resultMap.get("code").toString().equals("200")) { + return R.ok("设置成功"); + } else { + String msg = resultMap.get("msg").toString(); + if (msg.contains("Password") && msg.contains("min")){ + return R.fail("密码长度限制最少六位,请重新设置密码"); + } + return R.fail(resultMap.get("msg").toString()); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SyncLogController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SyncLogController.java new file mode 100644 index 0000000..b35d00a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SyncLogController.java @@ -0,0 +1,71 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.zhishu.domain.SyncLog; +import org.dromara.zhishu.service.ISyncLogService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/syncLog") +public class SyncLogController extends BaseController { + + private final ISyncLogService syncLogService; + + /** + * 同步货区 + */ + @PostMapping("/syncLocations") + @SaIgnore + public R syncLocations(@RequestBody Map map){ + String type = map.get("type").toString(); + Long userId = LoginHelper.getUserId(); + SyncLog syncLogBo = new SyncLog(); + syncLogBo.setUserId(userId); + syncLogBo.setType(type); + List syncLogList = syncLogService.queryList(syncLogBo); + if (!syncLogList.isEmpty()){ + return R.fail("数据已迁移完毕"); + } + String msg = ""; + try{ + if (type.equals("1")){ + String res = InterfaceUtils.getInterfaceSync("http://175.27.224.66:8111","/api/shelf-chain?userId="+userId); + Map resMap = JsonUtil.transferToObj(res,Map.class); + msg = resMap.get("msg").toString(); + }else if (type.equals("2")){ + String res = InterfaceUtils.getInterfaceSync("http://175.27.224.66:8111","/api/sync-goods?userId="+userId); + Map resMap = JsonUtil.transferToObj(res,Map.class); + msg = resMap.get("msg").toString(); + }else{ + msg = "异常类型:"+type; + } + }catch (Exception e){ + msg = "调用接口异常 :"+e.getMessage(); + } + + SyncLog syncLog = new SyncLog(); + syncLog.setUserId(userId); + syncLog.setMsg(msg); + syncLog.setType(type); + syncLog.setCreateBy(System.currentTimeMillis()); + syncLogService.insertByBo(syncLog); + return R.ok(msg); + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopOrderController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopOrderController.java new file mode 100644 index 0000000..da98594 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopOrderController.java @@ -0,0 +1,665 @@ +package org.dromara.zhishu.controller; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.apache.poi.ss.formula.functions.Count; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.bo.DepotOrderBo; +import org.dromara.zhishu.domain.dto.request.UpdateIsSynOrderRequest; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryRequest; +import org.dromara.zhishu.domain.dto.request.OrderListByShopIdRequest; +import org.dromara.zhishu.domain.dto.PddOrderQueryDto; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.util.UrlUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.bo.TShopOrderBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.Objects; +import java.util.regex.Pattern;import org.springframework.beans.factory.annotation.Autowired; +/** + * 订单 + * + * @author Lion Li + * @date 2025-03-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopOrder") +public class TShopOrderController extends BaseController { + + @Autowired + private RestTemplate restTemplate; + + private static final Logger log = LoggerFactory.getLogger(TShopOrderController.class); + private final IShopService shopService; + private final ITShopOrderService tShopOrderService; + private final IZhishuShopGoodsService zhishuShopGoodsService; + private final ITDepotService depotService; + private final IDepotOrderService depotOrderService; + + private final StockChangeLogService stockChangeLogService; + private final ShopMapper shopMapper; + + + private static final String ORDER_URL = UrlUtil.getOrderServiceUrl() + "/api/erpGoodsOrder"; + + /** + * 统计用户订单数量 + */ + @SaIgnore + @GetMapping("/todayCount/{id}") + public Integer countOrder(@PathVariable Long id) { + List shopIdList = shopMapper.getShopIdByCreateBy(id); + + // 构建URL,id也作为请求参数 + UriComponentsBuilder builder = UriComponentsBuilder + .fromHttpUrl(ORDER_URL + "/todayCount") + .queryParam("id", id); // id作为queryParam + + // shopIdList作为多个同名参数 + for (String shopId : shopIdList) { + builder.queryParam("shopIdList", shopId); + } + + String url = builder.toUriString(); + System.out.println("Calling URL: " + url); // 打印看看生成的URL + + // 调用项目2的接口 + Integer count = restTemplate.getForObject(url, Integer.class); + + return count; + } + + @SaIgnore + @GetMapping("/totalCount/{id}") + public Integer TotalOrder(@PathVariable Long id){ + List shopIdList = shopMapper.getShopIdByCreateBy(id); + + // 构建URL,id也作为请求参数 + UriComponentsBuilder builder = UriComponentsBuilder + .fromHttpUrl(ORDER_URL + "/monthOrder") + .queryParam("id", id); // id作为queryParam + + // shopIdList作为多个同名参数 + for (String shopId : shopIdList) { + builder.queryParam("shopIdList", shopId); + } + + String url = builder.toUriString(); + System.out.println("Calling URL: " + url); // 打印看看生成的URL + + // 调用项目2的接口 + Integer count = restTemplate.getForObject(url, Integer.class); + + return count; + } + + @SaIgnore + @GetMapping("/todaySale/{id}") + public BigDecimal todaySale(@PathVariable Long id) { + List shopIdList = shopMapper.getShopIdByCreateBy(id); + + // 构建URL,id也作为请求参数 + UriComponentsBuilder builder = UriComponentsBuilder + .fromHttpUrl(ORDER_URL + "/todaySale") + .queryParam("id", id); // id作为queryParam + + // shopIdList作为多个同名参数 + for (String shopId : shopIdList) { + builder.queryParam("shopIdList", shopId); + } + + String url = builder.toUriString(); + System.out.println("Calling URL: " + url); // 打印看看生成的URL + + // 调用项目2的接口 + BigDecimal sale = restTemplate.getForObject(url, BigDecimal.class); + + return sale; + } + + @SaIgnore + @GetMapping("/totalSale/{id}") + public BigDecimal totalSale(@PathVariable Long id) { + List shopIdList = shopMapper.getShopIdByCreateBy(id); + + // 构建URL,id也作为请求参数 + UriComponentsBuilder builder = UriComponentsBuilder + .fromHttpUrl(ORDER_URL + "/monthSale") + .queryParam("id", id); // id作为queryParam + + // shopIdList作为多个同名参数 + for (String shopId : shopIdList) { + builder.queryParam("shopIdList", shopId); + } + + String url = builder.toUriString(); + System.out.println("Calling URL: " + url); // 打印看看生成的URL + + // 调用项目2的接口 + BigDecimal totalSale = restTemplate.getForObject(url, BigDecimal.class); + + return totalSale; + } + + @SaIgnore + @GetMapping("/orderDisplay/{id}") + public Map orderDisplay(@PathVariable Long id) { + // 构建URL,只传递id参数 + String url = UriComponentsBuilder + .fromHttpUrl(ORDER_URL + "/orderDisplay") + .queryParam("id", id) + .toUriString(); + + System.out.println("Calling URL: " + url); + + // 调用外部接口 + Map result = restTemplate.getForObject(url, Map.class); + return result; + } + + @SaIgnore + @GetMapping("/hourOrder/{id}") + public Map hourOrder(@PathVariable Long id) { + // 构建URL,只传递id参数 + String url = UriComponentsBuilder + .fromHttpUrl(ORDER_URL + "/hourOrder") + .queryParam("id", id) + .toUriString(); + + System.out.println("Calling URL: " + url); + + // 调用外部接口 + Map result = restTemplate.getForObject(url, Map.class); + return result; + } + + @SaIgnore + @GetMapping("/orderAmount/{id}") + public Map orderAmountDistribution(@PathVariable Long id) { + // 构建URL,只传递id参数 + String url = UriComponentsBuilder + .fromHttpUrl(ORDER_URL + "/orderAmountDistribution") + .queryParam("id", id) + .toUriString(); + + System.out.println("Calling URL: " + url); + + // 调用外部接口 + Map result = restTemplate.getForObject(url, Map.class); + return result; + } + + /** + * 查询订单列表 + */ +// @SaCheckPermission("zhishu:shopOrder:list") + @SaIgnore + @GetMapping("/list") + public TableDataInfo list(TShopOrderBo bo, PageQuery pageQuery) { + return tShopOrderService.queryPageList(bo, pageQuery); + } + + /** + * 查询订单列表 + */ + @SaCheckPermission("zhishu:shopOrder:list") + @GetMapping("/page") + public TableDataInfo page(@Validated(QueryGroup.class) TShopOrderBo bo, PageQuery pageQuery) { + return tShopOrderService.customPageList(bo, pageQuery); + } + + + /** + * 导出订单列表 + */ + @SaCheckPermission("zhishu:shopOrder:export") + @Log(title = "订单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TShopOrderBo bo, HttpServletResponse response) { + List list = tShopOrderService.queryList(bo); + ExcelUtil.exportExcel(list, "订单", TShopOrderVo.class, response); + } + + /** + * 获取订单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shopOrder:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tShopOrderService.queryById(id)); + } + + /** + * 新增订单 + */ + @SaCheckPermission("zhishu:shopOrder:add") + @Log(title = "订单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TShopOrderBo bo) { + return toAjax(tShopOrderService.insertByBo(bo)); + } + + /** + * 修改订单 + */ + @SaCheckPermission("zhishu:shopOrder:edit") + @Log(title = "订单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TShopOrderBo bo) { + return toAjax(tShopOrderService.updateByBo(bo)); + } + + /** + * 删除订单 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:shopOrder:remove") + @Log(title = "订单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tShopOrderService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 订单列表查询接口(根据成交时间) + * + * @param queryDto + */ +// @SaCheckPermission("zhishu:shopOrder:remove") +// @Log(title = "订单", businessType = BusinessType.DELETE) + @GetMapping("/getInterShopOrder") + public R getInterShopOrder(@RequestBody PddOrderQueryDto queryDto) { + + return tShopOrderService.getInterShopOrder(queryDto); + } + + /** + * 根据订单编码查询订单信息 + * + * @param orderSn + * @return + */ + @SaIgnore + @GetMapping("/listByOrderSn") + public TShopOrderVo listByOrderSn(@NotNull(message = "平台订单编码不能为空") String orderSn) { + return tShopOrderService.listByOrderSn(orderSn); + } + + @SaIgnore + @GetMapping("/getOrderByOrderSn") + public String getOrderByOrderSn(@NotNull(message = "平台订单编码不能为空") String orderSn) { + TShopOrderVo vo = tShopOrderService.listByOrderSn(orderSn); + if(vo == null){ + return "-1"; + }else{ + return vo.getId().toString(); + } + } + + /** + * 根据店铺id查询订单信息 + * + * @param request + * @return + */ + @SaIgnore + @PostMapping("/listByShopId") + public List listByShopId(@RequestBody OrderListByShopIdRequest request) { + return tShopOrderService.listByShopId(request); + } + + /** + * 批量插入/更新订单信息 + * + * @param orderList + * @return + */ + @SaIgnore + @PostMapping("/insertOrUpdateOrderBatch") + public Boolean insertOrUpdateOrderBatch(@NotEmpty(message = "订单信息不能为空") @RequestBody List orderList) { + tShopOrderService.insertOrUpdateOrderBatch(orderList); + return true; + } + + /** + * 定时同步孔网订单 + * + * @return + */ + @SaIgnore + @GetMapping("/syncKfzOrderTask") + public Boolean syncKfzOrderTask() { + tShopOrderService.syncKfzOrderTask(); + return true; + } + + /** + * 获取配送方式列表 + * + * @param shopId + * @param orderSourceType + * @return + */ + @SaIgnore + @GetMapping("/delivery/methodList") + public R> syncKfzOrderTaskTest(@NotNull(message = "店铺Id不能为空") Long shopId, @NotNull(message = "订单类型不能为空") Integer orderSourceType) { + List result = tShopOrderService.deliveryMethodList(shopId, orderSourceType); + return R.ok(result); + } + + /** + * 订单发货 + * + * @param request + * @return + */ + @SaIgnore + @PostMapping("/delivery") + public R orderDelivery(@Validated @RequestBody OrderDeliveryRequest request) { + Boolean result = tShopOrderService.orderDelivery(request); + return R.ok(result); + } + + + @SaIgnore + @PostMapping("/checkInfo") + public R checkInfo(String orderId) { + TShopOrderVo shopOrderVo = tShopOrderService.queryById(Long.parseLong(orderId)); + // 校验是否报错 + Map itemList = JsonUtils.parseMap(shopOrderVo.getItemList()); + System.out.println(itemList); + + List list = (List) itemList.get("itemList"); + // 获取goodsSourceUnknownException 异常的商品id字符串 + String errorIdStr = ""; + for (int i = 0; i < list.size(); i++) { + Map dataMap = (Map) list.get(i); + if (dataMap.get("orderExceptionType").equals("goodsSourceUnknownException")) { + if(dataMap.get("orderItemIds")!= null){ + List errorIdList = (List) dataMap.get("orderItemIds"); + for (int j = 0; j < errorIdList.size(); j++) { + if (StringUtils.isEmpty(errorIdStr)) { + errorIdStr = errorIdList.get(j).toString(); + } else { + errorIdStr += "," + errorIdList.get(j).toString(); + } + } + } + + } + } + List orderItems = (List) itemList.get("orderItems"); + + for (int i = 0; i < orderItems.size(); i++) { + Map dataMap = (Map) orderItems.get(i); + + //拼多多结构与孔网结构不同 做出判断 1 拼多多 2 孔网 + + if(shopOrderVo.getOrderSourceType()==1){ + System.out.println("拼多多"); + // 校验id是否存在于异常商品id字符串中 + if (dataMap.get("goodsId").toString().contains(errorIdStr)) { + // 根据货号查询商品信息,校验商品库存是否为0 + String artNo = dataMap.get("outerId").toString(); + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.selectShopGoodsByArtNo(artNo); + + if (new BigDecimal(zhishuShopGoodsVo.getInventory().toString()).compareTo(BigDecimal.ZERO) == 0) { + // 库存为0 + System.out.println("库存为0"); + List stockChangeLogVoList = stockChangeLogService.selectShopStockLogbyCreateBy(zhishuShopGoodsVo.getId(), shopOrderVo.getOrderSn()); + if(!stockChangeLogVoList.isEmpty()){ + String beforeInv = stockChangeLogVoList.get(0).getBeforeInv().toString(); + if(Integer.parseInt(beforeInv)>0){ + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + } + } + return R.fail("商品库存不足"); + } else { + // + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + } + } + + }if (shopOrderVo.getOrderSourceType()==2){ + System.out.println("孔网"); + if (dataMap.get("itemId").toString().contains(errorIdStr)) { + // 根据货号查询商品信息,校验商品库存是否为0 + String artNo = dataMap.get("itemSn").toString(); + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.selectShopGoodsByArtNo(artNo); + if (new BigDecimal(zhishuShopGoodsVo.getInventory().toString()).compareTo(BigDecimal.ZERO) == 0) { + // 库存为0 + System.out.println("库存为0"); + List stockChangeLogVoList = stockChangeLogService.selectShopStockLogbyCreateBy(zhishuShopGoodsVo.getId(), shopOrderVo.getOrderSn()); + if(!stockChangeLogVoList.isEmpty()){ + String beforeInv = stockChangeLogVoList.get(0).getBeforeInv().toString(); + if(Integer.parseInt(beforeInv)>0){ + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + } + } + + return R.fail("商品库存不足"); + } else { + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + } + } + + } + + + } + System.out.println(list); + // 校验货号是否存在我们数据库 +// zhishuShopGoodsService.selectShopGoodsByArtNo() + + return R.ok(); + } + + + + + @SaIgnore + @PostMapping("/checkInfolist") + + public R checkInfolist(String[] orderIds) { + + for (String orderId : orderIds ){ + TShopOrderVo shopOrderVo = tShopOrderService.queryById(Long.parseLong(orderId)); + // 校验是否报错 + Map itemList = JsonUtils.parseMap(shopOrderVo.getItemList()); + System.out.println(itemList); + + List list = (List) itemList.get("itemList"); + // 获取goodsSourceUnknownException 异常的商品id字符串 + String errorIdStr = ""; + for (int i = 0; i < list.size(); i++) { + Map dataMap = (Map) list.get(i); + if (dataMap.get("orderExceptionType").equals("goodsSourceUnknownException")) { + if(dataMap.get("orderItemIds")!= null){ + List errorIdList = (List) dataMap.get("orderItemIds"); + for (int j = 0; j < errorIdList.size(); j++) { + if (StringUtils.isEmpty(errorIdStr)) { + errorIdStr = errorIdList.get(j).toString(); + } else { + errorIdStr += "," + errorIdList.get(j).toString(); + } + } + } + + } + } + List orderItems = (List) itemList.get("orderItems"); + + for (int i = 0; i < orderItems.size(); i++) { + Map dataMap = (Map) orderItems.get(i); + + //拼多多结构与孔网结构不同 做出判断 1 拼多多 2 孔网 + if(shopOrderVo.getOrderSourceType()==1){ + System.out.println("拼多多"); + // 校验id是否存在于异常商品id字符串中 + if (dataMap.get("goodsId").toString().contains(errorIdStr)) { + // 根据货号查询商品信息,校验商品库存是否为0 + String artNo = dataMap.get("outerId").toString(); + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.selectShopGoodsByArtNo(artNo); + List stockChangeLogVoList = stockChangeLogService.selectShopStockLogbyCreateBy(zhishuShopGoodsVo.getId(), shopOrderVo.getOrderSn()); + + if (new BigDecimal(zhishuShopGoodsVo.getInventory().toString()).compareTo(BigDecimal.ZERO) == 0) { + // 库存为0 + System.out.println("库存为0"); + if(!stockChangeLogVoList.isEmpty()){ + String beforeInv = stockChangeLogVoList.get(0).getBeforeInv().toString(); + if(Integer.parseInt(beforeInv)>0){ + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + return R.ok(); + } + } + + return R.fail("商品库存不足"); + } else { + // + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + } + } + + }if (shopOrderVo.getOrderSourceType()==2){ + System.out.println("孔网"); + if (dataMap.get("itemId").toString().contains(errorIdStr)) { + // 根据货号查询商品信息,校验商品库存是否为0 + String artNo = dataMap.get("itemSn").toString(); + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.selectShopGoodsByArtNo(artNo); + List stockChangeLogVoListkw = stockChangeLogService.selectShopStockLogbyCreateBy(zhishuShopGoodsVo.getId(), shopOrderVo.getOrderSn()); + + if (new BigDecimal(zhishuShopGoodsVo.getInventory().toString()).compareTo(BigDecimal.ZERO) == 0) { + // 库存为0 + System.out.println("库存为0"); + + if(!stockChangeLogVoListkw.isEmpty()){ + String beforeInv = stockChangeLogVoListkw.get(0).getBeforeInv().toString(); + if(Integer.parseInt(beforeInv)>0){ + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + return R.ok(); + }else{ + return R.fail("商品库存不足"); + } + }else { + return R.fail("商品库存不足"); + } + + } else { + insertDepotOrderBo(zhishuShopGoodsVo, orderId, dataMap); + } + } + + } + + + } + System.out.println(list); + + } + + return R.ok(); + + } + + + /** + * 重新同步订单(已扣减库存订单不会再次扣减) + * + * @return + */ + @SaIgnore + @PostMapping("/syncKfzHistoryOrder") + public R syncKfzHistoryOrder(@NotNull(message = "重新拉取历史订单天数不能为空") @RequestParam Integer days, @NotEmpty(message = "同步店铺不能为空") @RequestBody List shopIdList) { + tShopOrderService.syncKfzHistoryOrder(days, shopIdList); + return R.ok(true); + } + + /** + * 重新同步订单完成回调 + * + * @return + */ + @SaIgnore + @GetMapping("/syncKfzHistoryOrderCallBack") + public R syncKfzHistoryOrderCallBack(@NotNull(message = "店铺Id不能为空") @RequestParam Long shopId) { + tShopOrderService.syncKfzHistoryOrderCallBack(shopId); + return R.ok(true); + } + + + /** + * 修改订单同步状态 + * + * @return + */ + @SaIgnore + @PostMapping("/updateIsSynOrder") + public R updateIsSynOrder(@Validated @RequestBody UpdateIsSynOrderRequest request) { + tShopOrderService.updateIsSynOrder(request); + return R.ok(true); + } + + public void insertDepotOrderBo(ZhishuShopGoodsVo zhishuShopGoodsVo,String orderId,Map dataMap){ + /** + * 正常 下发仓库订单给仓库 + */ + // 获取仓库code + // String code = artNo.substring(0, 1); + TDepotVo depotVo = depotService.queryById(zhishuShopGoodsVo.getDepotId()); + // 获取仓库创建人作为任务执行人 + + DepotOrderBo depotOrderBo = new DepotOrderBo(); + depotOrderBo.setShopOrderId(orderId); + depotOrderBo.setUserId(LoginHelper.getUserId()); + depotOrderBo.setItemList(JsonUtils.toJsonString(dataMap)); + depotOrderBo.setStatus("0"); + depotOrderBo.setCreateBy(LoginHelper.getUserId()); + depotOrderBo.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + depotOrderService.insertByBo(depotOrderBo); + + + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TUserPlatform.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TUserPlatform.java new file mode 100644 index 0000000..e402175 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TUserPlatform.java @@ -0,0 +1,14 @@ +package org.dromara.zhishu.controller; + +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/userPlatform") +public class TUserPlatform { + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TaskController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TaskController.java new file mode 100644 index 0000000..6508d27 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TaskController.java @@ -0,0 +1,2069 @@ +package org.dromara.zhishu.controller; + +import java.io.*; +import java.math.BigDecimal; +import java.util.*; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.opencsv.CSVWriter; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.TaskPause; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.mapper.TaskMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.client.FileClient; +import org.dromara.zhishu.util.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.core.io.Resource; +import org.springframework.http.ResponseEntity; +import org.springframework.core.io.FileSystemResource; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.data.ReadCellData; +import org.springframework.web.multipart.MultipartFile; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 任务列表 + * + * @author yxy + * @date 2025-03-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/task") +public class TaskController extends BaseController { + + private final ApplicationContext applicationContext; + + private final ITaskService taskService; + + private final IShopDetailService shopDetailService; + + private final IShopService shopService; + + private final ISysConfigService configService; + + private final IZhishuShopGoodsService zhishuShopGoodsService; + + private final IRunningTaskService runningTaskService; + + private final IRunningTaskByShopService runningTaskByShopService; + + private final FileClient fileClient; + + private final ITaskPauseService taskPauseService; + + private final TaskMapper baseMapper; + + @Autowired + private RestTemplate restTemplate; + + + @GetMapping("/selectTaskStatus") + @SaIgnore + public Map selectTaskStatus(){ + return runningTaskService.selectTaskStatus(); + } + + /** + * 查询任务列表列表 + */ + @SaCheckPermission("zhishu:task:list") + @GetMapping("/list") + public TableDataInfo list(TaskBo bo, PageQuery pageQuery) { + TableDataInfo result = taskService.queryPageList(bo, pageQuery); + List taskVoList = result.getRows(); + for (TaskVo taskVo : taskVoList){ + // 同步至自营书品 + if(Objects.equals(taskVo.getTaskType(),"SYNC_MY_GOODS")){ + Long taskDataNum = zhishuShopGoodsService.getTaskDataNum(taskVo.getId()); + taskVo.setSuccessCount(Math.toIntExact(taskDataNum)); + taskVo.setWaitCount((int) (taskVo.getDataNum()-taskDataNum)); + taskVo.setPauseCount(0); + }else if (taskVo.getTaskType().equals("NEW_ADD_TASK")){ + // 新发布商品接口,调用接口查询 + try{ + String taskRunningNumStr =InterfaceUtils.getInterface("http://36.212.12.92:8055","/getTaskRunningNum?taskId="+taskVo.getId()); + Map taskRunningNumMap = JSON.parseObject(taskRunningNumStr, Map.class); + String finistNum = taskRunningNumMap.get("finistNum").toString(); + String waitNum = taskRunningNumMap.get("waitNum").toString(); + taskVo.setWaitCount(Integer.parseInt(waitNum)); + taskVo.setSuccessCount(Integer.parseInt(finistNum)); + }catch (Exception e){ + taskVo.setWaitCount(0); + taskVo.setSuccessCount(0); + } + continue; + }else if(taskVo.getTaskType().equals("GET_KW_SHOP_GOODS")){ //如果是拉取任务则查询数据库 + int checkNum = runningTaskByShopService.checkTableExists("t_running_task_"+taskVo.getShopIds()); + if(checkNum == 0){ + taskVo.setSuccessCount(0); + taskVo.setWaitCount(0); + taskVo.setPauseCount(0); + }else{ + int num = runningTaskByShopService.selectGetShopGoodsNumByTasKId("t_running_task_"+taskVo.getShopIds(),taskVo.getId().toString()); + if(num == 0){ + taskVo.setSuccessCount(0); + taskVo.setWaitCount(0); + taskVo.setPauseCount(0); + }else{ + String status = runningTaskByShopService.selectStatus("t_running_task_"+taskVo.getShopIds()); + if(status.equals("2")){ + taskVo.setSuccessCount(0); + taskVo.setWaitCount(num); + taskVo.setPauseCount(0); + }else{ + taskVo.setSuccessCount(num); + Integer total = runningTaskByShopService.getShopGoodsTotalNumByTaskId("t_running_task_"+taskVo.getShopIds(),taskVo.getId()); + if (ObjectUtil.isEmpty(total) || total== 0){ + taskVo.setWaitCount(0); + }else{ + taskVo.setWaitCount(total - num); + } + + taskVo.setPauseCount(0); + } + } + } + continue; + } else if(taskVo.getTaskType().equals("GET_SHOP_GOODS")){ //如果是拉取任务则查询数据库 + int checkNum = runningTaskByShopService.checkTableExists("t_running_task_"+taskVo.getShopIds()); + if(checkNum == 0){ + taskVo.setSuccessCount(0); + taskVo.setWaitCount(0); + taskVo.setPauseCount(0); + }else{ + int num = runningTaskByShopService.getShopGoodsTotalNumByTaskId("t_running_task_"+taskVo.getShopIds(),taskVo.getId()); + if(num == 0){ + taskVo.setSuccessCount(0); + taskVo.setWaitCount(0); + taskVo.setPauseCount(0); + }else{ + String status = runningTaskByShopService.selectStatus("t_running_task_"+taskVo.getShopIds()); + if(status.equals("2")){ + taskVo.setSuccessCount(0); + taskVo.setWaitCount(num); + taskVo.setPauseCount(0); + }else{ + taskVo.setSuccessCount(num); + if (taskVo.getDataNum() == 0){ + taskVo.setWaitCount(0); + }else{ + taskVo.setWaitCount((int) (taskVo.getDataNum() - num)); + } + + taskVo.setPauseCount(0); + } + } + } + continue; + } else if(taskVo.getTaskType().equals("DEL")) { //删除店铺商品 + taskVo.setSuccessCount(taskVo.getDataNum().intValue()); + taskVo.setWaitCount(0); + taskVo.setPauseCount(0); + } + + String filePath = "https://book.center.file.buzhiyushu.cn/task_log/task-log-csv/"+taskVo.getId()+"/"+taskVo.getId()+".csv"; + + List voList; + + if(UploadUtil.isFileExists(filePath)){ + //读取日志文件 + try { + Map numMap = JsonObjUtil.parseJsonFromUrl("https://book.center.file.buzhiyushu.cn/task_log/task-log-csv/"+taskVo.getId()+"/"+taskVo.getId()+"_count.json"); + taskVo.setSuccessCount(Integer.parseInt(numMap.get("totalTaskCount").toString())); + taskVo.setWaitCount(0); + taskVo.setPauseCount(0); + } catch (IOException e) { + taskVo.setSuccessCount(0); + taskVo.setWaitCount(0); + taskVo.setPauseCount(0); + } + } + + voList = runningTaskService.selectTaskAllNum(taskVo.getId()); + //已执行数量 + int successCount = 0; + //待执行数量 + int waitCount = 0; + //暂停数量 + int pauseCount = 0; + + for(int i=0;i< voList.size();i++) { + RunningTaskNumVo vo = voList.get(i); + String status = vo.getStatus(); + if (status.equals("3") || status.equals("4")) { + //3 完成 4 报错 + successCount += vo.getAllNum(); + } else if (status.equals("5")){ + //暂停 + pauseCount += vo.getAllNum(); + } else { + waitCount += vo.getAllNum(); + } + } + + taskVo.setSuccessCount(taskVo.getSuccessCount() + successCount); + taskVo.setWaitCount(taskVo.getWaitCount() + waitCount); + taskVo.setPauseCount(taskVo.getPauseCount() + pauseCount); + } + result.setRows(taskVoList); + return result; + } + + @GetMapping("/logsList") + @SaIgnore + public Map logsList(String id){ + + TaskVo taskVo = taskService.queryById(Long.parseLong(id)); + + //如果是拉取任务则查询数据库 + if(taskVo.getTaskType().equals("GET_SHOP_GOODS") || taskVo.getTaskType().equals("GET_KW_SHOP_GOODS")){ + List shopDataList = new ArrayList<>(); + Map shopDataMap = new HashMap(); + ShopVo shopVo = shopService.queryById(Long.parseLong(taskVo.getShopIds())); + shopDataMap.put("taskId",id); + shopDataMap.put("shopId",shopVo.getId()); + shopDataMap.put("shopName", shopVo.getShopName()); + + int checkNum = runningTaskByShopService.checkTableExists("t_running_task_"+taskVo.getShopIds()); + if(checkNum == 0){ + //不存在拉取表 + shopDataMap.put("num","0"); + shopDataMap.put("successCount","0"); + shopDataMap.put("waitCount","0"); + }else{ + int num = runningTaskByShopService.getShopGoodsTotalNumByTaskId("t_running_task_"+taskVo.getShopIds(),taskVo.getId()); + if(num == 0){ + //不是最新的任务 + shopDataMap.put("num","0"); + shopDataMap.put("successCount","0"); + shopDataMap.put("waitCount","0"); + }else{ + String status = runningTaskByShopService.selectStatus("t_running_task_"+taskVo.getShopIds()); + shopDataMap.put("num",num); + if(status.equals("2")){ + //拉取任务未完成 + shopDataMap.put("successCount","0"); + shopDataMap.put("waitCount",num); + }else{ + //完成的任务 + shopDataMap.put("successCount",num); + shopDataMap.put("waitCount","0"); + } + } + } + + shopDataList.add(shopDataMap); + + Map map = new HashMap(); + map.put("successCount",shopDataMap.get("successCount")); + map.put("waitCount",shopDataMap.get("waitCount")); + map.put("allData",shopDataList); + return map; + }else{ + String filePath = "https://book.center.file.buzhiyushu.cn/task_log/task-log-csv/"+id+"/"+id+".csv"; + List voList; + Map map = new HashMap(); + List shopDataList = new ArrayList<>(); + int allNum = 0; + if(UploadUtil.isFileExists(filePath)){ + try { + Map numMap = JsonObjUtil.parseJsonFromUrl("https://book.center.file.buzhiyushu.cn/task_log/task-log-csv/"+taskVo.getId()+"/"+taskVo.getId()+"_count.json"); + allNum = Integer.parseInt(numMap.get("totalTaskCount").toString()); + Map shopNumMap = (Map) numMap.get("shopTaskCounts"); + for (Object key : shopNumMap.keySet()){ + //店铺id + String shopId = key.toString(); + //店铺数量 + int shopNum = Integer.parseInt(shopNumMap.get(shopId).toString()); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + Map shopDataMap = new HashMap(); + shopDataMap.put("waitCount",0); + shopDataMap.put("successCount",shopNum); + shopDataMap.put("num",shopNum); + shopDataMap.put("shopName",shopVo.getShopName()); + shopDataMap.put("shopId",shopId); + shopDataMap.put("taskId",id); + shopDataList.add(shopDataMap); + } + } catch (IOException e) { + System.out.println("异常"); + } + } + voList = runningTaskService.selectTaskAllNum(Long.parseLong(id)); + + //已执行数量 + int successCount = 0; + //待执行数量 + int waitCount = 0; + + Map shopDataMap = new HashMap(); + Long shopId = 0L; + for(int i=0;i< voList.size();i++){ + RunningTaskNumVo vo = voList.get(i); + ShopVo shopVo = shopService.queryById(vo.getShopId()); + vo.setShopName(shopVo.getShopName()); + String status = vo.getStatus(); + if(status.equals("3") || status.equals("4")){ + //3 完成 4 报错 + successCount += vo.getAllNum(); + }else{ + waitCount += vo.getAllNum(); + } + //统计任务 + if(shopId == 0L){ + shopId = vo.getShopId(); + if(status.equals("3") || status.equals("4")){ + shopDataMap.put("successCount",vo.getAllNum()); + }else{ + shopDataMap.put("waitCount",vo.getAllNum()); + } + shopDataMap.put("num",vo.getAllNum()); + shopDataMap.put("shopName",shopVo.getShopName()); + shopDataMap.put("shopId",vo.getShopId()); + shopDataMap.put("taskId",vo.getTaskId()); + }else if(!shopId.equals(vo.getShopId())){ + if(shopDataMap.get("successCount") == null){ + shopDataMap.put("successCount",0); + } + if (shopDataMap.get("waitCount") == null){ + shopDataMap.put("waitCount",0); + } + shopDataList.add(shopDataMap); + shopDataMap = new HashMap(); + shopId = vo.getShopId(); + if(status.equals("3") || status.equals("4")){ + shopDataMap.put("successCount",vo.getAllNum()); + }else{ + shopDataMap.put("waitCount",vo.getAllNum()); + } + shopDataMap.put("num",vo.getAllNum()); + shopDataMap.put("shopName",shopVo.getShopName()); + shopDataMap.put("shopId",vo.getShopId()); + shopDataMap.put("taskId",vo.getTaskId()); + }else{ + int num = (int) shopDataMap.get("num"); + num += vo.getAllNum(); + if(status.equals("3") || status.equals("4")){ + int shopSuccessCount = shopDataMap.get("successCount") == null ? 0 : (int) shopDataMap.get("successCount"); + shopSuccessCount += vo.getAllNum(); + shopDataMap.put("successCount",shopSuccessCount); + }else{ + int shopWaitCount = shopDataMap.get("waitCount") == null ? 0 : (int) shopDataMap.get("waitCount"); + shopWaitCount += vo.getAllNum(); + shopDataMap.put("waitCount",shopWaitCount); + } + shopDataMap.put("num",num); + } + } + if(shopDataMap.get("successCount") == null){ + shopDataMap.put("successCount",0); + } + if (shopDataMap.get("waitCount") == null){ + shopDataMap.put("waitCount",0); + } + if(shopDataMap.get("shopId") != null){ + shopDataList.add(shopDataMap); + } + + // 合并相同shopId的数据 + Map> mergedShopData = new HashMap<>(); + for (Map shopData : shopDataList) { + Long currentShopId = Long.parseLong(shopData.get("shopId").toString()); + + if (mergedShopData.containsKey(currentShopId)) { + // 如果已存在相同shopId,则累加数值 + Map existingData = mergedShopData.get(currentShopId); + + int existingNum = Integer.parseInt(existingData.get("num").toString()); + int currentNum = Integer.parseInt(shopData.get("num").toString()); + existingData.put("num", existingNum + currentNum); + + int existingSuccessCount = Integer.parseInt(existingData.get("successCount").toString()); + int currentSuccessCount = Integer.parseInt(shopData.get("successCount").toString()); + existingData.put("successCount", existingSuccessCount + currentSuccessCount); + + int existingWaitCount = Integer.parseInt(existingData.get("waitCount").toString()); + int currentWaitCount = Integer.parseInt(shopData.get("waitCount").toString()); + existingData.put("waitCount", existingWaitCount + currentWaitCount); + } else { + // 如果不存在,则添加到合并Map中 + Map newData = new HashMap<>(shopData); + mergedShopData.put(currentShopId, newData); + } + } + + // 将合并后的数据转换回List + List finalShopDataList = new ArrayList<>(mergedShopData.values()); + + map.put("successCount",(successCount + allNum)); + map.put("waitCount",waitCount); + map.put("allData",finalShopDataList); + return map; + } + + } + + @GetMapping("/getTaskCountByTaskTypeAll") + public Long getTaskCountByTaskType(){ + return runningTaskService.selectTaskStatusRunningCount(); + } + + @GetMapping("/logsDetailList/{taskId}/{shopId}") + @SaIgnore + public List logsDetailList(@PathVariable("taskId") String taskId, + @PathVariable("shopId") String shopId){ + + List voList = new ArrayList<>(); + TaskVo taskVo = taskService.queryById(Long.parseLong(taskId)); + if(taskVo.getTaskType().equals("GET_SHOP_GOODS") || taskVo.getTaskType().equals("GET_KW_SHOP_GOODS")){ + voList = runningTaskByShopService.selectTaskShopNum("t_running_task_"+taskVo.getShopIds(),taskVo.getId()); + }else{ + String filePath = "https://book.center.file.buzhiyushu.cn/task_log/task-log-csv/"+taskId+"/"+taskId+".csv"; + + if(UploadUtil.isFileExists(filePath)){ + try { + List> mapList = CsvUtils.readCsvAsMap("https://book.center.file.buzhiyushu.cn/task_log/task-log-csv/"+taskId+"/"+"StatusLog_"+shopId+".csv"); + + for(Map map : mapList){ + RunningTaskNumVo vo = new RunningTaskNumVo(); + vo.setAllNum(Integer.parseInt(map.get("all_num").toString())); + vo.setStatus(map.get("status").toString()); + vo.setTaskId(Long.parseLong(taskId)); + vo.setShopId(Long.parseLong(shopId)); + vo.setMsg(map.get("call_back_data").toString()); + voList.add(vo); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + List dbList = runningTaskService.selectTaskShopNum(Long.parseLong(taskId),Long.parseLong(shopId)); + + // 合并 voList 和 dbList,msg 相同的 allNum 相加 + Map mergedMap = new HashMap<>(); + + // 先处理 dbList + for (RunningTaskNumVo dbVo : dbList) { + String key = dbVo.getMsg(); + if (mergedMap.containsKey(key)) { + // 如果已存在相同 msg,则累加 allNum + RunningTaskNumVo existingVo = mergedMap.get(key); + existingVo.setAllNum(existingVo.getAllNum() + dbVo.getAllNum()); + } else { + // 如果不存在,则添加到 map 中 + mergedMap.put(key, dbVo); + } + } + + // 再处理 voList(CSV 数据) + for (RunningTaskNumVo csvVo : voList) { + String key = csvVo.getMsg(); + if (mergedMap.containsKey(key)) { + // 如果已存在相同 msg,则累加 allNum + RunningTaskNumVo existingVo = mergedMap.get(key); + existingVo.setAllNum(existingVo.getAllNum() + csvVo.getAllNum()); + } else { + // 如果不存在,则添加到 map 中 + mergedMap.put(key, csvVo); + } + } + + // 将合并后的结果重新赋值给 voList + voList = new ArrayList<>(mergedMap.values()); + } + + ShopVo shopVo = new ShopVo(); + for (int i=0;i< voList.size();i++){ + if(i == 0){ + shopVo = shopService.queryById(voList.get(0).getShopId()); + } + voList.get(i).setShopName(shopVo.getShopName()); + } + return voList; + } + + @GetMapping("/logsMsg") + @SaIgnore + public String logsMsg(String id){ + String msg = EasyExcelUtil.readFileContentString(UrlUtil.getUrl()+id+"-msg.txt"); + return msg; + } + + @SaIgnore + @GetMapping("/downloadLogs") + public ResponseEntity downloadLogs(String taskId, String shopId, HttpServletResponse response) { + File tempFile = null; + try { + // 调用接口获取数据 + String url = "https://task.log.buzhiyushu.cn/getTaskLog?taskId=" + taskId + "&shopId=" + shopId; + String logData = restTemplate.getForObject(url, String.class); + + // 解析JSON数据 + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(logData); + + // 获取数据库的日志 + List> taskLogMap = runningTaskService.selectLogByTaskId(Long.parseLong(taskId)); + + // 创建临时文件 + tempFile = File.createTempFile("task_log", ".csv"); + StringWriter stringWriter = new StringWriter(); + CSVWriter csvWriter = new CSVWriter(stringWriter); + + // 固定表头顺序和汉化 + String[] headers = {"isbn", "价格", "库存", "日志", "三方平台id"}; + csvWriter.writeNext(headers); + + // 合并数据:先添加接口返回的数据 + List> allData = new ArrayList<>(); + + // 处理接口返回的数据 + if (rootNode.get("code").asInt() == 200 && rootNode.has("data")) { + JsonNode dataNode = rootNode.get("data"); + if (dataNode != null && dataNode.isArray() && dataNode.size() > 0) { + for (JsonNode item : dataNode) { + Map rowData = new HashMap<>(); + + // isbn + rowData.put("isbn", item.has("isbn") ? item.get("isbn").asText() : ""); + + // totalPrice 分转元 + if (item.has("totalPrice")) { + String totalPriceStr = item.get("totalPrice").asText(); + try { + double priceInFen = Double.parseDouble(totalPriceStr); + double priceInYuan = priceInFen / 100.0; + rowData.put("价格", String.format("%.2f", priceInYuan)); + } catch (NumberFormatException e) { + rowData.put("价格", totalPriceStr); // 如果转换失败,保持原值 + } + } else { + rowData.put("价格", ""); + } + + // stock + rowData.put("库存", item.has("stock") ? item.get("stock").asText() : ""); + + // call_back_data + rowData.put("日志", item.has("call_back_data") ? item.get("call_back_data").asText() : ""); + + // trilateralId + rowData.put("三方平台id", item.has("trilateralId") ? item.get("trilateralId").asText() : ""); + + allData.add(rowData); + } + } + } + + // 添加数据库查询的日志数据 + for (Map dbLog : taskLogMap) { + Map rowData = new HashMap<>(); + + // 转换数据库中的字段,确保key与接口数据一致 + rowData.put("isbn", dbLog.get("isbn") != null ? dbLog.get("isbn").toString() : ""); + + // 价格处理(假设数据库中存储的是分,需要转换为元) + if (dbLog.get("totalPrice") != null) { + try { + double priceInFen = Double.parseDouble(dbLog.get("totalPrice").toString()); + double priceInYuan = priceInFen / 100.0; + rowData.put("价格", String.format("%.2f", priceInYuan)); + } catch (NumberFormatException e) { + rowData.put("价格", dbLog.get("totalPrice").toString()); + } + } else { + rowData.put("价格", ""); + } + + // 库存 + rowData.put("库存", dbLog.get("stock") != null ? dbLog.get("stock").toString() : ""); + + // 日志 + rowData.put("日志", dbLog.get("call_back_data") != null ? dbLog.get("call_back_data").toString() : ""); + + // 三方平台id + rowData.put("三方平台id", dbLog.get("trilateralId") != null ? dbLog.get("trilateralId").toString() : ""); + + allData.add(rowData); + } + + // 写入所有数据到CSV + for (Map rowData : allData) { + List row = new ArrayList<>(); + // 按照表头顺序添加数据 + for (String header : headers) { + row.add(rowData.getOrDefault(header, "")); + } + csvWriter.writeNext(row.toArray(new String[0])); + } + + csvWriter.close(); + + // 写入文件 + try (FileWriter fileWriter = new FileWriter(tempFile)) { + fileWriter.write(stringWriter.toString()); + } + + // 设置响应头 + String fileName = "taskLog.csv"; + Resource resource = new FileSystemResource(tempFile); + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()); + + // 添加临时文件删除钩子 + tempFile.deleteOnExit(); + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"") + .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8")) + .body(resource); + + } catch (Exception e) { + e.printStackTrace(); + // 异常情况下也尝试生成空CSV文件 + try { + if (tempFile == null) { + tempFile = File.createTempFile("task_log", ".csv"); + } + + StringWriter stringWriter = new StringWriter(); + CSVWriter csvWriter = new CSVWriter(stringWriter); + String[] headers = {"isbn", "价格", "库存", "日志", "三方平台id"}; + csvWriter.writeNext(headers); + csvWriter.close(); + + try (FileWriter fileWriter = new FileWriter(tempFile)) { + fileWriter.write(stringWriter.toString()); + } + + String fileName = "taskLog.csv"; + Resource resource = new FileSystemResource(tempFile); + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()); + + tempFile.deleteOnExit(); + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"") + .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8")) + .body(resource); + + } catch (Exception ex) { + ex.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + } + } + } + + /** + * 导出任务列表列表 + */ + @SaCheckPermission("zhishu:task:export") + @Log(title = "任务列表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TaskBo bo, HttpServletResponse response) { + List list = taskService.queryList(bo); + ExcelUtil.exportExcel(list, "任务列表", TaskVo.class, response); + } + + /** + * 获取店铺重复数据 + */ + @GetMapping("/getRepeatData") + @SaIgnore + public Page getRepeatData(Long shopId, Long pageNum, Long pageSize){ + return runningTaskByShopService.selectRepeat("t_running_task_"+shopId,pageNum,pageSize); + } + + /** + * 获取任务列表详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:task:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(taskService.queryById(id)); + } + + /** + * 新增任务列表 + */ + @SaCheckPermission("zhishu:task:add") + @Log(title = "任务列表", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody Map map) { + + //获取用户系统库数据 + LoginUser user = LoginHelper.getLoginUser(); + //更新方式 0 过滤重复 2 全新上传 + String way = map.get("way").toString(); + //任务类型 + String taskType = map.get("taskType").toString(); + //店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(",") ; + + //图书列表 + Map data = map.get("data") == null ? new HashMap() : (Map) map.get("data"); + //文件名称 + String taskExcelName = data.get("fileName") == null ? "" : data.get("fileName").toString(); + //店铺名称 + String shopNames = ""; + List validShopIds = new ArrayList<>(); + + long currentTime = System.currentTimeMillis(); + + for(String shopId:shopIdsArr) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 判断店铺是否无效 + boolean isInvalid = false; + if(currentTime > shopVo.getExpirationTime().getTime()){ + isInvalid = true; + }else if (!shopVo.getShopType().equals("1") && (shopVo.getIsExpiration().equals("0") || shopVo.getIsExpiration().equals("2") || StringUtils.isEmpty(shopVo.getIsExpiration()))){ + isInvalid = true; + }else if(shopService.checkUsageCount(shopVo) == 0){ + isInvalid = true; + } + // 如果店铺无效,跳过后续处理 + if (isInvalid) { + continue; + } + // 记录有效店铺ID + validShopIds.add(shopId); + if (shopNames.equals("")) { + shopNames = shopVo.getShopName(); + } else { + shopNames = shopNames + "," + shopVo.getShopName(); + } + + // 根据shopId查询数据表是否存在 + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopId); + if (checkMark == 0) { + // 不存在则创建表 + runningTaskByShopService.createTable("t_running_task_" + shopId); + } + } + + if (validShopIds.isEmpty()){ + throw new RuntimeException("请选择有效店铺"); + } + + // 如果需要更新原始的shopIdsArr为有效店铺ID数组 + shopIdsArr = validShopIds.toArray(new String[0]); + + if(taskType.equals("EDIT_GOODS_STOCK")){ + String[] shopNamesArr = shopNames.split(","); + + // 确保两个数组长度一致 + if (shopIdsArr.length != shopNamesArr.length) { + throw new RuntimeException("shopIds 和 shopNames 数量不匹配"); + } + + // 获取每个店铺的数据量 + Long total = Long.parseLong(data.get("total").toString()); + + // 使用索引遍历,为每个店铺创建独立的任务 + for (int i = 0; i < shopIdsArr.length; i++) { + // 清理数据:去除前后空格 + String shopId = shopIdsArr[i].trim(); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + + List list = null; + try { + list = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),BookVo.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count",list.size()+""); + createMap.put("task_type","5"); + createMap.put("img_type","1"); + + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + map.put("createResStr",createResStr); + + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (createResMap.get("code").equals("500")){ + throw new RuntimeException(createResMap.get("msg").toString()); + } + + /** + * 调用线程执行任务 + * 注意:这里需要传递 taskBo 对象到 TaskRunnable + * 如果 TaskRunnable 构造函数需要原始 map,可能需要调整 map 中的 shopIds + */ + // 如果需要,可以创建一个新的 map,只包含当前店铺的 shopId + Map singleShopMap = new HashMap<>(map); + singleShopMap.put("shopIds", shopId); // 更新为单个 shopId + + TaskRunnable taskRunnable = new TaskRunnable(taskService, singleShopMap, taskBo, user, applicationContext, "4"); + Thread thread = new Thread(taskRunnable); + thread.start(); + } + }else if(taskType.equals("STOCK_SYNCHRONIZE")){ + /** + * 手动库存同步任务 + */ + String[] shopNamesArr = shopNames.split(","); + + // 确保两个数组长度一致 + if (shopIdsArr.length != shopNamesArr.length) { + throw new RuntimeException("shopIds 和 shopNames 数量不匹配"); + } + //// 获取每个店铺的数据量 +// Long total = Long.parseLong(data.get("total").toString()); + // 使用索引遍历,为每个店铺创建独立的任务 + for (int i = 0; i < shopIdsArr.length; i++) { + // 清理数据:去除前后空格 + String shopId = shopIdsArr[i].trim(); + String shopName = shopNamesArr[i].trim(); + + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + + // 存储任务信息 + taskBo.setTaskType(taskType); + taskBo.setFileName("excel表格更新:" + taskExcelName); + taskBo.setShopIds(shopId); // 只设置单个 shopId + taskBo.setShopNames(shopName); // 只设置单个 shopName + taskBo.setDataNum(0L); // 单个店铺的数据量(不需要乘以店铺数量) + taskBo.setTaskStatus("0"); + taskService.insertByBo(taskBo); + + /** + * 调用线程执行任务 + * 注意:这里需要传递 taskBo 对象到 TaskRunnable + * 如果 TaskRunnable 构造函数需要原始 map,可能需要调整 map 中的 shopIds + */ + // 如果需要,可以创建一个新的 map,只包含当前店铺的 shopId + Map singleShopMap = new HashMap<>(map); + singleShopMap.put("shopIds", shopId); // 更新为单个 shopId + + TaskRunnable taskRunnable = new TaskRunnable(taskService, singleShopMap, taskBo, user, applicationContext, "6"); + Thread thread = new Thread(taskRunnable); + thread.start(); + } + + } else if(taskType.equals("EDIT_ISONSALE_GOODS")){ + // 更新商品上下架状态 + String[] shopNamesArr = shopNames.split(","); + // 确保两个数组长度一致 + if (shopIdsArr.length != shopNamesArr.length) { + throw new RuntimeException("shopIds 和 shopNames 数量不匹配"); + } + for (int i = 0; i < shopIdsArr.length; i++) { + // 清理数据:去除前后空格 + String shopId = shopIdsArr[i].trim(); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + + List list = null; + try { + list = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),BookVo.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count",list.size()+""); + createMap.put("task_type","5"); + createMap.put("img_type","1"); + + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + map.put("createResStr",createResStr); + + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (createResMap.get("code").equals("500")){ + throw new RuntimeException(createResMap.get("msg").toString()); + } + /** + * 调用线程执行任务 + * 注意:这里需要传递 taskBo 对象到 TaskRunnable + * 如果 TaskRunnable 构造函数需要原始 map,可能需要调整 map 中的 shopIds + */ + // 如果需要,可以创建一个新的 map,只包含当前店铺的 shopId + Map singleShopMap = new HashMap<>(map); + singleShopMap.put("shopIds", shopId); // 更新为单个 shopId + TaskRunnable taskRunnable = new TaskRunnable(taskService, singleShopMap, taskBo, user, applicationContext, "5"); + Thread thread = new Thread(taskRunnable); + thread.start(); + } + }else if(taskType.equals("DELETE_SHOP_GOODS")){ + /** + * 定时删除商品任务 + */ + // 删除数量 + String deleteNum = map.get("deleteNum").toString(); + for (int i = 0; i < shopIdsArr.length; i++) { + String shopId = shopIdsArr[i].trim(); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count",deleteNum); + createMap.put("task_type","10"); + createMap.put("img_type","1"); + createMap.put("del_num",deleteNum); + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + map.put("createResStr",createResStr); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (createResMap.get("code").equals("500")){ + throw new RuntimeException(createResMap.get("msg").toString()); + } + } + + }else if(way.equals("3") || taskType.equals("UPDATE_GOODS_PRICE")){ + // 3 仅更新价格 + // 拆分 shopNames(假设 shopNames 也是逗号分隔的字符串) + String[] shopNamesArr = shopNames.split(","); + if (shopIdsArr.length != shopNamesArr.length) { + throw new RuntimeException("shopIds 和 shopNames 数量不匹配"); + } + for (int i = 0; i < shopIdsArr.length; i++) { + // 清理数据:去除前后空格 + String shopId = shopIdsArr[i].trim(); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + + List list = null; + try { + list = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),BookVo.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count",list.size()+""); + createMap.put("task_type","5"); + createMap.put("img_type","1"); + + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + map.put("createResStr",createResStr); + + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (createResMap.get("code").equals("500")){ + throw new RuntimeException(createResMap.get("msg").toString()); + } + + + /** + * 调用线程执行任务 + * 注意:这里需要传递 taskBo 对象到 TaskRunnable + * 如果 TaskRunnable 构造函数需要原始 map,可能需要调整 map 中的 shopIds + */ + // 如果需要,可以创建一个新的 map,只包含当前店铺的 shopId + Map singleShopMap = new HashMap<>(map); + singleShopMap.put("shopIds", shopId); // 更新为单个 shopId + + TaskRunnable taskRunnable = new TaskRunnable(taskService, singleShopMap, taskBo, user, applicationContext, "2"); + Thread thread = new Thread(taskRunnable); + thread.start(); + } + }else if(taskType.equals("UPDATE_GOODS_TASK")){ + String[] shopNamesArr = shopNames.split(","); + if (shopIdsArr.length != shopNamesArr.length) { + throw new RuntimeException("shopIds 和 shopNames 数量不匹配"); + } + for (int i = 0; i < shopIdsArr.length; i++) { + // 清理数据:去除前后空格 + String shopId = shopIdsArr[i].trim(); + String shopName = shopNamesArr[i].trim(); + + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + + // 存储任务信息 + taskBo.setTaskType(taskType); + taskBo.setFileName("excel表格更新商品:" + taskExcelName); + taskBo.setShopIds(shopId); // 只设置单个 shopId + taskBo.setShopNames(shopName); // 只设置单个 shopName + taskBo.setDataNum(0L); // 单个店铺的数据量(不需要乘以店铺数量) + taskBo.setTaskStatus("0"); + taskService.insertByBo(taskBo); + + /** + * 调用线程执行任务 + * 注意:这里需要传递 taskBo 对象到 TaskRunnable + * 如果 TaskRunnable 构造函数需要原始 map,可能需要调整 map 中的 shopIds + */ + // 如果需要,可以创建一个新的 map,只包含当前店铺的 shopId + Map singleShopMap = new HashMap<>(map); + singleShopMap.put("shopIds", shopId); // 更新为单个 shopId + + TaskRunnable taskRunnable = new TaskRunnable(taskService, singleShopMap, taskBo, user, applicationContext, "7"); + Thread thread = new Thread(taskRunnable); + thread.start(); + } + }else if(way.equals("0") || way.equals("2")){ + String[] shopNamesArr = shopNames.split(","); + + // 确保两个数组长度一致 + if (shopIdsArr.length != shopNamesArr.length) { + throw new RuntimeException("shopIds 和 shopNames 数量不匹配"); + } + + // 获取每个店铺的数据量 + Long total = Long.parseLong(data.get("total").toString()); + + // 使用索引遍历,为每个店铺创建独立的任务 + for (int i = 0; i < shopIdsArr.length; i++) { + // 清理数据:去除前后空格 + String shopId = shopIdsArr[i].trim(); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 根据shopId查询数据表是否存在 + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopId); + if (checkMark == 0) { + // 不存在则创建表 + runningTaskByShopService.createTable("t_running_task_" + shopId); + } + + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + List list = null; + try { + list = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),BookVo.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count",list.size()+""); + createMap.put("task_type","2"); + + // 图片类型 1 仅官图 2 仅实拍图 11 优先实拍图 12 优先官图 + String imageSelect = map.get("imageSelect").toString(); + // 对应 1 仅官图 2 仅实拍图 3 优先官图 4 优先实拍图 + switch (imageSelect){ + case "1","2":createMap.put("img_type",imageSelect);break; + case "12":createMap.put("img_type","3");break; + case "11":createMap.put("img_type","4");break; + } + + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + map.put("createResStr",createResStr); + + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (createResMap.get("code").equals("500")){ + throw new RuntimeException(createResMap.get("msg").toString()); + } + + taskBo.setWay(way); + /** + * 调用线程执行任务 + * 注意:这里需要传递 taskBo 对象到 TaskRunnable + * 如果 TaskRunnable 构造函数需要原始 map,可能需要调整 map 中的 shopIds + */ + // 如果需要,可以创建一个新的 map,只包含当前店铺的 shopId + Map singleShopMap = new HashMap<>(map); + singleShopMap.put("shopIds", shopId); // 更新为单个 shopId + + TaskRunnable taskRunnable = new TaskRunnable(taskService, singleShopMap, taskBo, user, applicationContext, "1"); + Thread thread = new Thread(taskRunnable); + thread.start(); + } + } + return toAjax(1); + } + + /** + * 新增任务列表 + */ + @SaIgnore + @PostMapping("/centerBooks") + public Map centerBooks(String jsonStr) { + + //接受数据 + Map dataMap = JsonUtil.transferToObj(jsonStr, HashMap.class); + + //任务名称 + String fileName = dataMap.get("taskId").toString(); + + String way = dataMap.get("way") == null ? "2" : dataMap.get("way").toString(); + + TaskVo taskVo = taskService.selectByFileName(fileName); + + //获取用户系统库数据 + LoginUser user = new LoginUser(); + user.setUserId(taskVo.getCreateBy()); + + TaskBo taskBo = new TaskBo(); + //存储任务信息 + taskBo.setId(taskVo.getId()); + taskBo.setShopIds(taskVo.getShopIds()); + taskBo.setShopNames(taskVo.getShopNames()); + taskBo.setTaskType(taskVo.getTaskType()); + taskBo.setDataNum(taskVo.getDataNum()); + taskBo.setTaskStatus("1"); + + //是否使用官图 + String imageSelect = dataMap.get("imageSelect") == null ? "" : dataMap.get("imageSelect").toString(); + //获取商品信息重新封装 + List result = (List) dataMap.get("result"); + List list = new ArrayList<>(); + for(Map map : result){ + Map newMap = new HashMap(); + newMap.put("bookNum",map.get("isbn")); + newMap.put("price",map.get("totalPrice")); +// newMap.put("stock","1"); + if(imageSelect.equals("11")){ + newMap.put("bookImgUrl", map.get("imgBigUrl") == null || StringUtils.isEmpty(map.get("imgBigUrl").toString())? "" : map.get("imgBigUrl").toString()); + } + list.add(newMap); + } + + Map map = new HashMap(); + map.put("taskType", "1"); + map.put("way", way); + map.put("listStatus", "1"); + map.put("bookCategory", "0"); + map.put("shopIds", taskVo.getShopIds()); + map.put("data", list); + map.put("imageSelect",imageSelect); + + /** + * 调用线程执行任务 + */ + TaskRunnable taskRunnable = new TaskRunnable(taskService, map,taskBo,user,applicationContext,"3"); + Thread thread = new Thread(taskRunnable); + thread.start(); + + + + Map returnMap = new HashMap(); + returnMap.put("success", true); + returnMap.put("code","200"); + returnMap.put("message","执行成功"); + return returnMap; + } + + /** + * 暂停线程 + * @param threadId + */ + @GetMapping("/pauseThread/{threadId}/{taskId}") + public void pauseThread(@PathVariable("threadId") String threadId,@PathVariable("taskId") Long taskId){ + + Map map = JsonUtil.transferToObj(threadId,Map.class); + if(map.get("threadId") != null && StringUtils.isNotEmpty(map.get("threadId").toString())){ + //threadId 不为空时,暂停erp线程 : threadId是excel上传文件存储的线程id + taskService.zanTing(map.get("threadId").toString()); + }else if(map.get("threadIdGoods") != null && StringUtils.isNotEmpty(map.get("threadIdGoods").toString())){ + //threadIdGoods 是 勾选商品上传生成的系统任务的线程id + zhishuShopGoodsService.zanTing(map.get("threadIdGoods").toString()); + }else{ + if(map.get("pddThreadId") != null && StringUtils.isNotEmpty(map.get("pddThreadId").toString())){ + String pddIp = configService.selectConfigByKey("pdd.ip"); + InterfaceUtils.getInterface(pddIp,"/api/pdd/auth/zanTing/"+map.get("pddThreadId").toString()); + } + if(map.get("kongfzThreadId") != null && StringUtils.isNotEmpty(map.get("kongfzThreadId").toString())){ + String kongfzIp = configService.selectConfigByKey("kongfz.ip"); + InterfaceUtils.getInterface(kongfzIp,"/api/kfz/zanTing/"+map.get("kongfzThreadId").toString()); + } + } + + TaskBo taskBo = new TaskBo(); + taskBo.setId(taskId); + taskBo.setTaskStatus("2"); + taskService.updateByBo(taskBo); + } + + /** + * 继续执行线程 + * @param threadId + */ + @GetMapping("/continueThread/{threadId}/{taskId}") + public void continueThread(@PathVariable("threadId") String threadId,@PathVariable("taskId") Long taskId){ + + Map map = JsonUtil.transferToObj(threadId,Map.class); + if(map.get("threadId") != null && StringUtils.isNotEmpty(map.get("threadId").toString())){ + //threadId 不为空时,恢复erp线程 + taskService.huanXing(map.get("threadId").toString()); + }else if(map.get("threadIdGoods") != null && StringUtils.isNotEmpty(map.get("threadIdGoods").toString())){ + //threadIdGoods 是 勾选商品上传生成的系统任务的线程id + zhishuShopGoodsService.huanXing(map.get("threadIdGoods").toString()); + } else{ + //为空时,恢复pdd和kfz的线程 + if(map.get("pddThreadId") != null && StringUtils.isNotEmpty(map.get("pddThreadId").toString())){ + String pddIp = configService.selectConfigByKey("pdd.ip"); + InterfaceUtils.getInterface(pddIp,"/api/pdd/auth/huanXing/"+map.get("pddThreadId").toString()); + } + if(map.get("kongfzThreadId") != null && StringUtils.isNotEmpty(map.get("kongfzThreadId").toString())){ + String kongfzIp = configService.selectConfigByKey("kongfz.ip"); + InterfaceUtils.getInterface(kongfzIp,"/api/kfz/huanXing/"+map.get("kongfzThreadId").toString()); + } + } + TaskBo taskBo = new TaskBo(); + taskBo.setId(taskId); + taskBo.setTaskStatus("1"); + taskService.updateByBo(taskBo); + } + + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "发布任务数据", BookVo.class, response); + } + + + /** + * 更新商品信息导入模板 + */ + @PostMapping("/importUpdateGoodsTemplate") + public void importUpdateGoodsTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "sheet", SuccessDataItemDto.class, response); + } + + /** + * 更新价格的导入模板 + * @param response + */ + @PostMapping("/importEditPriceTemplate") + public void importEditPriceTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "更新价格任务数据", BookEditPriceVo.class, response); + } + + /** + * 更新价格的导入模板 + * @param response + */ + @PostMapping("/importEditStockTemplate") + public void importEditStockTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "更新库存任务数据", BookEditStockVo.class, response); + } + + /** + * 更新商品上下架状态的导入模板 + * @param response + */ + @PostMapping("/importEditIsOnSaleTemplate") + public void importEditIsOnSaleTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "更新上下架任务数据", BookEditIsOnsaleVo.class, response); + } + + /** + * 修改任务列表 + */ + @SaCheckPermission("zhishu:task:edit") + @Log(title = "任务列表", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TaskBo bo) { + return toAjax(taskService.updateByBo(bo)); + } + + /** + * 删除任务列表 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:task:remove") + @Log(title = "任务列表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + Long userId = LoginHelper.getUserId(); + for(Long id : ids){ + Task task=taskService.getTaskBoById(id.toString()); + if(task!=null && task.getTaskType().equals("GET_SHOP_GOODS")){ + String[] shopIds = task.getShopIds().split(","); + for (String shopId : shopIds){ + //解决拉取商品任务 + runningTaskService.updataStatus(Long.parseLong(shopId),id); + + } + }else{ + String[] shopIds = task.getShopIds().split(","); + for (String shopId : shopIds){ + TaskPause taskPause = new TaskPause(); + taskPause.setCreateBy(userId); + taskPause.setTaskId(id); + taskPause.setShopId(Long.parseLong(shopId)); + taskPauseService.insert(taskPause); + } + + //删除任务 + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(id); + runningTask.setStatus("4"); + runningTask.setCallBackData("任务已删除"); + runningTaskService.update(runningTask); + } + //修改任务的状态为5 + Task bo = new Task(); + bo.setId(id); + bo.setTaskStatus("5"); + baseMapper.updateById(bo); + } +// return toAjax(taskService.deleteWithValidByIds(List.of(ids), true)); + return toAjax(1); + } + + @GetMapping("/getShopTaskAllNum") + @SaIgnore + public Map getShopTaskAllNum(String[] shopId,String isOnSale,String isbn,String priceDown,String priceUp,String startDate,String endDate,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode){ + Map result = new HashMap<>(); + for (String shopIdstr : shopId) { + int num = runningTaskByShopService.checkTableExists("t_running_task_" + shopIdstr); + if (num == 0) { + result.put(shopIdstr, 0); + } else { + int count = runningTaskByShopService.selectGetShopGoodsNum( + "t_running_task_" + shopIdstr, isOnSale, isbn, priceDown, priceUp, startDate, endDate,goodsName,stockDown,stockUp,trilateralId,goodsCode,skuCode); + result.put(shopIdstr, count); + } + } + + return result; + } + + @GetMapping("/selectTaskStatusByTaskType") + @SaIgnore + public R selectTaskStatusByTaskType(String shopId,String taskType){ + Long num = runningTaskService.selectTaskStatusByTaskType(Long.parseLong(shopId),taskType); + + if(num == 0){ + return R.ok(); + }else{ + return R.fail("当前店铺存在正在执行中的下架任务"); + } + } + + @PostMapping(value = "/upload") + public R upload(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + // 检测文件名中是否包含空格 + String filename = file.getOriginalFilename(); + if (filename != null && filename.contains(" ")) { + return R.fail("文件名中包含空格,请修改后重新上传"); + } + RedisUtils.deleteObject("taskExcelName"); + + + /** + * 存储书号到radis + */ + List list; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), SuccessDataItemDto.class, true); + // 获取原始数据并过滤掉所有字段都为空的无效行 + List rawList = excelResult.getList(); + List validList = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + + list = MapstructUtils.convert(validList, SuccessDataItemDto.class); + //校验是否必填 + for(int i=0;i result = fileClient.upload(UrlUtil.getFileServiceUrl(), base64Content, "TaskExcel", uuid+"_"+file.getOriginalFilename()); + + Map urlMap = JsonUtil.transferToObj(result.getData(),Map.class); + + Map map = new HashMap<>(); + map.put("total",list.size()); + map.put("url", urlMap.get("localPath")); + map.put("fileName",file.getOriginalFilename()); + + return R.ok(map); + } + + @PostMapping(value = "/updateGoods") + public R updateGoods(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + // 检测文件名中是否包含空格 + String filename = file.getOriginalFilename(); + if (filename != null && filename.contains(" ")) { + return R.fail("文件名中包含空格,请修改后重新上传"); + } + RedisUtils.deleteObject("taskExcelName"); + /** + * 存储书号到radis + */ + List list; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), UpdateBookVo.class, true); + list = MapstructUtils.convert(excelResult.getList(), UpdateBookVo.class); + if (list.isEmpty() || list.size() == 0){ + return R.fail("请勿上传空文件"); + } + //校验是否必填 + for(int i=0;i result = fileClient.upload(UrlUtil.getFileServiceUrl(), base64Content, "TaskExcel", uuid+"_"+file.getOriginalFilename()); + Map urlMap = JsonUtil.transferToObj(result.getData(),Map.class); + Map map = new HashMap<>(); + map.put("total",list.size()); + map.put("url", urlMap.get("localPath")); + map.put("fileName",file.getOriginalFilename()); + return R.ok(map); + } + + @PostMapping(value = "/uploadEditPrice") + public R uploadEditPrice(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + // 检测文件名中是否包含空格 + String filename = file.getOriginalFilename(); + if (filename != null && filename.contains(" ")) { + return R.fail("文件名中包含空格,请修改后重新上传"); + } + RedisUtils.deleteObject("taskExcelName"); + /** + * 存储书号到radis + */ + List list; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), SuccessDataItemDto.class, true); + + // 获取原始数据并过滤掉所有字段都为空的无效行 + List rawList = excelResult.getList(); + List validList = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + + list = MapstructUtils.convert(validList, SuccessDataItemDto.class); + + if (list.isEmpty() || list.size() == 0){ + return R.fail("请勿上传空文件"); + } + //校验是否必填 + for(int i=0;i result = fileClient.upload(UrlUtil.getFileServiceUrl(), base64Content, "TaskExcel", uuid+"_"+file.getOriginalFilename()); + + Map urlMap = JsonUtil.transferToObj(result.getData(),Map.class); + + Map map = new HashMap<>(); + map.put("total",list.size()); + map.put("url", urlMap.get("localPath")); + map.put("fileName",file.getOriginalFilename()); + + return R.ok(map); + } + + + @PostMapping(value = "/uploadEditStock") + public R uploadEditStock(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + // 检测文件名中是否包含空格 + String filename = file.getOriginalFilename(); + if (filename != null && filename.contains(" ")) { + return R.fail("文件名中包含空格,请修改后重新上传"); + } + RedisUtils.deleteObject("taskExcelName"); + /** + * 存储书号到radis + */ + List list; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), SuccessDataItemDto.class, true); + // 获取原始数据并过滤掉所有字段都为空的无效行 + List rawList = excelResult.getList(); + List validList = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + + list = MapstructUtils.convert(validList, SuccessDataItemDto.class); + + if (list.isEmpty() || list.size() == 0){ + return R.fail("请勿上传空文件"); + } + //校验是否必填 + for(int i=0;i result = fileClient.upload(UrlUtil.getFileServiceUrl(), base64Content, "TaskExcel", uuid+"_"+file.getOriginalFilename()); + + Map urlMap = JsonUtil.transferToObj(result.getData(),Map.class); + + Map map = new HashMap<>(); + map.put("total",list.size()); + map.put("url", urlMap.get("localPath")); + map.put("fileName",file.getOriginalFilename()); + + return R.ok(map); + } + + @PostMapping(value = "/uploadEditIsOnSale") + public R uploadEditIsOnSale(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + // 检测文件名中是否包含空格 + String filename = file.getOriginalFilename(); + if (filename != null && filename.contains(" ")) { + return R.fail("文件名中包含空格,请修改后重新上传"); + } + RedisUtils.deleteObject("taskExcelName"); + /** + * 存储书号到radis + */ + List list; + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), SuccessDataItemDto.class, true); + + // 获取原始数据并过滤掉所有字段都为空的无效行 + List rawList = excelResult.getList(); + List validList = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + + list = MapstructUtils.convert(validList, SuccessDataItemDto.class); + + if (list.isEmpty() || list.size() == 0){ + return R.fail("请勿上传空文件"); + } + //校验是否必填 + for(int i=0;i result = fileClient.upload(UrlUtil.getFileServiceUrl(), base64Content, "TaskExcel", uuid+"_"+file.getOriginalFilename()); + Map urlMap = JsonUtil.transferToObj(result.getData(),Map.class); + Map map = new HashMap<>(); + map.put("total",list.size()); + map.put("url", urlMap.get("localPath")); + map.put("fileName",file.getOriginalFilename()); + return R.ok(map); + } + + @SaIgnore + @GetMapping("/finishTash/{taskId}") + public String finishTash(@PathVariable String taskId){ + //读取文件,看店铺任务是否全部完成 + String fileName = taskId+".txt"; + List> logsMapList = EasyExcelUtil.readFileContent(UrlUtil.getUrl() +fileName); + + for(Map map : logsMapList){ + if(!map.get("progress").equals("100.00")){ + return "未全部执行完毕"; + } + } + TaskBo taskBo = new TaskBo(); + taskBo.setId(Long.parseLong(taskId)); + taskBo.setTaskStatus("3"); + taskService.updateByBo(taskBo); + return "任务已完成"; + } + + @GetMapping("/checkFile") + public String checkFile(){ + String taskExcelName = RedisUtils.getCacheObject("taskExcelName"); + return taskExcelName; + } + @GetMapping("/delFile") + public void delFile(){ + RedisUtils.deleteObject("taskExcelName"); + } + + @PostMapping("/tbStock") + public R tbStock(@RequestBody Map map){ + String[] taskIds = map.get("ids").toString().split(","); + String depotId = map.get("depotId").toString(); + + //存储上传成功的商品 + List shopGoodsBoList = new ArrayList<>(); + // 获取当前登录用户的ID + Long userId = LoginHelper.getUserId(); + //遍历任务 + for(String taskId : taskIds){ + TaskVo task = taskService.queryById(Long.parseLong(taskId)); + //根据taskid和shopid 获取txt文件读取 "上传成功" 类型的 xlsx的文件名 + String[] shopIds = task.getShopIds().split(","); + for(String shopId : shopIds){ + String fileName = UrlUtil.getUrl() + task.getId() + shopId + ".txt"; + List> mapList = EasyExcelUtil.readFileContent(fileName); + //遍历店铺类型 + for(Map chiledMap : mapList){ + if(chiledMap.get("logName").equals("上传成功")){ + //获取文件名 + String successPath = UrlUtil.getUrl() + chiledMap.get("mark") + ".xlsx"; + //获取上传成功文件List + List> shopSuccessList =EasyExcelUtil.convertExcelToMap(successPath); + for(Map successMap : shopSuccessList){ + ZhishuShopGoodsBo zhishuShopGoodsBo = new ZhishuShopGoodsBo(); + + + zhishuShopGoodsBo.setIsbn(successMap.get("书号").toString()); + + + zhishuShopGoodsBo.setGoodsName(successMap.get("书名").toString()); + zhishuShopGoodsBo.setPrice(Long.parseLong(successMap.get("价格").toString())); + zhishuShopGoodsBo.setStock(Long.parseLong(successMap.get("库存").toString())); + zhishuShopGoodsBo.setConditionCode("九品"); + zhishuShopGoodsBo.setUserId(userId); + zhishuShopGoodsBo.setProductId(""); + zhishuShopGoodsBo.setOriginalArtNo(""); + zhishuShopGoodsBo.setCreateBy(userId); + zhishuShopGoodsBo.setInventory(Long.parseLong(successMap.get("库存").toString())); + zhishuShopGoodsBo.setFixPrice(0L); + + //存储店铺id和三方平台id + Map params = new HashMap(); + params.put("shopId", shopId); + params.put("trilateralId", successMap.get("三方平台商品id").toString()); + zhishuShopGoodsBo.setParams(params); + + shopGoodsBoList.add(zhishuShopGoodsBo); + } + } + } + } + } + Boolean bool = zhishuShopGoodsService.insertList(shopGoodsBoList, Long.parseLong(depotId), "系统excel上传成功入库"); + if(bool){ + return R.ok("同步仓库成功"); + }else{ + return R.fail("同步仓库失败"); + } + } + + + //写入文件中 + @SaIgnore + @PostMapping("/taskRunningFile") + public synchronized String taskRunningFile(@RequestBody Map map) { + String type = map.get("type").toString(); + + if(type.equals("1")){ + String filePath = map.get("filePath").toString(); + List> data = (List>) map.get("data"); + Map headMap = (Map) map.get("headMap"); + EasyExcelUtil.writeExcel(filePath,data,headMap); + }else if(type.equals("2")){ + String fileName = map.get("fileName").toString(); + List> data = (List>) map.get("data"); + EasyExcelUtil.writeJsonToFile(fileName,data); + }else if(type.equals("3")){ + String fileName = map.get("fileName").toString(); + String jsonString = map.get("jsonString").toString(); + EasyExcelUtil.writeJsonToFile(fileName,jsonString); + }else if(type.equals("4")){ + String filePath = map.get("filePath").toString(); + List> list = new ArrayList<>(); + if(FileUtils.isFileExists(filePath)){ + list =EasyExcelUtil.readFileContent(filePath); + } + return JSON.toJSONString(list); + }else if(type.equals("5")){ + String filePath = map.get("filePath").toString(); + return EasyExcelUtil.readFileContentString(filePath); + }else if(type.equals("6")){ + String excelFilePath = map.get("excelFilePath").toString(); + List list = (List) map.get("list"); + EasyExcelUtil.continuousWriting(excelFilePath, list); + } + return ""; + } + + /** + * 删除PDD任务列表 + * + * @param bos 主键串 + */ + @SaCheckPermission("zhishu:task:remove") + @Log(title = "任务列表", businessType = BusinessType.DELETE) + @DeleteMapping("/delPdds") + public R removePdd(@RequestBody TaskBo[] bos) { + for(TaskBo bo : bos){ + TaskPause taskPause = new TaskPause(); + taskPause.setTaskId(bo.getId()); + String[] shopIdArr = bo.getShopIds().split(","); + for (String shopId : shopIdArr){ + taskPause.setShopId(Long.parseLong(shopId)); + } + taskPauseService.insert(taskPause); + } +// return toAjax(taskService.deleteWithValidByIds(List.of(ids), true)); + return R.ok("中止成功"); + } + + /** + * 暂停任务列表 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:task:pause") + @Log(title = "任务列表", businessType = BusinessType.UPDATE) + @PutMapping("/{ids}") + public R pause(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + Long userId = LoginHelper.getUserId(); + for(Long id : ids){ + Task task=taskService.getTaskBoById(id.toString()); + if(task!=null && task.getTaskType().equals("GET_SHOP_GOODS")){ + String[] shopIds = task.getShopIds().split(","); + for (String shopId : shopIds){ + //解决拉取商品任务 + runningTaskService.updataStatus(Long.parseLong(shopId),id); + + } + }else{ + String[] shopIds = task.getShopIds().split(","); + for (String shopId : shopIds){ + TaskPause taskPause = new TaskPause(); + taskPause.setCreateBy(userId); + taskPause.setTaskId(id); + taskPause.setShopId(Long.parseLong(shopId)); + taskPauseService.insert(taskPause); + } + + + } + + } + return toAjax(1); + } + + @PostMapping("/stopTask") + @SaIgnore + public R stopTask(String taskId){ + InterfaceUtils.getInterfacePost("http://118.195.145.133:8099/task/shutdown/"+taskId,"",new HashMap<>()); + InterfaceUtils.getInterfacePost("http://119.45.237.193:8099/task/shutdown/"+taskId,"",new HashMap<>()); + InterfaceUtils.getInterfacePost("http://119.45.181.25:8099/task/shutdown/"+taskId,"",new HashMap<>()); + + TaskBo bo = new TaskBo(); + bo.setId(Long.parseLong(taskId)); + bo.setTaskStatus("5"); + taskService.updateByBo(bo); + return R.ok("任务停止成功"); + } + + @GetMapping("/getRunningTask") + @SaIgnore + public String getRunningTask(String pageSize,String pageNum){ + BigDecimal pageSizeInt = new BigDecimal(pageSize).multiply(new BigDecimal(pageNum)); + List listVo = taskService.selectRunningTask(Integer.parseInt(pageSizeInt.toString()),Integer.parseInt(pageNum)); + for(TaskVo vo : listVo){ + String msg = ""; + try{ + msg = EasyExcelUtil.readFileContentString(UrlUtil.getUrl()+vo.getId()+"-msg.txt"); + }catch(Exception e){ + + } + vo.setMsg(msg); + } + + ; + Map map = new HashMap(); + map.put("data",listVo); + map.put("total",taskService.selectRunningTaskCount()); + return JsonUtils.toJsonString(map); + } + + + /** + * + */ + @GetMapping("/editTaskDataNum") + @SaIgnore + public Boolean editTaskDataNum(Long shopIds,Long dataNum,String taskType){ + taskService.editTaskDataNum(String.valueOf(shopIds),dataNum,taskType); + return true; + } + /** + * 暂停任务 + */ + @PostMapping("/taskPause") + @SaIgnore + public R taskPause(Long taskId){ + taskService.taskPause(taskId); + return R.ok(); + } + + /** + * 恢复任务 + */ + @PostMapping("/taskRecover") + @SaIgnore + public R taskRecover(Long taskId){ + taskService.taskRecover(taskId); + return R.ok(); + } + + /** + * 修改任务优先级 + */ + @PostMapping("/editTaskPriority") + @SaIgnore + public R editTaskPriority(Long taskId){ + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(taskId); + runningTask.setPriority(254L); + runningTask.setEditStatus("0"); + runningTaskService.update(runningTask); + return R.ok(); + } + + + /** + * 查询店铺是否存在拉取任务 + */ + @GetMapping("/selectShopTaskByGetShopGoods") + @SaIgnore + public R selectShopTaskByGetShopGoods(Long shopId){ + String status = runningTaskByShopService.selectStatus("t_running_task_"+shopId); + + if(status.equals("3")){ + return R.ok(); + }else{ + return R.fail(500,"店铺正在执行拉取任务中"); + } + } + + +// /** +// * 修改整店两件折扣 +// * @param shopId +// */ +// @GetMapping("/editTwoPiecesDiscount") +// @SaIgnore +// public void editTwoPiecesDiscount(Long shopId){ +// taskService.editTwoPiecesDiscount(shopId); +// } + /** + * 检查同步状态 + */ + @SaIgnore + @GetMapping("/checkTaskStatus") + public R checkTaskStatus(@RequestParam("id") String id) { + // 获取同步任务 + Task task = taskService.getTaskBoByRelationId(id); + // 查询任务执行完成数 + if (ObjectUtil.isNotEmpty(task)) { + Long dataNum = zhishuShopGoodsService.getTaskDataNum(task.getId()); + if(!Objects.equals(dataNum,task.getDataNum())){ + return R.fail("任务正在同步中"); + }else{ + return R.ok("当前任务已完成"); + } + } + return R.ok(); + } + + + @PostMapping("/batch") + public List getShopsBatch(@RequestBody Map> requestData) { + List ids = requestData.get("ids"); + if (ids == null || ids.isEmpty()) { + throw new RuntimeException("店铺ID列表不能为空"); + } + return taskService.getShopsBatch(ids); + } + + /** + * 批量获取店铺详情信息 + */ + @PostMapping("/detail/batch") + public List getShopDetailsBatch(@RequestBody Map> requestData) { + List ids = requestData.get("ids"); + if (ids == null || ids.isEmpty()) { + throw new RuntimeException("店铺ID列表不能为空"); + } + return taskService.getShopDetailsBatch(ids); + } + + @PostMapping("/addShopGoods") + public Map addShopGoods(@RequestParam Map map){ + Map resMap = new HashMap<>(); + map.put("imageSelect","2"); + map.put("isMoreSku","0"); + map.put("priority","3"); + map.put("imageBigUrl",""); + map.put("quality","100"); + String taskId = map.get("taskId") == null ? "" : map.get("taskId").toString(); + if (StringUtils.isEmpty(taskId)){ + resMap.put("code","500"); + resMap.put("msg","taskId不能为空"); + return resMap; + } + Task task = taskService.getTaskBoById(taskId); + if (task == null){ + resMap.put("code","500"); + resMap.put("msg","任务不存在.taskId:"+taskId); + return resMap; + } + Long goodsId = map.get("trilateralId") == null ? null : Long.parseLong(map.get("trilateralId").toString()); + if (goodsId == null){ + resMap.put("code","500"); + resMap.put("msg","trilateralId不能为空"); + return resMap; + } + ShopVo shopVo = shopService.queryById(Long.parseLong(task.getShopIds())); + if (shopVo == null){ + resMap.put("code","500"); + resMap.put("msg","店铺不存在.shopId:"+task.getShopIds()); + return resMap; + } + map.put("shopType",shopVo.getShopType()); + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(Long.parseLong(taskId)); + runningTask.setTaskName("新发布商品任务"); + runningTask.setShopId(shopVo.getId()); + runningTask.setGoodsId(goodsId); + runningTask.setPriority(255L); + runningTask.setStatus("3"); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setCallBackData("上传成功"); + runningTask.setTaskType("NEW_TASK_ADD"); + runningTask.setCreateBy(shopVo.getCreateBy()); + runningTask.setSuccessData(JsonUtils.toJsonString(map)); + runningTaskByShopService.insert("t_running_task_"+shopVo.getId(),runningTask); + resMap.put("code","200"); + resMap.put("msg","插入成功"); + return resMap; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserController.java new file mode 100644 index 0000000..7080a93 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserController.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.RequiredArgsConstructor; +import org.dromara.common.web.core.BaseController; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/user") +public class UserController extends BaseController { + //新用户方法 + @SaCheckPermission("zhishu:user:newuser") + @GetMapping("/newuser") + public String newUser() { + // 返回新用户 + return "新用户"; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserTAuditController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserTAuditController.java new file mode 100644 index 0000000..a64a4b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserTAuditController.java @@ -0,0 +1,118 @@ +package org.dromara.zhishu.controller; + +import java.util.List; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.vo.UserTAuditVo; +import org.dromara.zhishu.domain.bo.UserTAuditBo; +import org.dromara.zhishu.service.IUserTAuditService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 列表 + * + * @author Lion Li + * @date 2025-04-02 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/userAudit") +public class UserTAuditController extends BaseController { + + private final IUserTAuditService userTAuditService; + + /** + * 查询列表列表 + */ + @SaCheckPermission("zhishu:userAudit:list") + @GetMapping("/list") + public TableDataInfo list(UserTAuditBo bo, PageQuery pageQuery) { + return userTAuditService.queryPageList(bo, pageQuery); + } + + /** + * 导出列表列表 + */ + @SaCheckPermission("zhishu:userAudit:export") + @Log(title = "列表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(UserTAuditBo bo, HttpServletResponse response) { + List list = userTAuditService.queryList(bo); + ExcelUtil.exportExcel(list, "列表", UserTAuditVo.class, response); + } + + /** + * 获取列表详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:userAudit:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(userTAuditService.queryById(id)); + } + + /** + * 新增列表 + */ + @SaCheckPermission("zhishu:userAudit:add") + @Log(title = "列表", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody UserTAuditBo bo) { + return toAjax(userTAuditService.insertByBo(bo)); + } + + /** + * 修改列表 + */ + @SaCheckPermission("zhishu:userAudit:edit") + @Log(title = "列表", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody UserTAuditBo bo) { + return toAjax(userTAuditService.updateByBo(bo)); + } + + /** + * 删除列表 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:userAudit:remove") + @Log(title = "列表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(userTAuditService.deleteWithValidByIds(List.of(ids), true)); + } + + + @SaIgnore +// @SaCheckPermission("zhishu:userAudit:remove") +// @Log(title = "列表", businessType = BusinessType.) + @GetMapping("/log") + public R getAuditLog() { + UserTAuditVo vo=userTAuditService.getAuditLog(); + return R.ok(vo); + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WarehouseSettingsAttributeController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WarehouseSettingsAttributeController.java new file mode 100644 index 0000000..8de596a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WarehouseSettingsAttributeController.java @@ -0,0 +1,26 @@ +package org.dromara.zhishu.controller; + +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.domain.WarehouseSettingsAttribute; +import org.dromara.zhishu.service.IWarehouseSettingsAttributeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/warehouseSettingAttribute") +public class WarehouseSettingsAttributeController { + + private final IWarehouseSettingsAttributeService warehouseSettingsAttributeService; + + @GetMapping("/getList") + public List getList(WarehouseSettingsAttribute warehouseSettingsAttribute){ + return warehouseSettingsAttributeService.selectList(warehouseSettingsAttribute); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WaveController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WaveController.java new file mode 100644 index 0000000..7b59a99 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WaveController.java @@ -0,0 +1,61 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.vo.WaveVo; +import org.dromara.zhishu.service.IWaveService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.List; +import java.util.HashMap; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/wave/api") +public class WaveController { + + private final IWaveService waveService; + + @SaIgnore + @GetMapping("/getStaffId") + public R> getStaffId() { + List staffIds = waveService.getStaffId(); + Map data = new HashMap<>(); + data.put("rows", staffIds); + data.put("total", staffIds.size()); + return R.ok("获取成功", data); + } + + @SaIgnore + @GetMapping("/getStaffList/{userId}") + public R> getStaffList(@PathVariable("userId") String userId) { // 修改返回类型 + List staffList = waveService.getStaffList(userId); + Map data = new HashMap<>(); + data.put("rows", staffList); + data.put("total", staffList.size()); + return R.ok("获取成功", data); + } + + @SaIgnore + @GetMapping("/getStaffName/{staffId}") + public R getStaffName(@PathVariable("staffId") String staffId) { + try { + String staffName = waveService.getStaffName(staffId); + + if (staffName != null && !staffName.trim().isEmpty()) { + return R.ok("获取成功", staffName); + } else { + return R.fail("员工不存在"); + } + } catch (Exception e) { + return R.fail("获取员工姓名失败: " + e.getMessage()); + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WxPayChatControlle.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WxPayChatControlle.java new file mode 100644 index 0000000..45e4670 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WxPayChatControlle.java @@ -0,0 +1,317 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSONObject; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.bo.UserRechargeBo; +import org.dromara.zhishu.service.IUserRechargeService; +import org.dromara.zhishu.service.impl.BookBaseInfoServiceImpl; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.JsonObjUtil; +import org.dromara.zhishu.util.WxPayUtil; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; + +import java.math.BigDecimal; +import java.security.PublicKey; +import java.util.Calendar; +import java.util.HashMap; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/weChat") +public class WxPayChatControlle { + + private final IUserRechargeService userRechargeService; + private final ISysConfigService configService; + private final SysUserMapper sysUserMapper; + private final BookBaseInfoServiceImpl bookBaseInfoService; + + private static final String APPID = "wxec160b6872dc24cf"; + private static final String APPSECRET = "ed7d3b45c94b3d56f23db0479c4475a9"; + private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token"; + + @SaIgnore + @GetMapping("/getAccessToken") + public void getAccessToken() { + String url = String.format( + "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", + APPID, APPSECRET); + + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpGet request = new HttpGet(url); + + try (CloseableHttpResponse response = httpClient.execute(request)) { + HttpEntity entity = response.getEntity(); + if (entity != null) { + String result = EntityUtils.toString(entity); + System.out.println(result); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +// @SaIgnore +// @GetMapping("/toWxPay/{ddName}") +// public ResponseEntity toWxPay(@PathVariable("ddName")String ddName) { +// String wxPay = WxPayUtil.wxPay(ddName); +// return WxPayUtil.generateQRCode(wxPay); +// } + + @SaIgnore + @PostMapping("/wxPayCallBack") + public String wxPayCallBack(HttpServletRequest request){ + try { + // 获取请求头和请求体 + Map headers = WxPayUtil.getHeaders(request); + // 获取请求体 + String requestBody = WxPayUtil.getRequestBody(request); + Map map = WxPayUtil.getRequestBodyAsMap(request); + Map resourceMap = (Map) map.get("resource"); + //使用平台证书公钥验证签名 +// PublicKey publicKey = WxPayUtil.loadPublicKeyFromPem("/wxPay/wechatpay_6E6A328311EAC53D048D222F9FED79310E267329.pem"); + PublicKey publicKey = WxPayUtil.loadPublicKeyFromPem("C:\\Users\\Administrator\\wxPay\\wxPay\\wechatpay_6E6A328311EAC53D048D222F9FED79310E267329.pem"); + + boolean isSignatureValid = WxPayUtil.verifyWechatPaySignature( + publicKey, + requestBody, + headers.get("wechatpay-signature"), + headers.get("wechatpay-timestamp"), + headers.get("wechatpay-nonce") + ); + + // 4. 解密数据 + String decryptedData = WxPayUtil.decryptToString( + resourceMap.get("associated_data").toString().getBytes(), + resourceMap.get("nonce").toString().getBytes(), + resourceMap.get("ciphertext").toString(), + WxPayUtil.getApiV3Key().getBytes() + ); + + System.out.println("decryptedData:"+decryptedData); + // 5. 解析 JSON(示例:FastJSON) + Map dataMap = JsonUtils.parseObject(decryptedData,Map.class); + //自定义参数 + // 获取 amount 字段(也是一个 Map) + Map amountMap = (Map) dataMap.get("amount"); + System.out.println("amountMap : "+amountMap); + + String attach = dataMap.get("attach").toString(); + System.out.println("attach1111111111 :"+attach); + JSONObject attachObj = JSONObject.parseObject(attach); + Long taskId = attachObj.getLong("taskId"); + System.out.println("taskId1111111111 :"+taskId); + String orderId = attachObj.getString("orderId"); + System.out.println("orderId1111111111 :"+orderId); + String userId = attachObj.getString("userId"); + + // 修改新后台新订单表 + if (orderId != null){ + Map map1 = new HashMap(); + map1.put("orderId",orderId); + map1.put("orderInfo",JsonUtils.toJsonString(dataMap)); + map1.put("userId",userId); + System.out.println("充值回调参数"+map1); + String orderUrl = configService.selectConfigByKey("order.url"); + String interfaceGet = InterfaceUtils.postForm(orderUrl, "/api/orders/orderForPay", map1); +// String interfaceGet = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/orders/orderForPay", map1); + System.out.println("充值结果: "+interfaceGet); + Map orderSuccess = JsonUtils.parseObject(interfaceGet,Map.class); + Integer code = (Integer) orderSuccess.get("code"); + if (code == null || code != 200) { + // 这里可以打印日志或抛异常 + System.err.println("更新服务失败,返回结果:" + orderSuccess); + return "{\"code\": \"FAIL\", \"message\": \"更新服务失败\"}"; + } + + } +// //成功支付时间 +// String successTime = dataMap.get("success_time").toString(); +// // 根据价格判断 +// UserRechargeBo bo = new UserRechargeBo(); +// bo.setId(taskId); +// bo.setSuccessTime(DateUtils.getNextDay()); +// bo.setStatus("1"); +// bo.setAllDataStr(decryptedData); +// userRechargeService.updateByBo(bo); + +// // 获取type类型 +// // 支付成功后修改用户订单信息 +// // 插入会员表 修改参数 +// Integer count = updateUserVip(bo,payerTotal); +// // 插入订单表 +// Integer result =InsertOrder(decryptedData,taskId); + + // 6. 返回成功响应 + return "{\"code\": \"SUCCESS\", \"message\": \"成功\"}"; + + } catch (Exception e) { + e.printStackTrace(); + return "{\"code\": \"FAIL\", \"message\": \"处理失败: " + e.getMessage() + "\"}"; + } + } + + + @PostMapping("/wxPayCallBack2") + @SaIgnore + public String wxPayCallBack2(HttpServletRequest request){ + try { + // 获取请求头和请求体 + Map headers = WxPayUtil.getHeaders(request); + // 获取请求体 + String requestBody = WxPayUtil.getRequestBody(request); + Map map = WxPayUtil.getRequestBodyAsMap(request); + Map resourceMap = (Map) map.get("resource"); + //使用平台证书公钥验证签名 +// PublicKey publicKey = WxPayUtil.loadPublicKeyFromPem("/wxPay/wechatpay_6E6A328311EAC53D048D222F9FED79310E267329.pem"); + PublicKey publicKey = WxPayUtil.loadPublicKeyFromPem("C:\\Users\\Administrator\\wxPay\\wxPay\\wechatpay_6E6A328311EAC53D048D222F9FED79310E267329.pem"); + + boolean isSignatureValid = WxPayUtil.verifyWechatPaySignature( + publicKey, + requestBody, + headers.get("wechatpay-signature"), + headers.get("wechatpay-timestamp"), + headers.get("wechatpay-nonce") + ); + + // 4. 解密数据 + String decryptedData = WxPayUtil.decryptToString( + resourceMap.get("associated_data").toString().getBytes(), + resourceMap.get("nonce").toString().getBytes(), + resourceMap.get("ciphertext").toString(), + WxPayUtil.getApiV3Key().getBytes() + ); + + System.out.println("decryptedData:"+decryptedData); + // 5. 解析 JSON(示例:FastJSON) + Map dataMap = JsonUtils.parseObject(decryptedData,Map.class); + //自定义参数 + // 获取 amount 字段(也是一个 Map) + Map amountMap = (Map) dataMap.get("amount"); + + // 获取 payer_total 的值 + int payerTotal = (int) amountMap.get("payer_total"); + + String attach = dataMap.get("attach").toString(); + //成功支付时间 + String successTime = dataMap.get("success_time").toString(); + // 根据价格判断 + UserRechargeBo bo = new UserRechargeBo(); + bo.setId(Long.parseLong(attach)); + bo.setSuccessTime(DateUtils.getNextDay()); + bo.setStatus("1"); + bo.setAllDataStr(decryptedData); + userRechargeService.updateByBo(bo); + + // 6. 返回成功响应 + return "{\"code\": \"SUCCESS\", \"message\": \"成功\"}"; + + } catch (Exception e) { + e.printStackTrace(); + return "{\"code\": \"FAIL\", \"message\": \"处理失败: " + e.getMessage() + "\"}"; + } + } + + + public Integer updateUserVip(UserRechargeBo bo,int payerTotal){ + // 获取当前日历实例 + Calendar calendar = Calendar.getInstance(); + long nowTimeStamp = System.currentTimeMillis(); + // 设置日历为当前时间 + calendar.setTimeInMillis(nowTimeStamp); + if (payerTotal != 9800) { + // 价格不为98元,也就是页面会员,添加一年后的时间戳 + calendar.add(Calendar.YEAR, 1); + } else { + // 其他情况,添加一个月 + calendar.add(Calendar.MONTH, 1); + } + long timeStamp = calendar.getTimeInMillis(); + + Map params = new HashMap<>(); + params.put("id",bo.getId()); + params.put("expiration_date", timeStamp); // 30天后 + params.put("pay_status",0); + params.put("created_time", nowTimeStamp); + params.put("updated_time", nowTimeStamp); + String path1 = "/user/putuserInfo"; + String goUrl = configService.selectConfigByKey("go.url"); + String BookBaseInfoVoStr = InterfaceUtils.getInterfacePost(goUrl, path1, params); + //获取接口返回值 + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); + //获取BookBaseInfoVoStr是一个json的字符串要获取Code值 + JSONObject jsonObject1 = JSONObject.parseObject(BookBaseInfoVoStr); + //获取code值没有data + String code = jsonObject1.getString("code"); + if (code.equals("200")) { + return 1; + } else { + return 0; + } + } + + + + //订单插入到新后台 + public Integer InsertOrder(String decryptedData, Long id){ + Map dataMap = JsonUtils.parseObject(decryptedData,Map.class); + // 获取 amount 字段(也是一个 Map) + Map amountMap = (Map) dataMap.get("amount"); + + // 获取 payer_total 的值 + int payerTotal = (int) amountMap.get("payer_total"); + if(dataMap.get("trade_state_desc").toString().equals("支付成功")) { + //获取当前时间戳 + long timestamp = System.currentTimeMillis(); + //获取当前用户id + Long userId = LoginHelper.getUserId(); + Map params = new HashMap<>(); + params.put("order_sn", dataMap.get("out_trade_no").toString()); + params.put("user_id", userId); + params.put("mchid", dataMap.get("mchid")); + params.put("app_id", dataMap.get("appid")); + params.put("rec_business_config_id",id); + params.put("amount", payerTotal); + params.put("recharge_type", "1"); + params.put("order_type", "3"); + params.put("status", 1); + params.put("create_by", userId); + params.put("update_by", userId); + params.put("created_time", timestamp); + params.put("updated_time", timestamp); + params.put("is_del", 0); + String path1 = "/user/insertOrder"; + String goUrl = configService.selectConfigByKey("go.url"); + String BookBaseInfoVoStr = InterfaceUtils.getInterfacePost(goUrl, path1, params); + + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); + //获取BookBaseInfoVoStr是一个json的字符串要获取Code值 + JSONObject jsonObject1 = JSONObject.parseObject(BookBaseInfoVoStr); + //获取code值没有data + String code = jsonObject1.getString("code"); + Map paramsVo = new HashMap<>(); + bookBaseInfoService.InsertButtonVip(paramsVo, BigDecimal.valueOf(payerTotal* 100L)); + return 1; + } + return 0; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XyController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XyController.java new file mode 100644 index 0000000..c66f63d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XyController.java @@ -0,0 +1,77 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.impl.XianYvQueryShopImpl; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/xy/api") +public class XyController { + + private final IShopService shopService; + private final XianYvQueryShopImpl xianYvQueryShop; + + /** + * 咸鱼授权 + * + * @param code + * @param response + * @return + */ + @SaIgnore + @GetMapping("/tokenSq/{code}/{shopName}/{token}/{shopKey}") + public R tokenSq(@PathVariable("code") String code, @PathVariable("shopName") String shopName, @PathVariable("token") String token, @PathVariable("shopKey") String shopKey, HttpServletResponse response) { + + Long userId = LoginHelper.getUserId(); + + R>> shopResult = xianYvQueryShop.XianYvQueryShop(code, token); + + // 检查接口调用是否成功且有数据 + if ((shopResult.getCode() == 200) && shopResult.getData() != null && !shopResult.getData().isEmpty()) { + List> xyUser = shopResult.getData(); + + // 循环创建店铺,每个店铺名称创建一个店铺记录 + for (Map userInfo: xyUser) { + + ShopBo bo = new ShopBo(); + bo.setShopKey(shopKey); + ShopVo shopVo = shopService.queryList(bo).get(0); + + ShopBo shopBo = new ShopBo(); + if (shopVo != null) { + shopBo.setId(shopVo.getId()); + shopBo.setShopName(shopName); + shopBo.setMallId(Long.parseLong(code)); + shopBo.setToken(token); + shopBo.setShopKey(shopKey); + + shopService.updateByBo(shopBo); + } + } + + return R.ok("成功修改 " + xyUser.size() + " 个店铺"); + + } else { + return R.ok("账户店铺为空,无法添加"); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopImagesController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopImagesController.java new file mode 100644 index 0000000..09ec1aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopImagesController.java @@ -0,0 +1,105 @@ +package org.dromara.zhishu.controller; + +import java.util.List; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.zhishu.domain.bo.ZhishuShopImagesBo; +import org.dromara.zhishu.domain.vo.ZhishuShopImagesVo; +import org.dromara.zhishu.service.IZhishuShopImagesService; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 商品图片 + * + * @author Lion Li + * @date 2025-03-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/shopImages") +public class ZhishuShopImagesController extends BaseController { + + private final IZhishuShopImagesService zhishuShopImagesService; + + /** + * 查询商品图片列表 + */ + @SaCheckPermission("system:shopImages:list") + @GetMapping("/list") + public TableDataInfo list(ZhishuShopImagesBo bo, PageQuery pageQuery) { + return zhishuShopImagesService.queryPageList(bo, pageQuery); + } + + /** + * 导出商品图片列表 + */ + @SaCheckPermission("system:shopImages:export") + @Log(title = "商品图片", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ZhishuShopImagesBo bo, HttpServletResponse response) { + List list = zhishuShopImagesService.queryList(bo); + ExcelUtil.exportExcel(list, "商品图片", ZhishuShopImagesVo.class, response); + } + + /** + * 获取商品图片详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:shopImages:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(zhishuShopImagesService.queryById(id)); + } + + /** + * 新增商品图片 + */ + @SaCheckPermission("system:shopImages:add") + @Log(title = "商品图片", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ZhishuShopImagesBo bo) { + return toAjax(zhishuShopImagesService.insertByBo(bo)); + } + + /** + * 修改商品图片 + */ + @SaCheckPermission("system:shopImages:edit") + @Log(title = "商品图片", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ZhishuShopImagesBo bo) { + return toAjax(zhishuShopImagesService.updateByBo(bo)); + } + + /** + * 删除商品图片 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:shopImages:remove") + @Log(title = "商品图片", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids) { + return toAjax(zhishuShopImagesService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/dll/DllInitializer.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/dll/DllInitializer.java new file mode 100644 index 0000000..83ddfbf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/dll/DllInitializer.java @@ -0,0 +1,50 @@ +package org.dromara.zhishu.dll; + +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class DllInitializer { + private static boolean initialized = false; + + @PostConstruct + public void init() { + try { + System.out.println("正在加载 erp DLL库"); + ErpSimpleDllLoader.loadDLL(); + initialized = true; + System.out.println("erp DLL 库加载成功"); + } catch (Exception e) { + System.err.println("Native 库加载失败: " + e.getMessage()); + throw new RuntimeException("Native 库加载失败", e); + } + } + + public static boolean isInitialized() { + return initialized; + } + + + /** + * 清理文件路径 + */ + private static String cleanFilePath(String path) { + if (path == null) return null; + return path.replaceAll("[\\p{Cntrl}]", "").trim().replace('\\', '/'); + } + + /** + * 接口转发 + * @param requestMethod 请求方法类型 + * @param erpUrl 请求路径 + * @param json 参数 + * @return 同步结果字符串 + */ + public static String executeInterfaceForward(String requestMethod, String erpUrl, String json) { + if (!initialized) { + throw new IllegalStateException("拼多多 DLL库未初始化"); + } + return ErpSimpleDllLoader.executeInterfaceForward(requestMethod, erpUrl, json); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/dll/ErpSimpleDllLoader.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/dll/ErpSimpleDllLoader.java new file mode 100644 index 0000000..6f71c79 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/dll/ErpSimpleDllLoader.java @@ -0,0 +1,129 @@ +package org.dromara.zhishu.dll; + +import com.sun.jna.Function; +import com.sun.jna.NativeLibrary; +import com.sun.jna.Pointer; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class ErpSimpleDllLoader { + + private static NativeLibrary nativeLibrary; + + // 接口转发 + private static Function interfaceForwardFunc; + + private static Function freeCStringFunc; + + // 外部库文件路径 + //private static final String EXTERNAL_LIB_PATH = "/www/wwwroot/config/erp.so"; + private static final String EXTERNAL_LIB_PATH = "D:/zhishu/dll/erp.dll"; + + public static void loadDLL() throws Exception { + String libraryPath = getLibraryPath(); + System.out.println("正在加载 ERP native 库: " + libraryPath); + + File libraryFile = new File(libraryPath); + + // 验证库文件是否存在 + if (!libraryFile.exists()) { + throw new FileNotFoundException("ERP Native 库文件不存在: " + libraryPath); + } + + // 验证文件大小 + System.out.println("ERP 库文件大小: " + libraryFile.length() + " bytes"); + if (libraryFile.length() == 0) { + throw new IOException("ERP 库文件为空: " + libraryPath); + } + + // 在 Linux 系统上设置执行权限 + if (!System.getProperty("os.name").toLowerCase().contains("win")) { + boolean success = libraryFile.setExecutable(true); + System.out.println("设置 ERP 库执行权限: " + (success ? "成功" : "失败")); + } + + // 加载库文件 + nativeLibrary = NativeLibrary.getInstance(libraryFile.getAbsolutePath()); + + // 拼多多订单同步 + interfaceForwardFunc = nativeLibrary.getFunction("InterfaceForward"); + + // 释放c串内存 + freeCStringFunc = nativeLibrary.getFunction("FreeCString"); + + if (interfaceForwardFunc == null) throw new Exception("无法找到 InterfaceForward 函数"); + if (freeCStringFunc == null) throw new Exception("无法找到 FreeCString 函数"); + + System.out.println("ERP Native 库加载成功: " + libraryPath); + } + + /** + * 获取库文件路径 + */ + private static String getLibraryPath() throws IOException { + // 优先使用外部路径 + String externalPath = EXTERNAL_LIB_PATH; + System.out.println("使用 ERP 外部库文件: " + externalPath); + return externalPath; + + } + + /** + * 接口转发 + * @param requestMethod 请求方法类型 + * @param erpUrl 请求路径 + * @param json 参数 + * @return 同步结果字符串 + */ + public static String executeInterfaceForward(String requestMethod, String erpUrl, String json) { + try { + String cleanedRequestMethod = ensureUtf8(requestMethod); + String cleanedErpUrl = ensureUtf8(erpUrl); + String cleanedJson = ensureUtf8(json); + Object result = interfaceForwardFunc.invoke(Pointer.class, + new Object[]{cleanedRequestMethod, cleanedErpUrl,cleanedJson}); + return ptrToString((Pointer) result); + } catch (Exception e) { + return "Error: " + e.getMessage(); + } + } + + /** + * 确保字符串使用UTF-8编码 + */ + private static String ensureUtf8(String str) { + if (str == null) return null; + try { + byte[] utf8Bytes = str.getBytes(StandardCharsets.UTF_8); + return new String(utf8Bytes, StandardCharsets.UTF_8); + } catch (Exception e) { + System.err.println("UTF-8编码转换失败: " + e.getMessage()); + return str; + } + } + + private static String ptrToString(Pointer ptr) { + if (ptr == null) return ""; + try { + return ptr.getString(0, "UTF-8"); + } catch (Exception e) { + System.err.println("字符串解码失败: " + e.getMessage()); + return ""; + } finally { + freeCString(ptr); + } + } + + private static void freeCString(Pointer ptr) { + if (ptr != null) { + try { + freeCStringFunc.invoke(Void.class, new Object[]{ptr}); + } catch (Exception e) { + System.err.println("释放C字符串失败: " + e.getMessage()); + } + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/BookBaseInfo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/BookBaseInfo.java new file mode 100644 index 0000000..7b2cd6a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/BookBaseInfo.java @@ -0,0 +1,153 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; +import org.dromara.zhishu.domain.vo.BookPic; + +import java.io.Serial; + +/** + * 基础信息对象 book_base_info + * + * @author Lion Li + * @date 2025-03-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("book_base_info") +public class BookBaseInfo extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 书名 + */ + private String bookName; + + /** + * 书图片 + */ + private BookPic bookPic; + + private BookPic bookPicS; + + /** + * ibsn + */ + private String isbn; + + /** + * 作者 + */ + private String author; + + /** + * 编辑 + */ + private String editor; + + /** + * 装帧 + */ + private String bindingLayout; + + /** + * 出版社 + */ + private String publisher; + + /** + * 版次 + */ + private String edition; + + /** + * 开本 + */ + private String format; + + /** + * 语种 + */ + private String languages; + + /** + * 出版时间 + */ + private String publicationTime; + + /** + * 印刷时间 + */ + private String printTime; + + /** + * 纸张 + */ + private String paper; + + /** + * 页数 + */ + private String pages; + + /** + * 字数 + */ + private String wordage; + + /** + * 定价 + */ + private String fixPrice; + + /** + * 已售 + */ + private String buyCount=""; + /** + * 在售 + */ + private String sellCount=""; + + /** + * 内容 + */ + private String content; + + /** + * 备注 + */ + private String remark; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 叶子类目id + */ + private Long catId; + + private Long publictionTimes; + + private Long buyCounts; + + private Long sellCounts; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/CardResult.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/CardResult.java new file mode 100644 index 0000000..a25ef36 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/CardResult.java @@ -0,0 +1,32 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; + +/** + * 身份证信息 + */ +@Data +public class CardResult { +// 图片路径 + private String url; +// 提示信息 + private String message; +// 身份证地址 + private String address; +// private String AdvancedInfo; +// 办理地点 + private String authority; +// 出生年月日 + private String birth; +// 身份证号 + private String idNum; +// 身份证姓名 + private String name; +// 身份证民族 + private String nation; +// 身份证性别 + private String sex; +// 有效期 + private String validDate; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/FilterSet.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/FilterSet.java new file mode 100644 index 0000000..135f10a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/FilterSet.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.util.Date; + +/** + * 过滤设置对象 t_filter_set + * + * @author yxy + * @date 2025-04-14 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_filter_set") +public class FilterSet extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 过滤类型 + */ + private String filterType; + + /** + * 限制类型 + */ + private String limitationType; + + /** + * 添加方式 + */ + private String addWay; + + /** + * 内容文件 + */ + private String addTxt; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + private String sort; + + private Date createTime; + + /** + * 加入原因 + */ + private String reason; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PddShopInfo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PddShopInfo.java new file mode 100644 index 0000000..76a2157 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PddShopInfo.java @@ -0,0 +1,29 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 店铺主表对象 t_shop + * + * @author taiping + * @date 2025-03-22 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("pdd_shop") +public class PddShopInfo { + @TableId(value = "id") + private Long id; + private String form_shop; + private String encoding_shop; + private String isbn; + private String name_book; + private String status_shop; + private int inventory; + private int price; + private int salesvolume; + private String time_found; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/RunningLogFile.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/RunningLogFile.java new file mode 100644 index 0000000..b5e8e43 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/RunningLogFile.java @@ -0,0 +1,62 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 程序运行日志表对象 t_running_log_file + * + * @author yxy + * @date 2025-06-12 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_running_log_file") +public class RunningLogFile extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件顺序 + */ + private String fileOrder; + + /** + * 文件类型 + */ + private String fileType; + + /** + * 文件大小 + */ + private String fileSize; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Shop.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Shop.java new file mode 100644 index 0000000..285c76c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Shop.java @@ -0,0 +1,165 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 店铺主表对象 t_shop + * + * @author yxy + * @date 2025-03-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop") +public class Shop extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 三方店铺id + */ + private Long mallId; + + /** + * 万里牛系统ID + */ + private String shopNike; + + /** + * 店铺类型 1 拼多多 + */ + private String shopType; + + /** + * 分组 + */ + private String shopGroup; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 店铺名称(对应平台的店铺名称) + */ + private String shopAliasName; + + /** + * 是否授权 0未授权 1已授权 2已过期 + */ + private String shopAuthorize; + + /** + * 到期时间 + */ + private Date expirationTime; + + /** + * 添加时间 + */ + private Date addTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 店铺key + */ + private String shopKey; + + /** + * token + */ + private String token; + + /** + * 刷新token 的token + */ + private String refreshToken; + + + /** + * 店铺状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 租户编码 + */ + private String tenant_id; + + /** + * pdd 授权后的 可以同步订单的时间戳 + */ + private Long startUpdatedAt; + + /** + * 第三方平台账号 + */ + private String account; + + /** + * 第三方平台密码 + */ + private String password; + + /** + * 用户id + */ + private Long userId; + + /** + * 是否开启同步订单:默认0-否 1-是 + */ + private Integer isSynOrder; + + + /** + * 服务版本 + */ + private String skuSpec; + + + /** + * erp到期时间 + */ + private Date shopExpirationTime; + + /** + * erp是否到期 + */ + private String isExpiration; + + /** + * 拼多多试用版是否无上限 1 否 2 是 + */ + private String deregulation; + + /** + * 使用次数 + */ + private Long usageCount; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsPublished.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsPublished.java new file mode 100644 index 0000000..9a572e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsPublished.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.util.Date; + +/** + * 记录发布数据对象 t_shop_goods_published + * + * @author yxy + * @date 2025-04-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_goods_published") +public class ShopGoodsPublished extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 图书主键 + */ + private String shopGoodsId; + + + /** + * 发布的店铺ids + */ + private String shopId; + + /** + * 平台商品id + */ + private String platformId; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 修改时间 + */ + private Date updateTime; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsPublishedLog.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsPublishedLog.java new file mode 100644 index 0000000..fce5368 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsPublishedLog.java @@ -0,0 +1,81 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 商品发布记录 + * + * @author Ygb + * @date 2025-06-16 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_goods_published_log") +public class ShopGoodsPublishedLog extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 商品id + */ + private Long shopGoodsId; + + /** + * 已发布商品id + */ + private Long shopGoodsPublishedId; + + /** + * 平台商品id + */ + private String platformId; + + /** + * 相关Id + */ + private String aboutId; + + /** + * 平台类型 1 拼多多 2-孔夫子 + */ + private Integer platformType; + + /** + * 日志类型 1-上架 2-下架 + */ + private Integer logType; + + /** + * 操作类型 1-发布任务 2-订单 + */ + private Integer operationType; + + /** + * 状态 0-成功 1-失败 + */ + private Integer status; + + /** + * 租户编码 + */ + private String tenantId; + + /** + * 删除标志(0代表存在 1代表删除) + */ + private String delFlag; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsRejection.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsRejection.java new file mode 100644 index 0000000..d2edf52 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodsRejection.java @@ -0,0 +1,66 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import lombok.*; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 商品驳回记录表 + * + * @author Ygb + * @date 2025-06-16 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Table(name = "shop_goods_rejection") +@Builder +@NoArgsConstructor // 必须添加 +@AllArgsConstructor // 建议添加 +public class ShopGoodsRejection extends BaseEntity{ + @Serial + private static final long serialVersionUID = 1L; + + @TableId(value = "id") + private Long id; + + + private String shopGoodsId; + + + private Long shopId; + + + private String platformId; + + + private Date createTime; + + + private String rejectionReason; + + private String isbn; + + private String shopName; + + + private String tenantId; + + private Integer platformType; + + private String shopGoodsImg; + + private Integer goodsType; + + private Long offshelfTime; + + private String syncFlag; + + private Long userId; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopImg.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopImg.java new file mode 100644 index 0000000..41fafce --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopImg.java @@ -0,0 +1,67 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 店铺图片对象 t_shop_img + * + * @author yxy + * @date 2025-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_img") +public class ShopImg extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 父id + */ + private Long pid; + + /** + * 相对路径 + */ + private String relativePath; + + /** + * 绝对路径 + */ + private String absolutePath; + + /** + * 类型 1封面水印 2商详水印 3 商详头图 4 商详尾图 5 轮播尾图 + */ + private String type; + + /** + * 图片顺序 + */ + private Long imgOrder; + + /** + * 店铺状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopWarehouse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopWarehouse.java new file mode 100644 index 0000000..1cd2d92 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopWarehouse.java @@ -0,0 +1,41 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 店铺与仓库自动发布关联对象 t_shop_warehouse + * + * @author yxy + * @date 2025-12-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_warehouse") +public class ShopWarehouse extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 用户id(仓库id) + */ + private Long userId; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopWarehouseAuto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopWarehouseAuto.java new file mode 100644 index 0000000..49a397e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopWarehouseAuto.java @@ -0,0 +1,55 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 店铺与仓库自动发布关联对象 进销存仓库 + * + * @author yxy + * @date 2026-06-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("shop_warehouse_auto") +public class ShopWarehouseAuto extends BaseEntity { + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 店铺类型 1 拼多多 2 孔夫子 5 闲鱼 + */ + private String shopType; + + /** + * 用户id + */ + private Long userId; + + /** + * 仓库id + */ + private Long warehouseId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/StockChangeLog.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/StockChangeLog.java new file mode 100644 index 0000000..81f3cd0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/StockChangeLog.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * 库存变更记录 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@TableName("t_stock_change_log") +public class StockChangeLog { + /** + * 库存变更记录id + */ + private Long id; + /** + * 商品id + */ + private Long shopGoodsId; + /** + * 操作类型 + */ + private Integer type; + /** + * 关联id + */ + private String aboutId; + /** + * 变更前库存 + */ + private Long beforeInv; + /** + * 变更后库存 + */ + private Long afterInv; + /** + * 创建人 + */ + private Long createBy; + /** + * 用户名 + */ + private Long updateBy; + + /** + * 创建时间 + */ + private Date createTime; + /** + * 修改时间 + */ + private Date updateTime; + + /** + * 删除标志(0代表存在 1代表删除) + */ + private String delFlag; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TBookAudit.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TBookAudit.java new file mode 100644 index 0000000..fad5bea --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TBookAudit.java @@ -0,0 +1,90 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 图书审核管理对象 t_book_audit + * + * @author Lion Li + * @date 2025-04-18 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_book_audit") +public class TBookAudit extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 审核图书id + */ + @TableId(value = "id") + private Long id; + + /** + * 用户id + */ + private Long userId; + + /** + * 产品编码 + */ + private String productId; + + /** + * 商品名称 + */ + private String goodsName; + + /** + * isbn + */ + private String isbn; + + /** + * 货号 + */ + private String artNo; + + /** + * 标准售价 + */ + private Long price; + + /** + * 商品定价 + */ + private Long fixPrice; + + /** + * 品相 + */ + private String conditionCode; + + /** + * 商品编号 + */ + private String itemNumber; + + /** + * 审核状态(0 通过 1 未通过 2 待审核) + */ + private String status; + + /** + * 库存 + */ + private Long inventory; + + /** + * 书图片 + */ + private String bookPic; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TDepot.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TDepot.java new file mode 100644 index 0000000..c436e40 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TDepot.java @@ -0,0 +1,83 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 仓库信息设置对象 t_depot + * + * @author Lion Li + * @date 2025-03-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_depot") +public class TDepot extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 仓库id + */ + private Long id; + + /** + * 仓库编号 + */ + private String code; + + /** + * 仓库名称 + */ + private String name; + + /** + *单位 + */ + private String unit; + + /** + * 仓库地址 + */ + private String address; + + /** + * 仓库管理员 + */ + private String manager; + + + /** + * 仓库状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 货架数量 + */ + private Long sheQuantityMax; + + /** + * 用户id + */ + private Long userId; + /** + * 模板id + */ + private Long templateId; + /** + * tenantId + */ + private String tenantId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteCode.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteCode.java new file mode 100644 index 0000000..bba480f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteCode.java @@ -0,0 +1,57 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; +import java.util.Date; + +/** + * 邀请码表实体类 + */ +@Data +@NoArgsConstructor +@TableName("t_invite_codes") +public class TInviteCode implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 邀请人ID + */ + private Long userId; + + /** + * 邀请码 + */ + private String code; + + /** + * 邀请链接 + */ + private String inviteUrl; + + /** + * 过期时间 + */ + private Date expireTime; + + /** + * 是否已使用 + */ + private Boolean used; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createdAt; + + private String tenantId; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteRelation.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteRelation.java new file mode 100644 index 0000000..e038ae2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteRelation.java @@ -0,0 +1,44 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; +import java.util.Date; + +/** + * 邀请关系表实体类 + */ +@Data +@NoArgsConstructor +@TableName("t_invite_relations") +public class TInviteRelation implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + /** + * 邀请人ID + */ + private Long inviterId; + + /** + * 被邀请人ID + */ + private Long inviteeId; + + /** + * 使用的邀请码 + */ + private String inviteCode; + + /** + * 邀请时间 + */ + private Date inviteTime; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteRelations.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteRelations.java new file mode 100644 index 0000000..3e19224 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TInviteRelations.java @@ -0,0 +1,53 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 【请填写功能名称】对象 t_invite_relations + * + * @author Lion Li + * @date 2025-12-16 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("t_invite_relations") +public class TInviteRelations { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 邀请人手机号 + */ + private String inviterPhone; + + /** + * 被邀请人ID + */ + private Long inviteeId; + + /** + * 使用的邀请码 + */ + private String inviteCode; + + /** + * 邀请时间 + */ + private Date inviteTime; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TLogistics.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TLogistics.java new file mode 100644 index 0000000..fdff265 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TLogistics.java @@ -0,0 +1,119 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 物流管理对象 t_logistics + * + * @author Lion Li + * @date 2025-04-22 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_logistics") +public class TLogistics extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 物流模板名称 + */ + private String templateName; + + /** + * 发货地-省 + */ + private String deliveryProvince; + + /** + * 发货地-市 + */ + private String deliveryCity; + + /** + * 发货地-区 + */ + private String deliveryArea; + + /** + * 详细地址 + */ + private String deliveryAddress; + + /** + * 计价方式(0按重量 1按标准本数(图书专用) 2按件数 3单独设置运费) + */ + private String pricingMethod; + + /** + * 运送方式(0快递 1自提) + */ + private String shipping; + + /** + * 首重 首本 首件 + */ + private Long firWbv; + + /** + * 首费 单位:元 + */ + private Long firPrice; + + /** + * 续重 续本 续件 + */ + private Long continueWbv; + + /** + * 续费 单位:元 + */ + private Long continuePrice; + + /** + * 模板状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 运送范围 + */ + private String shippingRange; + + /** + * 仓库ID + */ + private Long warehouseId; + /** + * 联系人 + */ + private String contact; + + /** + * 联系电话 + */ + private String phoneNumber; + /** + * 详细地址 + */ + private String fullAddress; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopDepotAotu.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopDepotAotu.java new file mode 100644 index 0000000..1073e70 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopDepotAotu.java @@ -0,0 +1,47 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 店铺自动发布仓库关联对象 t_shop_depot_aotu + * + * @author Lion Li + * @date 2025-09-05 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_depot_aotu") +public class TShopDepotAotu extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + + /** + * 店铺id + */ + private Long shopId; + + /** + * 仓库id + */ + private Long depotId; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopMessageSubscribe.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopMessageSubscribe.java new file mode 100644 index 0000000..c5cb52e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopMessageSubscribe.java @@ -0,0 +1,67 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +import java.io.Serial; +import java.util.Date; + +/** + * 订单对象 t_shop_order + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_message_subscribe") +public class TShopMessageSubscribe extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键Id + */ + @TableId(value = "id") + private Long id; + + /** + * 店铺Id + */ + private Long shopId; + + /** + * 订阅详情(json字符串) + */ + private String subscribeDetail; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopOrder.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopOrder.java new file mode 100644 index 0000000..72b59cc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopOrder.java @@ -0,0 +1,384 @@ +package org.dromara.zhishu.domain; + +import org.apache.poi.hpsf.Decimal; +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 订单对象 t_shop_order + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_order") +public class TShopOrder extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * Id + */ + @TableId(value = "id") + private Long id; + + /** + * 订单来源类型 1-拼多多 2-孔夫子 + */ + private Integer orderSourceType; + + /** + * 订单异常类型集合(json字符串):inventoryException-库存异常 goodsSourceUnknownException-未知商品来源 + */ + private String orderExceptionType; + + /** + * 店铺id + */ + private String shopId; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 地址 + */ + private String address; + + /** + * 详细地址(打码) + */ + private String addressMask; + + /** + * 售后状态 0:无售后 2:买家申请退款,待商家处理 3:退货退款,待商家处理 4:商家同意退款,退款中 5:平台同意退款,退款中 6:驳回退款,待买家处理 7:已同意退货退款,待用户发货 8:平台处理中 9:平台拒绝退款,退款关闭 10:退款成功 11:买家撤销 12:买家逾期未处理,退款失败 13:买家逾期,超过有效期 14:换货补寄待商家处理 15:换货补寄待用户处理 16:换货补寄成功 17:换货补寄失败 18:换货补寄待用户确认完成 21:待商家同意维修 22:待用户确认发货 24:维修关闭 25:维修成功 27:待用户确认收货 31:已同意拒收退款,待用户拒收 32:补寄待商家发货 33:同意召回后退款,待商家召回 + */ + private Integer afterSalesStatus; + + /** + * 买家留言信息 + */ + private String buyerMemo; + + /** + * 成交状态:0:未成交、1:已成交、2:已取消 + */ + private Integer confirmStatus; + + /** + * 成交时间 + */ + private String confirmTime; + + /** + * 订单创建时间 + */ + private String createdTime; + + /** + * 是否当日发货,1-是,0-否 + */ + private String deliveryOneDay; + + /** + * 折扣金额,单位:元,折扣金额=平台优惠+商家优惠+团长免单优惠金额 + */ + private BigDecimal discountAmount; + + /** + * 多多支付立减金额,单位:元 + */ + private BigDecimal duoDuoPayReduction; + + /** + * 是否多多批发 + */ + private Integer duoduoWholesale; + + /** + * 商品金额 + */ + private BigDecimal goodsAmount; + + /** + * 仓库编码 + */ + private String depotCode; + + /** + * 仓库信息 + */ + private String orderDepotInfo; + + /** + * 仓库id + */ + private String depotId; + + /** + * 仓库名称 + */ + private String depotName; + + /** + * 仓库类型,1:自有仓 2:订阅仓 两者都不是则传空 + */ + private Integer depotType; + + /** + * 货品id + */ + private Long wareId; + + /** + * 货品名称 + */ + private String wareName; + + /** + * 货品编码 + */ + private String wareSn; + + /** + * 货品类型(0:普通货品:1:组合货品) + */ + private Integer wareType; + + /** + * 订单编号 + */ + private String orderSn; + + /** + * 订单状态 + */ + private Integer orderStatus; + + /** + * 支付金额 + */ + private BigDecimal payAmount; + + /** + * 支付单号 + */ + private String payNo; + + /** + * 支付时间 + */ + private String payTime; + + /** + * 支付方式 + */ + private String payType; + + /** + * 平台优惠金额 + */ + private BigDecimal platformDiscount; + + /** + * 邮费 + */ + private BigDecimal postage; + + /** + * 预售时间 + */ + private String preSaleTime; + + /** + * 承诺送达时间 + */ + private String promiseDeliveryTime; + + /** + * 确认收货时间 + */ + private String receiveTime; + + /** + * 省份 + */ + private String province; + + /** + * 省份编码 + */ + private String provinceId; + + /** + * 市 + */ + private String city; + + /** + * 市编码 + */ + private String cityId; + + /** + * 区,乡镇 + */ + private String town; + + /** + * 区县编码 + */ + private String townId; + + /** + * 收件人地址 + */ + private String receiverAddress; + + /** + * 收件人地址(打码) + */ + private String receiverAddressMask; + + /** + * 收件人姓名 + */ + private String receiverName; + + /** + * 收件人姓名 + */ + private String receiverNameMask; + + /** + * 收件人手机号 + */ + private String receiverPhone; + + /** + * 收件人手机号(打码) + */ + private String receiverPhoneMask; + + /** + * 售后状态 + */ + private Integer refundStatus; + + /** + * 订单备注 + */ + private String remark; + + /** + * 订单备注标记 1-红色,2-黄色,3-绿色,4-蓝色,5-紫色 + */ + private String remarkTag; + + /** + * 订单备注标记名称 + */ + private String remarkTagName; + + /** + * 退货包运费,1:是,0:否 + */ + private Integer returnFreightPayer; + + /** + * 订单审核状态(0-正常订单, 1-审核中订单) + */ + private Integer riskControlStatus; + + /** + * 是否门店自提 + */ + private Integer selfContained; + + /** + * 商家优惠金额 + */ + private BigDecimal sellerDiscount; + + /** + * 缺货处理状态 -1:无缺货处理 0: 缺货待处理 1缺货已处理 + */ + private Integer stockOutHandleStatus; + + /** + * 全国联保,1:是,0:否 + */ + private Integer supportNationwideWarranty; + + /** + * 快递单号 + */ + private String trackingNumber; + + /** + * 以旧换新国家补贴金额,单位:元 + */ + private BigDecimal tradeInNationalSubsidyAmount; + + /** + * 订单类型 0-普通订单 ,1- 定金订单 + */ + private Integer tradeType; + + /** + * 订单的更新时间 + */ + private String updatedAt; + + /** + * 催发货时间 + */ + private String urgeShippingTime; + + /** + * 预约配送日期 + */ + private String yypsDate; + + /** + * 预约配送时段 + */ + private String yypsTime; + + /** + * 合单ID2 + */ + private String openAddressId2; + + /** + * 店铺状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 商品列表 + */ + private String itemList; + + /** + * 额外附属信息 + */ + private String extraInfo; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopOrderDetail.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopOrderDetail.java new file mode 100644 index 0000000..867cc8a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShopOrderDetail.java @@ -0,0 +1,108 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 订单详情对象 t_shop_order_detail + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_order_detail") +public class TShopOrderDetail extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 店铺id + */ + private String shopId; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 订单id + */ + private Long orderId; + + /** + * 订单号 + */ + private String orderSn; + + /** + * 商品数量 + */ + private Integer goodsCount; + + /** + * 商品编码 + */ + private String goodsId; + + /** + * 商品图片 + */ + private String goodsImg; + + /** + * 商品名称 + */ + private String goodsName; + + /** + * 商品单件 单价:元 + */ + private BigDecimal goodsPrice; + + /** + * 商品规格 + */ + private String goodsSpec; + + /** + * 商品维度外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息 + */ + private String outerGoodsId; + + /** + * sku维度商家外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息 + */ + private String outerId; + + /** + * 商品sku编码 + */ + private String skuId; + + /** + * 店铺状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserSettingsAttribute.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserSettingsAttribute.java new file mode 100644 index 0000000..acc3f24 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserSettingsAttribute.java @@ -0,0 +1,43 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; + +@Data +public class UserSettingsAttribute { + + private Long id; + /** + * 设置模板id + */ + private Long warehouseSettingId; + + /** + * 规则属性id + */ + private Long attributeId; + + /** + * 规则内容 + */ + private String attributeValue; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 创建时间 + */ + private Long createAt; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 修改时间 + */ + private Long updateAt; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserTAudit.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserTAudit.java new file mode 100644 index 0000000..471a57b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserTAudit.java @@ -0,0 +1,45 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 列表对象 t_audit + * + * @author Lion Li + * @date 2025-04-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_audit") +public class UserTAudit extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 管理员ID + */ + private Long adminId; + + /** + * 审核状态(0通过 1未通过) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopGoods.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopGoods.java new file mode 100644 index 0000000..3ca2641 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopGoods.java @@ -0,0 +1,211 @@ +package org.dromara.zhishu.domain; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import jakarta.persistence.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.tenant.core.TenantEntity; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; + +import java.io.Serial; +import java.math.BigDecimal; + +/** + * 商品信息对象 zhishu_shop_goods + * + * @author Lion Li + * @date 2025-03-07 + */ +@Data +@Entity +@EqualsAndHashCode(callSuper = true) +@TableName("zhishu_shop_goods") +@DynamicInsert +@DynamicUpdate +public class ZhishuShopGoods extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @Id + @TableId(value = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private String id; + + + /** + * 用户id + */ + @Column(name = "user_id") + private Long userId; + + /** + * 产品编码 + */ + @Column(name = "productId") + private String productId; + + /** + * 是否加入分销:0-否 1-是 + */ + @Column(name = "isJoinDistribution") + private Integer isJoinDistribution = 1; + + /** + * 仓库Id + */ + @Column(name = "depot_id") + private Long depotId; + + /** + * 商品名称 + */ + @Column(name = "goodsName") + private String goodsName; + + /** + * isbn + */ + @Column(name = "isbn") + private String isbn; + + /** + * 货号 + */ + @Column(name = "artNo") + private String artNo; + + /** + * 原始货号 + */ + @Column(name = "original_art_no") + private String originalArtNo; + + /** + * 期初库存 + */ + @Column(name = "stock") + private Long stock; + + /** + * 标准售价 + */ + @Column(name = "price") + private Long price; + + /** + * 品相 + */ + @Column(name = "conditionCode") + private String conditionCode; + + /** + * 备注 + */ + @Column(name = "remark") + private String remark; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 商品编号 + */ + @Column(name = "item_number") + private String itemNumber; + + /** + * 商品定价 + */ + @Column(name = "fixPrice") + private Long fixPrice; + + /** + * 库存 + */ + @Column(name = "inventory") + private Long inventory; + + /** + * 图片 + */ + @Column(name = "book_pic") + private String bookPic; + + /** + * 是否已进行货号转换:0-未转换 1-已转换 + */ + @Column(name = "is_art_no_conversion") + private Integer isArtNoConversion; + + /** + * 图书分类ID + */ + @Column(name = "category_id") + private Long categoryId; + /** + * 模板类型 + */ + @TableField(exist = false) + private String templateType; + /** + * 作者 + */ + @TableField(exist = false) + private String author; + /** + * 出版社 + */ + @TableField(exist = false) + private String publisher; + /** + * 纸张 + */ + @TableField(exist = false) + private String format; + /** + * 打印时间 + */ + @TableField(exist = false) + private String printTime; + /** + * 字数 + */ + @TableField(exist = false) + private String wordage; + /** + * 统一书号 + */ + @TableField(exist = false) + private String goodUnifyIsbn; + + /** + * 仓库编号 + */ + // @Column(name = "warehouseId") + // private String warehouseId; + + @TableField(exist = false) + private String templateMinPrice; + /** + * 任务id + */ + /** + * 图书分类ID + */ + @Column(name = "task_id") + private Long taskId; +} + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopGoodsDetail.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopGoodsDetail.java new file mode 100644 index 0000000..ac8eeb2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopGoodsDetail.java @@ -0,0 +1,77 @@ +package org.dromara.zhishu.domain; + +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 商品信息补全表对象 zhishu_shop_goods_detail + * + * @author yxy + * @date 2025-06-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("zhishu_shop_goods_detail") +public class ZhishuShopGoodsDetail extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 商品id + */ + private Long pid; + + /** + * 作者 + */ + private String author; + + /** + * 出版社 + */ + private String publisher; + + /** + * 出版时间 + */ + private String publishertime; + + /** + * 开本 + */ + private String format; + + /** + * 字数 + */ + private String wordage; + + /** + * 统一书号 + */ + private String unifiedisbn; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/DepotOrderBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/DepotOrderBo.java new file mode 100644 index 0000000..7fea293 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/DepotOrderBo.java @@ -0,0 +1,55 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.DepotOrder; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 仓库订单信息业务对象 t_depot_order + * + * @author yxy + * @date 2025-06-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = DepotOrder.class, reverseConvertGenerate = false) +public class DepotOrderBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 店铺订单id + */ + private String shopOrderId; + + /** + * 处理人 + */ + private Long userId; + + /** + * 商品信息 + */ + private String itemList; + + /** + * 仓库订单状态 0 待发货 1 已发货 2 无库存 3 转发任务 + */ + private String status; + + + private Integer pageNum; + + private Integer pageSize; + + private String delFlag; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EncryptionDataBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EncryptionDataBo.java new file mode 100644 index 0000000..587fd86 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EncryptionDataBo.java @@ -0,0 +1,41 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class EncryptionDataBo { + private List dataUrl; + private Integer shopPrice; + private Integer minPrice; + private Integer maxPrice; + private List shopId; + private String shopType; + private Map totalCount; + private String shopToken; + private Long mallId; + private String shopKey; + /** + * 查询条件 + */ + private String isOnSale; + private String isbn; + private String priceDown; + private String priceUp; + private String startDate; + private String endDate; + + private String goodsName; + private String stockDown; + private String stockUp; + private String trilateralId; + private String goodsCode; + private String skuCode; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ErpGoodsOrderBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ErpGoodsOrderBo.java new file mode 100644 index 0000000..92b5218 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ErpGoodsOrderBo.java @@ -0,0 +1,265 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import org.dromara.zhishu.domain.ErpGoodsOrder; + +/** + * 平台订单业务对象 erp_goods_order + * + * @author yxy + * @date 2025-12-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ErpGoodsOrder.class, reverseConvertGenerate = false) +public class ErpGoodsOrderBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 订单编号 + */ + private String orderSn; + + /** + * 平台店铺id + */ + private Long shopId; + + /** + * erp店铺id + */ + private Long shopErpId; + + /** + * erp店铺名称 + */ + private String shopErpName; + + /** + * 店铺类型 + */ + private Long shopType; + + /** + * 商品一级id + */ + private Long catId1; + + /** + * 商品二级id + */ + private Long catId2; + + /** + * 商品三级id + */ + private Long catId3; + + /** + * 商品四级id + */ + private Long catId4; + + /** + * 订单中商品sku列表 + */ + private String itemList; + + /** + * 订单金额 单位:分 + */ + private Long orderTotal; + + /** + * 商品金额(以分为单位)商品金额=商品销售价格*商品数量-订单改价折扣金额 + */ + private Long goodsAmount; + + /** + * 订单改价折扣金额(以分为单位) + */ + private Long orderChangeAmount; + + /** + * 支付金额 (以分为单位) 支付金额=商品金额-折扣金额+邮费+服务费 + */ + private Long payAmount; + + /** + * 创建时间 时间戳 + */ + private Long createdAt; + + /** + * 成交状态 + */ + private Long confirmStatus; + + /** + * 成交时间 时间戳 + */ + private Long confirmAt; + + /** + * 支付单号 + */ + private String payNo; + + /** + * 支付时间 时间戳 + */ + private Long payAt; + + /** + * 支付方式 + */ + private Long payType; + + /** + * 平台优惠金额 (以分为单位) + */ + private Long platformDiscount; + + /** + * 买家留言信息 + */ + private String buyerMemo; + + /** + * 发货状态 1:待发货,2:已发货待签收,3:已签收 + */ + private Long orderStatus; + + /** + * 物流id + */ + private Long shippingId; + + /** + * 发货时间 时间戳 + */ + private Long shippingAt; + + /** + * 收件地城市 + */ + private String city; + + /** + * 城市编码 + */ + private Long cityId; + + /** + * 收件地省份 + */ + private String province; + + /** + * 省份编码 + */ + private Long provinceId; + + /** + * 收件地国家或地区 + */ + private String country; + + /** + * 国家或地区编码 + */ + private Long countryId; + + /** + * 收件地区县 + */ + private String town; + + /** + * 区县编码 + */ + private Long townId; + + /** + * 快递单号 + */ + private String trackingNumber; + + /** + * 商家订单备注 + */ + private String remark; + + /** + * 订单备注标记,1-红色,2-黄色,3-绿色,4-蓝色,5-紫色 + */ + private Long remarkTag; + + /** + * 订单备注标记名称 + */ + private String remarkTagName; + + /** + * 确认收货时间 + */ + private Long receiveAt; + + /** + * 售后状态 + */ + private Long afterSalesStatus; + + /** + * 订单最近一次更新时间 + */ + private Long updatedAt; + + /** + * 是否可视化 + */ + private Long isShow; + + /** + * shop_id的MD5首字母(大写)用于分区 + */ + @NotBlank(message = "shop_id的MD5首字母(大写)用于分区不能为空", groups = { EditGroup.class }) + private String shopMd5Prefix; + + + /** + * 是否下发 + */ + private Long isIssue; + + /** + * erp的订单售后状态 0 无售后 1 仅退款 2 退货退款 3 处理完成 4 拒绝 5 延后处理 + */ + private Long erpAfterSalesStatus; + + /** + * erp订单售后发起时间 + */ + private Long erpAssCreateAt; + + /** + * 售后原因 + */ + private String erpAssReason; + + /** + * 拒绝原因 + */ + private String erpAssRemark; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ExcelTaskBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ExcelTaskBo.java new file mode 100644 index 0000000..2d91134 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ExcelTaskBo.java @@ -0,0 +1,67 @@ +package org.dromara.zhishu.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.zhishu.domain.ExcelTask; + +/** + * 任务列表业务对象 t_task + * + * @author yxy + * @date 2025-03-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ExcelTask.class, reverseConvertGenerate = false) +public class ExcelTaskBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 任务类型 1 发布商品 + */ + private String taskType; + + /** + * 仓库id 字符串 + */ + private String depotIds; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 执行数据条数 + */ + private Long dataNum; + + /** + * 任务状态 + */ + private String taskStatus; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 线程id + */ + private Long threadId; + + /** + * 用户id + */ + private Long userId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/FilterSetBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/FilterSetBo.java new file mode 100644 index 0000000..b0d611d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/FilterSetBo.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.FilterSet; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 过滤设置业务对象 t_filter_set + * + * @author yxy + * @date 2025-04-14 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = FilterSet.class, reverseConvertGenerate = false) +public class FilterSetBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 过滤类型 + */ + private String filterType; + + /** + * 限制类型 + */ + private String limitationType; + + /** + * 添加方式 + */ + private String addWay; + + /** + * 内容文件 + */ + private String addTxt; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 分类 + */ + private String sort; + + /** + * 加入原因 + */ + private String reason; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/InviteCodeBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/InviteCodeBo.java new file mode 100644 index 0000000..998622b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/InviteCodeBo.java @@ -0,0 +1,57 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Date; + +/** + * 邀请码业务对象 + */ +@Data +@NoArgsConstructor +public class InviteCodeBo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 邀请人ID + */ + @NotNull(message = "邀请人ID不能为空", groups = { AddGroup.class }) + private Long userId; + + /** + * 邀请码 + */ + private String code; + + /** + * 邀请链接 + */ + private String inviteUrl; + + /** + * 过期时间(天数) + */ + private Integer expireDays; + + /** + * 过期时间 + */ + private Date expireTime; + + /** + * 是否已使用 + */ + private Boolean used; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/LogisticsBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/LogisticsBo.java new file mode 100644 index 0000000..3be6f9e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/LogisticsBo.java @@ -0,0 +1,79 @@ +package org.dromara.zhishu.domain.bo; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.EditGroup; + +import java.util.List; +import java.util.Map; + +@Data +//@EqualsAndHashCode(callSuper = true) +//@AutoMapper(target = Logistics.class, reverseConvertGenerate = false) +public class LogisticsBo { + /** + * + */ + @NotNull(message = "不能为空", groups = {EditGroup.class}) + private Long id; + /** + * 发货地-区id + */ + private Integer delivery_area; //delivery_area + /** + * 发货地-市id + */ + private Integer delivery_city; + /** + * 发货地-省id + */ + private Integer delivery_province; + /** + * 计价方式(0按重量 1按标准本数(图书专用) 2按件数 3单独设置运费) + */ + private Integer pricing_method; + /** + * 运送方式(0快递 1自提) + */ + private String shipping; + + /** + * 运送范围 + */ + @JsonProperty("shipping_range") + private Map> shippingRange; + + + /** + * 物流模板名称 + */ + private String template_name; + + /** + * 仓库ID + */ + private Long warehouse_id; + + /** + * 配送说明 + */ + private String remark; + + /** + * 联系人 + */ + private String contact; + + /** + * 联系电话 + */ + private String phoneNumber; + /** + * 详细地址 + */ + private String fullAddress; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopDetailBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopDetailBo.java new file mode 100644 index 0000000..b06b9c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopDetailBo.java @@ -0,0 +1,304 @@ +package org.dromara.zhishu.domain.bo; + +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.zhishu.domain.ShopDetail; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 商品详情业务对象 t_shop_detail + * + * @author yxy + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ShopDetail.class, reverseConvertGenerate = false) +public class ShopDetailBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 物流运费模板id + */ + private Long templateId; + + /** + * 高价 + */ + private Long highPrice; + + /** + * 低价 + */ + private Long lowPrice; + + /** + * 销售模板id + */ + private Long saleTemplateId; + + /** + * 是否开启7天无理由 0关闭 1开启 + */ + private String sevenDays; + + /** + * 是否开始二手 0关闭 1开启 + */ + private String isSecondHand; + + /** + * 轮播数量开启 0关闭 1开启 + */ + private String carouselNum; + + /** + * 是否开启详情图 0关闭 1开启 + */ + private String isDetailsImg; + + /** + * 是否开启目录详情 0关闭 1开启 + */ + private String isCatalogueDetails; + + /** + * 是否开启信息图片 0关闭 1开启 + */ + private String isInformationImg; + + /** + * 标题前缀 + */ + private String titlePrefix; + + /** + * 标题后缀 + */ + private String titleSuffix; + + /** + * 标题过滤 + */ + private String titleFilter; + + /** + * 货号前缀 + */ + private String itemNumberPrefix; + + /** + * 标题组成 + */ + private String titleConsistOf; + + /** + * 间隔字符 0无间隔 1空格 + */ + private String spaceCharacter; + + /** + * 是否开启自动截断 0关闭 1开启 + */ + private String autoTruncation; + + /** + * 我的设置 + */ + private String mySetUp; + + /** + * 系统设置 + */ + private String systemSetUp; + + /** + * 过滤套装 0否 1是 + */ + private String filterSuit; + + /** + * 删除保护 0关闭 1开启 + */ + private String isDelProtect; + + /** + * 下架保护 0关闭 1开启 + */ + private String isRemoveProtect; + + /** + * 图书定价 0关闭 1开启 + */ + private String bootPrice; + + /** + * 自有图片 0关闭 1开启 + */ + private String ownPictures; + + /** + * 默认库存 + */ + private Long stockDeff; + + /** + * 两件折扣 + */ + private Long twoDiscount; + + /** + * 是否预售 0非预售 1定时预售 2 时段预售 + */ + private String presale; + + /** + * 假一赔十 0 关闭 1开启 + */ + private String fake; + + /** + * 发货时间 0 24小时 1 48小时 + */ + private String deliveryTime; + + /** + * 白底图 0关闭 1开启 + */ + private String whitePicture; + + /** + * 水印位置 0全部 1第一张 + */ + private String watermarkPosition; + + /** + * 无图过滤 0关闭 1开启 + */ + private String filtering; + + /** + * 最低价定价 0关闭 1开启 + */ + private String lowerPrice; + + /** + * 最低定价折扣 + */ + private String lowerPriceDiscount; + + /** + * 拼单模板id + */ + private Long spellTemplateId; + + /** + * 发布地区类型 + */ + private String districtType; + + /** + * 常驻地区id + */ + private String districtId; + + /** + * 默认品相 + */ + private Long conditionDef; + + /** + * 品相描述 + */ + private String conditionDes; + + /** + * 推荐语 + */ + private String recommend; + + /** + * 是否包邮 + */ + private String isParcel; + + /** + * 图书模板 + */ + private String bookTemplate; + + /** + * 图书重量 + */ + private BigDecimal bookWeight; + + /** + * 标准本数 + */ + private BigDecimal standardNumber; + + /** + * 开启闲管家过滤重复 + */ + private String openRepeat; + + /** + * 是否自动上传 0 否 1 是 + */ + private String autoAdd; + + /** + * 是否开启咸鱼擦亮 + */ + private String openPolish; + + private String context; + + /** + * 擦亮方式 0擦亮原商品 1发布新商品 + */ + private String polishType; + + /** + * 闲鱼店铺发布品类 0 图书 1 其他 + */ + private String publishType; + + /** + * 闲鱼类目ID + */ + private String categoryId; + + /** + * 频率 + */ + private int frequency; + + /** + * 自动发布的仓库id列表 + */ + private List warehouseList; + + /** + * 进销存自动发布的仓库id列表 + */ + private List mappingList; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SpecBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SpecBo.java new file mode 100644 index 0000000..ce36798 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SpecBo.java @@ -0,0 +1,90 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.Spec; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 自定义规格设置业务对象 t_spec + * + * @author yxy + * @date 2025-03-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = Spec.class, reverseConvertGenerate = false) +public class SpecBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 规格类型id + */ + private String specTypeId; + + /** + * 规格类型名称 + */ + private String specTypeName; + + /** + * 规格组成 0 自定义 1 ISBN 2 书名 3货号 + */ + private String specCompose; + + /** + * 自定义规格名称 + */ + private String specName; + + /** + * 自定义规格前缀 + */ + private String specPrefix; + + /** + * 自定义规格后缀 + */ + private String specSuffix; + + /** + * 规格编码组成 0 自定义 1 ISBN 2 书名 3货号 + */ + private String specCodeCompose; + + /** + * 自定义规格编码前缀 + */ + private String specCodePrefix; + + /** + * 自定义规格编码后缀 + */ + private String specCodeSuffix; + + /** + * SKU水印图片路径 + */ + private String specSyUrl; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SynchronizationShopLogBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SynchronizationShopLogBo.java new file mode 100644 index 0000000..6b703fe --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SynchronizationShopLogBo.java @@ -0,0 +1,93 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; + +import jakarta.validation.constraints.*; + +/** + * 同步店铺商品库存日志业务对象 + * + * @author yxy + * @date 2026-04-14 + */ +@Data +public class SynchronizationShopLogBo { + + /** + * 主键ID + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 商品id + */ + private Long goodsId; + + /** + * 商品的创建人 + */ + private Long goodsCreateBy; + + /** + * erp订单id + */ + private Long erpOrderId; + + /** + * 订单号 + */ + private String orderSn; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 店铺的创建人 + */ + private Long shopCreateBy; + + /** + * 更新后库存 + */ + private Integer inventory; + + /** + * 更新前库存 + */ + private Integer inventoryOld; + + /** + * 三方平台id + */ + private Long platformId; + + /** + * 状态码 200 成功 500 失败 + */ + private String code; + + /** + * 日志信息 + */ + private String msg; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + private Long updateBy; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TBookAuditBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TBookAuditBo.java new file mode 100644 index 0000000..8136786 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TBookAuditBo.java @@ -0,0 +1,80 @@ +package org.dromara.zhishu.domain.bo; + +import jakarta.persistence.Column; +import org.dromara.zhishu.domain.TBookAudit; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 图书审核管理业务对象 t_book_audit + * + * @author Lion Li + * @date 2025-04-18 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TBookAudit.class, reverseConvertGenerate = false) +public class TBookAuditBo extends BaseEntity { + + /** + * id + */ + private Long id; + /** + * 用户id + */ + private Long userId; + + /** + * 产品编码 + */ + private String productId; + + /** + * 商品名称 + */ + private String goodsName; + + /** + * isbn + */ + private String isbn; + + /** + * 货号 + */ + private String artNo; + + /** + * 品相 + */ +// @NotBlank(message = "品相不能为空", groups = { AddGroup.class, EditGroup.class }) + private String conditionCode; + + /** + * 商品编号 + */ + private String itemNumber; + + /** + * 审核状态(0 通过 1 未通过 2 待审核) + */ + private String status; + + /** + * 库存 + */ + private Long inventory; + + + /** + * 书图片 + */ + private String bookPic; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TDistrictBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TDistrictBo.java new file mode 100644 index 0000000..c99029c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TDistrictBo.java @@ -0,0 +1,53 @@ +package org.dromara.zhishu.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.zhishu.domain.TDistrict; + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TDistrict.class, reverseConvertGenerate = false) +public class TDistrictBo extends BaseEntity { + + /** + * 区划信息id + */ + @NotNull(message = "区划信息id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 父级挂接id + */ + private Long pid; + + /** + * 区划编码 + */ + private String code; + + /** + * 区划名称 + */ + private String name; + + /** + * 备注 + */ + private String remark; + + /** + * 状态 0 正常 -2 删除 -1 停用 + */ + private Long status; + + /** + * 级次id 0:省/自治区/直辖市 1:市级 2:县级 + */ + private Long level; + + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TLogisticsBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TLogisticsBo.java new file mode 100644 index 0000000..933bd9e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TLogisticsBo.java @@ -0,0 +1,101 @@ +package org.dromara.zhishu.domain.bo; + + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import org.dromara.zhishu.domain.TLogistics; + +/** + * 物流管理业务对象 t_logistics + * + * @author Lion Li + * @date 2025-04-22 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TLogistics.class, reverseConvertGenerate = false) +public class TLogisticsBo extends BaseEntity { + + /** + * 主键 + */ + private Long id; + + /** + * 物流模板名称 + */ + private String templateName; + + /** + * 发货地-省 + */ + private String deliveryProvince; + + /** + * 发货地-市 + */ + private String deliveryCity; + + /** + * 发货地-区 + */ + private String deliveryArea; + + /** + * 详细地址 + */ + private String deliveryAddress; + + /** + * 计价方式(0按重量 1按标准本数(图书专用) 2按件数 3单独设置运费) + */ + private String pricingMethod; + + /** + * 运送方式(0快递 1自提) + */ + private String shipping; + + /** + * 首重 首本 首件 + */ + private Long firWbv; + + /** + * 首费 单位:元 + */ + private Long firPrice; + + /** + * 续重 续本 续件 + */ + private Long continueWbv; + + /** + * 续费 单位:元 + */ + private Long continuePrice; + + /** + * 模板状态(0正常 1停用) + */ + private String status; + + /** + * 运送范围 + */ + private String shippingRange; + + /** + * 仓库ID + */ + private Long warehouseId; + + private Long userId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopDepotAotuBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopDepotAotuBo.java new file mode 100644 index 0000000..9cc21fd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopDepotAotuBo.java @@ -0,0 +1,30 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 店铺自动发布仓库关联业务对象 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class TShopDepotAotuBo extends BaseEntity { + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 店铺名称(用于搜索) + */ + private String shopName; + + /** + * 仓库名称(用于搜索) + */ + private String depotName; + + // 注意:如果需要,可以添加其他字段,但确保前端不传递不需要的参数 +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopOrderBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopOrderBo.java new file mode 100644 index 0000000..e344755 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopOrderBo.java @@ -0,0 +1,121 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.TShopOrder; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.util.List; + +/** + * 订单业务对象 t_shop_order + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TShopOrder.class, reverseConvertGenerate = false) +public class TShopOrderBo extends BaseEntity { + + /** + * 订单编号 + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 三方平台订单编号 + */ + private String orderSn; + + /** + * 订单来源类型 1-拼多多 2-孔夫子 + */ + private Integer orderSourceType; + + /** + * 订单异常类型集合(json字符串):inventoryException-库存异常 goodsSourceUnknownException-未知商品来源 + */ + private List orderExceptionTypeList; + + /** + * 售后状态 0:无售后 2:买家申请退款,待商家处理 3:退货退款,待商家处理 4:商家同意退款,退款中 5:平台同意退款,退款中 6:驳回退款,待买家处理 7:已同意退货退款,待用户发货 8:平台处理中 9:平台拒绝退款,退款关闭 10:退款成功 11:买家撤销 12:买家逾期未处理,退款失败 13:买家逾期,超过有效期 14:换货补寄待商家处理 15:换货补寄待用户处理 16:换货补寄成功 17:换货补寄失败 18:换货补寄待用户确认完成 21:待商家同意维修 22:待用户确认发货 24:维修关闭 25:维修成功 27:待用户确认收货 31:已同意拒收退款,待用户拒收 32:补寄待商家发货 33:同意召回后退款,待商家召回 + */ + private Integer afterSalesStatus; + + /** + * 成交状态:0:未成交、1:已成交、2:已取消 + */ + private Integer confirmStatus; + + /** + * 订单状态发货状态,枚举值:1:待发货,2:已发货待签收,3:已签收 + */ + private Integer orderStatus; + + /** + * 用户 + */ + private Long userId; + + /** + * 店铺id + */ + private List shopIdList; + + /** + * 商品名称 + */ + private String goodsName; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 省份名称 + */ + private String province; + + /** + * 市名称 + */ + private String city; + + /** + * 区名称 + */ + private String town; + + /** + * 查询订单创建时间起始时间 + */ + private String createdTimeStart; + + /** + * 查询订单创建时间截至时间 + */ + private String createdTimeEnd; + + /** + * 收件人名称 + */ + private String receiverNameMask; + + /** + * 收件人电话 + */ + private String receiverPhoneMask; + + /** + * 快递单号 + */ + private String trackingNumber; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TaskBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TaskBo.java new file mode 100644 index 0000000..669de5f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TaskBo.java @@ -0,0 +1,73 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.Task; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +/** + * 任务列表业务对象 t_task + * + * @author yxy + * @date 2025-03-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = Task.class, reverseConvertGenerate = false) +public class TaskBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 任务类型 1 发布商品 + */ + private String taskType; + + /** + * 店铺id 字符串 + */ + private String shopIds; + + private String shopNames; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 执行数据条数 + */ + private Long dataNum; + + /** + * 任务状态 + */ + private String taskStatus; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 线程id + */ + private String threadId; + /** + * 关系id + */ + private Long relationId; + + /** + * 更新方式 0 更新重复 2 全新上传 + */ + private String way; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserRechargeBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserRechargeBo.java new file mode 100644 index 0000000..137bedd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserRechargeBo.java @@ -0,0 +1,119 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.UserRecharge; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +/** + * 用户充值业务对象 t_user_recharge + * + * @author yxy + * @date 2025-04-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = UserRecharge.class, reverseConvertGenerate = false) +public class UserRechargeBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 用户id + */ + private Long userId; + + /** + * 充值类型 1 微信支付 2 支付宝支付 ... + */ + private String rechargType; + + /** + * 充值金额 单位分 + */ + private BigDecimal rechargPrice; + + /** + * 支付成功时间 + */ + private Date successTime; + + /** + * 支付成功后回调方法中数据字符串 + */ + private String allDataStr; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 手续费 + */ + private BigDecimal commission; + + /** + * 是否充值到余额中 + */ + private String isBalance; + + + /** + * 出账账户 + */ + private String billingAccount; + + /** + * 入账账户 + */ + private String depositAccount; + + /** + * 交易号 + */ + private String transactionId; + + /** + * 备注 + */ + private String remark; + + /** + * 付款凭证 + */ + private String voucherImg; + + /** + * 卡密 + */ + private String cardKey; + + /** + * 日志备注 + */ + private String logTxt; + + /** + * 原始金额 + */ + private BigDecimal originalPrice; + + /** + * 更新金额 + */ + private BigDecimal updatePrice; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopImagesBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopImagesBo.java new file mode 100644 index 0000000..1eeb4a7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopImagesBo.java @@ -0,0 +1,39 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; +import org.dromara.zhishu.domain.ZhishuShopImages; + +/** + * 商品图片业务对象 zhishu_shop_images + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ZhishuShopImages.class, reverseConvertGenerate = false) +public class ZhishuShopImagesBo extends BaseEntity { + + /** + * id + */ + @NotBlank(message = "id不能为空", groups = { EditGroup.class }) + private String id; + + /** + * 商品ID + */ + private String goodsId; + + /** + * 存放路径 + */ + private String path; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BatchProcessingContext.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BatchProcessingContext.java new file mode 100644 index 0000000..f3de7e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BatchProcessingContext.java @@ -0,0 +1,33 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; +import org.dromara.zhishu.domain.dto.request.ZhishuShopGoodsRequest; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 分批处理上下文 + */ +@Data +public class BatchProcessingContext { + + private Long shopId; + + private Long userId; + + private String currentDateTime; + + private List allChangedData = Collections.synchronizedList(new ArrayList<>()); + + private List allNewData = Collections.synchronizedList(new ArrayList<>()); + + private AtomicInteger receivedBatches = new AtomicInteger(0); + + private int totalBatches; + + private String lockKey; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/CSVSkuListDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/CSVSkuListDto.java new file mode 100644 index 0000000..ae4091c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/CSVSkuListDto.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CSVSkuListDto { + + @JsonProperty("is_sku_onsale") + private Integer isSkuOnsale; + + @JsonProperty("outer_goods_id") + private Long outerGoodsId; + + @JsonProperty("outer_id") + private Long outerId; + + @JsonProperty("reserve_quantity") + private Integer reserveQuantity; + + @JsonProperty("sku_id") + private Long skuId; + + @JsonProperty("sku_quantity") + private Integer skuQuantity; + + @JsonProperty("spec") + private String spec; + + @JsonProperty("single_price") + private Long singlePrice; + + @JsonProperty("group_price") + private Long groupPrice; + + @JsonProperty("spec_details") + private List specDetails; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SpecDetail{ + + @JsonProperty("parent_id") + private Long parentId; + + @JsonProperty("parent_name") + private String parentName; + + @JsonProperty("spec_id") + private Long specId; + + @JsonProperty("spec_name") + private String specName; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/OrderGoodsDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/OrderGoodsDto.java new file mode 100644 index 0000000..3e27f12 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/OrderGoodsDto.java @@ -0,0 +1,39 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 圆通物流物品DTO + * + * @author yxy + */ +@Data +@Accessors(chain = true) +public class OrderGoodsDto { + + /** + * 商品名称 + */ + private String name; + + /** + * 商品数量 + */ + private Integer quantity; + + /** + * 商品ID + */ + private String goodsId; + + /** + * 货号/ISBN + */ + private String itemSn; + + /** + * 商品品质 + */ + private String quality; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/PddOrderIncrementQuery.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/PddOrderIncrementQuery.java new file mode 100644 index 0000000..4611beb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/PddOrderIncrementQuery.java @@ -0,0 +1,39 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; + +//https://open.pinduoduo.com/application/document/api?id=pdd.order.number.list.increment.get&permissionId=36 +@Data +public class PddOrderIncrementQuery { + + + private Integer order_status; // 1:待发货,2:已发货待签收,3:已签收 5:全部 + + private Integer page; + +// private Integer page_size; + + private Integer is_lucky_flag; //订单类型(是否抽奖订单),0-全部,1-非抽奖订单,2-抽奖订单 + + private Integer refund_status; //售后状态 1:无售后或售后关闭,2:售后处理中,3:退款中,4: 退款成功 5:全部 + + private Long start_updated_at; //开始时间 区间30 分钟 + + private Long end_updated_at; //结束时间 + + + private Integer trade_type; // 0-普通订单 ,1- 定金订单 + + private boolean use_has_next; + + + private String access_token; // token + + private String startTime; + + private String endTime; + + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/RunningTaskShopGoodsDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/RunningTaskShopGoodsDto.java new file mode 100644 index 0000000..a2e331b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/RunningTaskShopGoodsDto.java @@ -0,0 +1,56 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; + +@Data +public class RunningTaskShopGoodsDto { + /** + * 表名 + */ + private String tableName; + + /** + * 是否在售状态 + */ + private String isOnsale; + + /** + * 任务编号 + */ + private Long taskId; + + /** + * ISBN编号 + */ + private String isbn; + + /** + * 价格下限 + */ + private Long priceDown; + + /** + * 价格上限 + */ + private Long priceUp; + + /** + * 开始日期 + */ + private String startDate; + + /** + * 结束日期 + */ + private String endDate; + + /** + * 页码 + */ + private Long pageNum; + + /** + * 每页大小 + */ + private Long pageSize; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/ShopGoodsDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/ShopGoodsDto.java new file mode 100644 index 0000000..de82488 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/ShopGoodsDto.java @@ -0,0 +1,78 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; + +@Data +public class ShopGoodsDto { + + private Long id; + + /** + * 商品id + */ + private String trilateralId; + + /** + * 图片地址 + */ + private String img; + + /** + * 创建时间 + */ + private String finishTime; + + /** + * 价格 单位分 + */ + private String totalPrice; + + /** + * isbn号 + */ + private String isbn; + + /** + * 标题 + */ + private String title; + + /** + * 品相 八五品就是85 全新就是100 + */ + private String quality; + + /** + * 商品编码 + */ + private String goodsCode; + + /** + * 店铺类型 1 拼多多 2 孔夫子 5 闲鱼 + */ + private String shopType; + + /** + * 库存 + */ + private String stock; + + /** + * 上下架状态 1 上架 0 下架 + */ + private String isOnSale; + + /** + * sku编号 + */ + private String skuCode; + + /** + * skuId + */ + private String skuId; + + private Integer pageNum; + + private Integer pageSize; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/WaveDetailRequestDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/WaveDetailRequestDto.java new file mode 100644 index 0000000..2d6280a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/WaveDetailRequestDto.java @@ -0,0 +1,82 @@ +package org.dromara.zhishu.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import jakarta.validation.Valid; +import java.util.List; + +@Data +@Schema(description = "波次明细请求DTO") +public class WaveDetailRequestDto { + + /** + * 波次ID(用户输入) + */ + @NotBlank(message = "波次ID不能为空") + @Schema(description = "波次ID", example = "WAVE001") + private String waveId; + + @NotBlank(message = "品相不能为空") + @Schema(description = "品相", example = "85") + private String quality; + + /** + * 货号(扫描的5位英数混合码) + */ + @NotBlank(message = "货号不能为空") + @Schema(description = "货号", example = "A12B3") + private String shipmentId; + + /** + * ISBN列表 + */ + @Valid + @NotNull(message = "ISBN列表不能为空") + @Schema(description = "ISBN列表") + private List isbnList; + + /** + * ISBN总数 + */ + @NotNull(message = "ISBN总数不能为空") + @Schema(description = "ISBN总数", example = "10") + private Integer totalCount; + + /** + * 提交时间,格式:yyyy/mm/dd hh:mm + */ + @NotBlank(message = "提交时间不能为空") + @Pattern(regexp = "\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}", + message = "时间格式应为 yyyy/MM/dd HH:mm") + @Schema(description = "提交时间,格式为 yyyy/MM/dd HH:mm", example = "2024/01/15 14:30") + private String submitTime; + + @Data + @Schema(description = "ISBN信息DTO") + public static class IsbnDto { + /** + * ISBN码 + */ + @NotBlank(message = "ISBN码不能为空") + @Schema(description = "ISBN码", example = "9787111636628") + private String isbn; + + /** + * 扫描时间,格式:yyyy/mm/dd hh:mm + */ + @NotBlank(message = "扫描时间不能为空") + @Pattern(regexp = "\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}", + message = "时间格式应为 yyyy/MM/dd HH:mm") + @Schema(description = "扫描时间,格式为 yyyy/MM/dd HH:mm", example = "2024/01/15 14:30") + private String time; + + private String quality; + } + + @Schema(description = "登录人ID", example = "123456") + private String userId; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/AddTaskLogRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/AddTaskLogRequest.java new file mode 100644 index 0000000..1fb3389 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/AddTaskLogRequest.java @@ -0,0 +1,28 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AddTaskLogRequest { + + private String taskId; + + private String shopId; + + private String isbn; + + private String totalPrice; + + private String goodsId; + + private String taskType; + + private String msg; + + private String successData; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/AuthorizationWlnRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/AuthorizationWlnRequest.java new file mode 100644 index 0000000..5e08e39 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/AuthorizationWlnRequest.java @@ -0,0 +1,16 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AuthorizationWlnRequest { + + private String appKey; + + private String appSecret; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/BatchGoodsRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/BatchGoodsRequest.java new file mode 100644 index 0000000..ad1ff7e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/BatchGoodsRequest.java @@ -0,0 +1,56 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 分批处理请求结构体 + * 用于B程序向A程序分批传输数据 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BatchGoodsRequest { + /** + * 店铺ID + */ + private Long shopId; + + /** + * 主任务ID + */ + private Long taskId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 当前批次号 + */ + private Integer batchNo; + + /** + * 总批次数 + */ + private Integer totalBatches; + + /** + * 当前批次数据 + */ + private List batchData; + + /** + * 同步时间 + */ + private String currentDateTime; + + /** + * 是否是最后一批 + */ + private Boolean isLastBatch; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/BatchSetSoldOutRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/BatchSetSoldOutRequest.java new file mode 100644 index 0000000..dd335aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/BatchSetSoldOutRequest.java @@ -0,0 +1,27 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BatchSetSoldOutRequest { + + /** + * 店铺Id + */ + @NotBlank(message = "店铺Id不能为空") + private String shopId; + + /** + * 商品信息 + */ + private List items; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpGoodsQueryOlnGoodsRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpGoodsQueryOlnGoodsRequest.java new file mode 100644 index 0000000..5d8c21d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpGoodsQueryOlnGoodsRequest.java @@ -0,0 +1,49 @@ +package org.dromara.zhishu.domain.dto.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ErpGoodsQueryOlnGoodsRequest { + + // 当前页码,从1开始 + private Integer page = 1; + + // 每页大小,最大50 + private Integer limit = 50; + + // 查询结束时间 + @JsonProperty("end_time") + private String endTime; + + // 线上商品编码 + @JsonProperty("item_id") + private String itemId; + + // 店铺ID 商品编码不为空场景下必须填写 + @JsonProperty("shop_nick") + private String shopNick; + + // 查询起始时间 + @JsonProperty("start_time") + private String startTime; + + // 扩展查询条件 + private Ext ext; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Ext { + + // 店铺类型,如0:淘宝,2:京东,28:拼多多,51:抖店等 更多可通过接口(/base/shop/list/shopTypes)获取 + @JsonProperty("shop_type") + private Integer shopType; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GetShopGoodsListRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GetShopGoodsListRequest.java new file mode 100644 index 0000000..0c58389 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GetShopGoodsListRequest.java @@ -0,0 +1,136 @@ +package org.dromara.zhishu.domain.dto.request; + +public class GetShopGoodsListRequest { + + private String token; + + // 商品列表类型。默认值为:sale,可选值为:sale(在售的商品),delisting(下架的商品),uncertif + private String type; + + // 页码。默认为:1 + private Integer pageNum; + + // 每页最大条数。默认为:50,最大值为:100 + private Integer pageSize; + + // 商品编号。可以通过商品编号精确匹配查询商品。 + private Long itemId; + + // 货号。尾部模糊查询,例如:itemSn=测试货号,是查询货号以“测试货号”开头的所有商品 + private String itemSn; + + // ISBN号。可以更新ISBN号查询相同ISBN的商品。 + private String isbn; + + // 上传时间,用于查询此时间之后上传的商品。格式: 2020-04-29 12:00:00 + private String addTimeBegin; + + // 上传时间,用于查询此时间之前上传的商品。格式: 2020-04-29 12:00:00 + private String addTimeEnd; + + // 排序字段,可选值为:itemId(根据商品编号排序),addTime(根据上书时间排序) + private String sortOrder; + + // 排序方式,可选值为:ASC(正序),DESC(倒序) + private String sortType; + + // 偏移查询商品编号,结合 itemId 排序,可优化查询,遍历全部商品 + private Long offsetId; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Integer getPageNum() { + return pageNum; + } + + public void setPageNum(Integer pageNum) { + this.pageNum = pageNum; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public Long getItemId() { + return itemId; + } + + public void setItemId(Long itemId) { + this.itemId = itemId; + } + + public String getItemSn() { + return itemSn; + } + + public void setItemSn(String itemSn) { + this.itemSn = itemSn; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getAddTimeBegin() { + return addTimeBegin; + } + + public void setAddTimeBegin(String addTimeBegin) { + this.addTimeBegin = addTimeBegin; + } + + public String getAddTimeEnd() { + return addTimeEnd; + } + + public void setAddTimeEnd(String addTimeEnd) { + this.addTimeEnd = addTimeEnd; + } + + public String getSortOrder() { + return sortOrder; + } + + public void setSortOrder(String sortOrder) { + this.sortOrder = sortOrder; + } + + public String getSortType() { + return sortType; + } + + public void setSortType(String sortType) { + this.sortType = sortType; + } + + public Long getOffsetId() { + return offsetId; + } + + public void setOffsetId(Long offsetId) { + this.offsetId = offsetId; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsSaleStatusSetBatchRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsSaleStatusSetBatchRequest.java new file mode 100644 index 0000000..23bc9a9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsSaleStatusSetBatchRequest.java @@ -0,0 +1,22 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Data +public class GoodsSaleStatusSetBatchRequest { + + @NotBlank(message = "token不能为空") + private String token; + + @NotNull(message = "商品状态不能为空") + private Integer isOnSale; + + @NotEmpty(message = "平台商品Id不能为空") + private List goodsPlatformIds; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsSaleStatusSetRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsSaleStatusSetRequest.java new file mode 100644 index 0000000..2ce8fe2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsSaleStatusSetRequest.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import java.util.List; + +@Data +public class GoodsSaleStatusSetRequest { + + @NotBlank(message = "token不能为空") + private String token; + + @NotNull(message = "商品状态不能为空") + private Integer isOnSale; + + @NotEmpty(message = "平台商品Id不能为空") + private Long goodsPlatformId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryPddRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryPddRequest.java new file mode 100644 index 0000000..0727b89 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryPddRequest.java @@ -0,0 +1,36 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrderDeliveryPddRequest { + + // 店铺Id + private Long shopId; + + // 快递公司编号 + private Long logisticsId; + + // 订单号 + private String orderSn; + + // 快递单号 + private String trackingNumber; + + // 发货个性内容 + private String feature; + + // 修改发货模式:不传则默认为首次发货 1=首次发货:用于订单首次发货,仅待发货订单可传入; 2=修改发货:用于订单修改发货,调用成功后将会覆盖原发货信息,仅已发货订单可传入 + private Integer redeliveryType; + + // 退货地址的id,不填则取商品默认退货地址(可在“拼多多-商家后台/售后工作台/售后设置”为商品绑定默认退货地址,若未设置则取店铺默认退货地址) + private String refundAddressId; + + // 发货批次:普通订单无需传入,当前仅限 分批发货订单(考研图书等场景) 传入 + private Integer sequenceId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryRequest.java new file mode 100644 index 0000000..90ce599 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryRequest.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrderDeliveryRequest { + + // 订单类型(1-拼多多 2-孔夫子) + @NotNull(message = "订单类型不能为空") + private Integer orderSourceType; + + // 店铺Id + @NotNull(message = "店铺Id不能为空") + private Long shopId; + + // 三方订单Id + @NotNull(message = "订单Id不能为空") + private String orderSn; + + // 配送方式 + @NotNull(message = "配送方式不能为空") + private String methodId; + + // 快递单号 + private String trackingNumber; + + // 自定义(孔夫子类型传:methodId=other时必传) + private String userDefined; + + // 多个运单号(孔夫子类型传) + private String moreShipmentNum; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/RenovateOnSaleRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/RenovateOnSaleRequest.java new file mode 100644 index 0000000..d955e2a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/RenovateOnSaleRequest.java @@ -0,0 +1,27 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.zhishu.domain.dto.BookPriceInfoDto; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RenovateOnSaleRequest { + + // 核价数据 + @NotEmpty + private BookPriceInfoDto data; + + // 店铺ID + @NotBlank + private String shopId; + + // 任务ID + @NotBlank + private String taskId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateIsSynOrderRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateIsSynOrderRequest.java new file mode 100644 index 0000000..109cb4b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateIsSynOrderRequest.java @@ -0,0 +1,20 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateIsSynOrderRequest { + + @NotBlank(message = "店铺Id不能为空") + private String shopId; + + @NotNull(message = "订单是否开启状态不能为空") + private Integer isSynOrder; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateSkuPriceRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateSkuPriceRequest.java new file mode 100644 index 0000000..5d2147a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateSkuPriceRequest.java @@ -0,0 +1,42 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateSkuPriceRequest { + + @NotBlank(message = "token不能为空") + private String token; + + @NotEmpty(message = "goodsSkus不能为空") + private List goodsSkus; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class GoodsSku { + + @NotNull(message = "平台商品Id不能为空") + private Long goodsPlatformId; + + @NotNull(message = "拼团购买价格不能为空") + private Long groupPrice; + + @NotNull(message = "单独购买价格不能为空") + private Long singlePrice; + + @NotNull(message = "商品规格Id不能为空") + private Long skuId; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ZhishuShopGoodsRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ZhishuShopGoodsRequest.java new file mode 100644 index 0000000..fc07aa2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ZhishuShopGoodsRequest.java @@ -0,0 +1,152 @@ +package org.dromara.zhishu.domain.dto.request; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +/** + * 商品信息业务对象 zhishu_shop_goods + * + * @author Lion Li + * @date 2025-03-07 + */ +@Data +public class ZhishuShopGoodsRequest { + + /** + * 商品id + */ + @ExcelProperty(value = "商品id", index = 0) + private String id; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id", index = 1) + private String userId; + + /** + * 租户编号 + */ + @ExcelIgnore + private String tenantId; + + /** + * 产品编码 + */ + @ExcelProperty(value = "产品编码", index = 2) + private String productId; + + /** + * 商品名称 + */ + @ExcelProperty(value = "商品名称", index = 3) + private String goodsName; + + /** + * isbn + */ + @ExcelProperty(value = "isbn", index = 4) + private String isbn; + + /** + * 货号 + */ + @ExcelProperty(value = "货号", index = 5) + private String artNo; + + /** + * 期初库存 + */ + @ExcelProperty(value = "期初库存", index = 6) + private Long stock; + + /** + * 标准售价 + */ + @ExcelProperty(value = "标准售价", index = 7) + private Long price; + + /** + * 品相 + */ + @ExcelProperty(value = "品相", index = 8) + private Integer conditionCode; + + /** + * 备注 + */ + @ExcelProperty(value = "备注", index = 9) + private String remark; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @ExcelIgnore + private String delFlag; + + /** + * 作者 + */ + private String author; + + /** + * 出版社 + */ + private String publisher; + + /** + * 出版时间 + */ + private String publisherTime; + + /** + * 开本 + */ + private String format; + /** + * 开本 + */ + private String wordage; + /** + * 统一书号 + */ + private String unifiedIsbn; + + /** + * 创建者 + */ + @ExcelIgnore + private Long createBy; + + /** + * 商品编号 + */ + @ExcelProperty(value = "商品编号", index = 10) + private String itemNumber; + + /** + * 商品定价 + */ + @ExcelProperty(value = "商品定价", index = 11) + private Long fixPrice; + + /** + * 库存 + */ + @ExcelProperty(value = "库存", index = 12) + private Integer inventory; + + /** + * 书图片 + */ + @ExcelProperty(value = "书图片", index = 13) + private String bookPic; + + /** + * 是否已进行货号转换:0-未转换 1-已转换 + */ + @ExcelIgnore + private Integer isArtNoConversion; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GoodsSaleStatusSetResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GoodsSaleStatusSetResponse.java new file mode 100644 index 0000000..48c16de --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GoodsSaleStatusSetResponse.java @@ -0,0 +1,22 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GoodsSaleStatusSetResponse { + + /** + * 平台商品Id + */ + private Long platformId; + + /** + * 信息 + */ + private String msg; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ItemListingResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ItemListingResponse.java new file mode 100644 index 0000000..27f3f10 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ItemListingResponse.java @@ -0,0 +1,26 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.Data; + +@Data +public class ItemListingResponse { + private String requestId; + private String requestMethod; + private SuccessResponse successResponse; + private Object errorResponse; + + @Data + public static class SuccessResponse { + private Item item; + } + + @Data + public static class Item { + private Integer itemId; + private String certifyStatus; + private String beginSaleTime; + private String updateTime; + private String endSaleTime; + private String isOnSale; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/excel/BaseInfoExcel.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/excel/BaseInfoExcel.java new file mode 100644 index 0000000..330c417 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/excel/BaseInfoExcel.java @@ -0,0 +1,119 @@ +package org.dromara.zhishu.domain.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +@Data +public class BaseInfoExcel { + + /** + * 书名 + */ + @ExcelProperty("书名") + private String bookName; + + /** + * 书图片 + */ + @ExcelProperty("图片地址") + private String bookPic; + + /** + * ibsn + */ + @ExcelProperty("isbn") + private String isbn; + + /** + * 作者 + */ + @ExcelProperty("作者") + private String author; + + /** + * 编辑 + */ + @ExcelProperty("编辑") + private String editor; + + /** + * 装帧 + */ + @ExcelProperty("装帧") + private String bindingLayout; + + /** + * 出版社 + */ + @ExcelProperty("出版社") + private String publisher; + + /** + * 版次 + */ + @ExcelProperty("版次") + private String edition; + + /** + * 开本 + */ + @ExcelProperty("开本") + private String format; + + /** + * 语种 + */ + @ExcelProperty("开本") + private String languages; + + /** + * 出版时间 + */ + @ExcelProperty("出版时间") + private String publicationTime; + + /** + * 印刷时间 + */ + @ExcelProperty("印刷时间") + private String printTime; + + /** + * 纸张 + */ + @ExcelProperty("纸张") + private String paper; + + /** + * 页数 + */ + @ExcelProperty("页数") + private String pages; + + /** + * 字数 + */ + @ExcelProperty("字数") + private String wordage; + + /** + * 定价 + */ + @ExcelProperty("定价") + private String fixPrice; + + /** + * 内容 + */ + @ExcelProperty("内容") + private String content; + + /** + * 备注 + */ + @ExcelProperty("备注") + private String remark; + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/excel/GoodsExcel.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/excel/GoodsExcel.java new file mode 100644 index 0000000..f48cdf8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/excel/GoodsExcel.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.domain.excel; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMappers; +import lombok.Data; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; + +@AutoMappers({ + @AutoMapper(target = ZhishuShopGoodsBo.class, reverseConvertGenerate = false) +}) +@Data +public class GoodsExcel { +// @ExcelProperty("商品编号\n") +// private String goodsNo; +// @ExcelProperty("商品名称\n") +// private String goodsName; +// @ExcelProperty("货号\n") +// private String artNo; +// @ExcelProperty("ISBN\n") +// private String isbn; +// @ExcelProperty("作者\n") +// private String author; +// @ExcelProperty("出版社\n") +// private String publishing; +// @ExcelProperty("商品定价\n") +// private String fixPrice; +// @ExcelProperty("商品售价\n") +// private String price; +// @ExcelProperty("本店分类\n") +// private String shopSort; +// @ExcelProperty("商品分类\n") +// private String sort; +// @ExcelProperty("品相\n") +// private String conditionCode; +// @ExcelProperty("库存\n") +// private String inventory; + // @ExcelProperty("上书时间\n") +// private String time; + + +// @ExcelProperty(index = 0) +// private String goodsNo; + @ExcelProperty(index = 0) + private String goodsName; + @ExcelProperty(index = 1) + private String artNo; + @ExcelProperty(index = 2) + private String isbn; + @ExcelProperty(index = 3) + private String conditionCode; + @ExcelProperty(index = 4) + private Long price; + @ExcelProperty(index = 5) + private Long inventory; +// @ExcelProperty(index = 4) +// private String author; +// @ExcelProperty(index = 5) +// private String publishing; +// @ExcelProperty(index = 6) +// private Long fixPrice; +// @ExcelProperty(index = 8) +// private String shopSort; +// @ExcelProperty(index = 9) +// private String sort; +// @ExcelProperty(index = 12) +// private String time; +// @ExcelProperty(index = 13) +// private Integer isArtNoConversion; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/AccessTokenVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/AccessTokenVo.java new file mode 100644 index 0000000..c3fd6b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/AccessTokenVo.java @@ -0,0 +1,39 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AccessTokenVo { + + /** + * 认证token + */ + private String accessToken; + + /** + * 消息推送 + */ + private MessageSubscribeVo messageSubscribeVo; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public MessageSubscribeVo getMessageSubscribeVo() { + return messageSubscribeVo; + } + + public void setMessageSubscribeVo(MessageSubscribeVo messageSubscribeVo) { + this.messageSubscribeVo = messageSubscribeVo; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ArtNoMoveVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ArtNoMoveVo.java new file mode 100644 index 0000000..a55a2cd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ArtNoMoveVo.java @@ -0,0 +1,19 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; + +@Data +public class ArtNoMoveVo { + private Long id; + private String oldArtNo; + private String newArtNo; + private Long userId; + private Long oldDepotId; + private Long newDepotId; + private Long createBy; + private Long createTime; + private Long updateBy; + private Long updateTime; + private Long isDel; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookBaseInfoVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookBaseInfoVo.java new file mode 100644 index 0000000..8e9a690 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookBaseInfoVo.java @@ -0,0 +1,253 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.pdd.pop.ext.fasterxml.jackson.annotation.JsonProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.zhishu.domain.BookBaseInfo; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 基础信息视图对象 book_base_info + * + * @author Lion Li + * @date 2025-03-08 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BookBaseInfo.class) +public class BookBaseInfoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private String id; + + /** + * 分类 + */ + @ExcelProperty(value = "分类") + private String category; + /** + * 书名 + */ + @ExcelProperty(value = "书名") + private String bookName; + + /** + * 书图片 + */ + @ExcelProperty(value = "书图片") + @JsonProperty("bookPic") + private BookPic bookPic; + + /** + * ibsn + */ + @ExcelProperty(value = "ibsn") + private String isbn; + + /** + * 作者 + */ + @ExcelProperty(value = "作者") + private String author; + + /** + * 编辑 + */ + @ExcelProperty(value = "编辑") + private String editor; + + /** + * 装帧 + */ + @ExcelProperty(value = "装帧") + private String bindingLayout; + + /** + * 出版社 + */ + @ExcelProperty(value = "出版社") + private String publisher; + + /** + * 版次 + */ + @ExcelProperty(value = "版次") + private String edition; + + /** + * 开本 + */ + @ExcelProperty(value = "开本") + private String format; + + /** + * 语种 + */ + @ExcelProperty(value = "语种") + private String languages; + + /** + * 出版时间 + */ + @ExcelProperty(value = "出版时间") + private String publicationTime; + + /** + * 印刷时间 + */ + @ExcelProperty(value = "印刷时间") + private String printTime; + + /** + * 纸张 + */ + @ExcelProperty(value = "纸张") + private String paper; + + /** + * 页数 + */ + @ExcelProperty(value = "页数") +// private String pages; + private String pageCount; + + /** + * 字数 + */ + @ExcelProperty(value = "字数") +// private String wordage; + private String wordCount; + + /** + * 定价 + */ + @ExcelProperty(value = "定价") + private String fixPrice; + + /** + * 内容 + */ + @ExcelProperty(value = "内容") + private String content; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 多少人买过 + */ + @ExcelProperty(value = "多少人买过") +// @JsonProperty("buy_counts") // 明确指定JSON字段名 + private String buyCounts; + + + /** + * 多少人在卖 + */ + @ExcelProperty(value = "多少人在卖") +// @JsonProperty("sell_counts") // 明确指定JSON字段名 + private String sellCounts; + + private String price; + + private String stock; + + private String bookPicNew; + + // 实拍图 + @ExcelProperty(value = "实拍图") + @JsonProperty("bookPicS") + private BookPic bookPicS; + + /** + * 叶子类目id + */ + private Long catId; + /** + * 本系统 + */ + private String goodsId; + //书名 + private String goodsName; + //商家编码 + private String code; + //excel指定商品图片 + private String bookImgUrl; + //消息 + private String msg; + //商品实拍图 + private String useImages; + //excel上传书名 + private String bookNameExcel; + //品相 + private String conditionCode; + //货号 + private String artNo; + //简介图片 + private String contentImage; + //孔夫子模板号 + private String tpl; + //同意书号 + private String unifiedIsbn; + //违规书号 + private Integer vioBook; + //套装书 + private Integer bookSet; + //一号多书 + private Integer onenumMbooks; + //违规出版社 + private Integer illPublisher; + //违规作者 + private Integer illAuthor; + + //仓库id + private String depotId; + + //货架id + private String shelvesId; + + //货位id + private String freightId; + + //图片类型 官图-1 实图-0 + private String picType; + //书号分类 9787-1 非9787-0 + private String categoryType; + //是否套装书 + private Long isSuit; + + private Integer daySale7; + private Integer daySale15; + private Integer daySale30; + private Integer daySale60; + private Integer daySale90; + private Integer daySale180; + private Integer daySale365; + private Integer thisYearSale; + private Integer lastYearSale; + private Integer totalSale; + private String updateTime; + /** 是否驳回商品:0=不限, 1=驳回商品 */ + private Integer isIllegal; + + /** 是否违规商品:0=不限, 1=违规商品 */ + private Integer isReturn; + + private String isFilter; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditIsOnsaleVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditIsOnsaleVo.java new file mode 100644 index 0000000..2d2ed59 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditIsOnsaleVo.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BookEditIsOnsaleVo.class) +public class BookEditIsOnsaleVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "商品ID(选填)") + @ColumnWidth(25) + private String trilateralId; + + @ExcelProperty(value = "商品编码(选填)") + @ColumnWidth(25) + private String goodsCode; + + @ExcelProperty(value = "ISBN(选填)") + @ColumnWidth(25) + private String isbn; + + @ExcelProperty(value = "上下架状态(必填)", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=下架,1=上架") + private String isOnSale; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/CourierLogVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/CourierLogVo.java new file mode 100644 index 0000000..27d52e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/CourierLogVo.java @@ -0,0 +1,85 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; +import java.math.BigDecimal; + +/** + * 快递日志视图对象 + * + * @author yxy + * @date 2026-03-18 + */ +@Data +public class CourierLogVo { + + /** + * 主键ID + */ + private Long id; + + /** + * erp订单id + */ + private Long erpOrderId; + + /** + * 订单编号 + */ + private String orderSn; + + /** + * 账号 + */ + private String partnerId; + + /** + * 联调密码 + */ + private String secret; + + /** + * 发件人信息 + */ + private String sender; + + /** + * 收件人信息 + */ + private String receiver; + + /** + * 商品信息 + */ + private String items; + + /** + * 订单唯一序列号 + */ + private String orderSerialNo; + + /** + * 操作类型 + */ + private String type; + + + /** + * 创建人 + */ + private Long createBy; + + /** + * 创建时间 + */ + private Long createAt; + + /** + * 修改人 + */ + private Long updateBy; + + /** + * 修改时间 + */ + private Long updateAt; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DecryptDataVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DecryptDataVo.java new file mode 100644 index 0000000..ade904e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DecryptDataVo.java @@ -0,0 +1,49 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DecryptDataVo { + + private Long url; //数据文件网络访问链接 + + private Long shopId; //店铺Id + + private Long mallId; //店铺平台id + + private String shopKey; // 闲鱼用:闲鱼店铺key + + private Integer type; //店铺类型 + + private Integer prePrice; //优惠券金额 + + private Integer maxPerice; //利润区间最大值 + + private Integer minPerice; //利润区间最小值 + + private Long totalCount; + + private String shopToken; + + private String isOnSale; + + private String isbn; + private String priceDown; + private String priceUp; + private String startDate; + private String endDate; + + private String goodsName; + private String stockDown; + private String stockUp; + private String trilateralId; + private String goodsCode; + private String skuCode; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ErpGoodsOrderVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ErpGoodsOrderVo.java new file mode 100644 index 0000000..7335270 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ErpGoodsOrderVo.java @@ -0,0 +1,313 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.zhishu.domain.ErpGoodsOrder; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 平台订单视图对象 erp_goods_order + * + * @author yxy + * @date 2025-12-10 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ErpGoodsOrder.class) +public class ErpGoodsOrderVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 订单编号 + */ + @ExcelProperty(value = "订单编号") + private String orderSn; + + /** + * 平台店铺id + */ + @ExcelProperty(value = "平台店铺id") + private Long shopId; + + /** + * erp店铺id + */ + @ExcelProperty(value = "erp店铺id") + private Long shopErpId; + + /** + * erp店铺名称 + */ + private String shopErpName; + + /** + * 店铺类型 + */ + @ExcelProperty(value = "店铺类型") + private Long shopType; + + /** + * 商品一级id + */ + @ExcelProperty(value = "商品一级id") + private Long catId1; + + /** + * 商品二级id + */ + @ExcelProperty(value = "商品二级id") + private Long catId2; + + /** + * 商品三级id + */ + @ExcelProperty(value = "商品三级id") + private Long catId3; + + /** + * 商品四级id + */ + @ExcelProperty(value = "商品四级id") + private Long catId4; + + /** + * 订单中商品sku列表 + */ + @ExcelProperty(value = "订单中商品sku列表") + private String itemList; + + /** + * 订单金额 单位:分 + */ + @ExcelProperty(value = "订单金额 单位:分") + private Long orderTotal; + + /** + * 商品金额(以分为单位)商品金额=商品销售价格*商品数量-订单改价折扣金额 + */ + @ExcelProperty(value = "商品金额", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "以=分为单位") + private Long goodsAmount; + + /** + * 订单改价折扣金额(以分为单位) + */ + @ExcelProperty(value = "订单改价折扣金额(以分为单位)") + private Long orderChangeAmount; + + /** + * 支付金额 (以分为单位) 支付金额=商品金额-折扣金额+邮费+服务费 + */ + @ExcelProperty(value = "支付金额 (以分为单位) 支付金额=商品金额-折扣金额+邮费+服务费") + private Long payAmount; + + /** + * 创建时间 时间戳 + */ + @ExcelProperty(value = "创建时间 时间戳") + private Long createdAt; + + /** + * 成交状态 + */ + @ExcelProperty(value = "成交状态") + private Long confirmStatus; + + /** + * 成交时间 时间戳 + */ + @ExcelProperty(value = "成交时间 时间戳") + private Long confirmAt; + + /** + * 支付单号 + */ + @ExcelProperty(value = "支付单号") + private String payNo; + + /** + * 支付时间 时间戳 + */ + @ExcelProperty(value = "支付时间 时间戳") + private Long payAt; + + /** + * 支付方式 + */ + @ExcelProperty(value = "支付方式") + private Long payType; + + /** + * 平台优惠金额 (以分为单位) + */ + @ExcelProperty(value = "平台优惠金额 (以分为单位)") + private Long platformDiscount; + + /** + * 买家留言信息 + */ + @ExcelProperty(value = "买家留言信息") + private String buyerMemo; + + /** + * 发货状态 1:待发货,2:已发货待签收,3:已签收 + */ + @ExcelProperty(value = "发货状态 1:待发货,2:已发货待签收,3:已签收") + private Long orderStatus; + + /** + * 物流id + */ + @ExcelProperty(value = "物流id") + private Long shippingId; + + /** + * 发货时间 时间戳 + */ + @ExcelProperty(value = "发货时间 时间戳") + private Long shippingAt; + + /** + * 收件地城市 + */ + @ExcelProperty(value = "收件地城市") + private String city; + + /** + * 城市编码 + */ + @ExcelProperty(value = "城市编码") + private Long cityId; + + /** + * 收件地省份 + */ + @ExcelProperty(value = "收件地省份") + private String province; + + /** + * 省份编码 + */ + @ExcelProperty(value = "省份编码") + private Long provinceId; + + /** + * 收件地国家或地区 + */ + @ExcelProperty(value = "收件地国家或地区") + private String country; + + /** + * 国家或地区编码 + */ + @ExcelProperty(value = "国家或地区编码") + private Long countryId; + + /** + * 收件地区县 + */ + @ExcelProperty(value = "收件地区县") + private String town; + + /** + * 区县编码 + */ + @ExcelProperty(value = "区县编码") + private Long townId; + + /** + * 快递单号 + */ + @ExcelProperty(value = "快递单号") + private String trackingNumber; + + /** + * 商家订单备注 + */ + @ExcelProperty(value = "商家订单备注") + private String remark; + + /** + * 订单备注标记,1-红色,2-黄色,3-绿色,4-蓝色,5-紫色 + */ + @ExcelProperty(value = "订单备注标记,1-红色,2-黄色,3-绿色,4-蓝色,5-紫色") + private Long remarkTag; + + /** + * 订单备注标记名称 + */ + @ExcelProperty(value = "订单备注标记名称") + private String remarkTagName; + + /** + * 确认收货时间 + */ + @ExcelProperty(value = "确认收货时间") + private Long receiveAt; + + /** + * 售后状态 + */ + @ExcelProperty(value = "售后状态") + private Long afterSalesStatus; + + /** + * 订单最近一次更新时间 + */ + @ExcelProperty(value = "订单最近一次更新时间") + private Long updatedAt; + + /** + * 是否可视化 + */ + private Long isShow; + + /** + * shop_id的MD5首字母(大写)用于分区 + */ + private String shopMd5Prefix; + + + /** + * 是否下发 + */ + private Long isIssue; + + /** + * erp的订单售后状态 0 无售后 1 仅退款 2 退货退款 3 处理完成 4 拒绝 5 延后处理 + */ + private int erpAfterSalesStatus; + + /** + * erp订单售后发起时间 + */ + private Long erpAssCreateAt; + + /** + * 售后原因 + */ + private String erpAssReason; + + /** + * 拒绝原因 + */ + private String erpAssRemark; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilterSetTxtVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilterSetTxtVo.java new file mode 100644 index 0000000..c2acb16 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilterSetTxtVo.java @@ -0,0 +1,29 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FilterSetTxtVo.class) +public class FilterSetTxtVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 内容文件 + */ + @ExcelProperty(value = "过滤内容") + private String addTxt; + + /** + * 分类 + */ + private String sort; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FreightGoodsCountVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FreightGoodsCountVo.java new file mode 100644 index 0000000..8b240e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FreightGoodsCountVo.java @@ -0,0 +1,33 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FreightGoodsCountVo { + + // 一级仓库Id + private Long depotId; + + // 一级仓库编码 + private String depotCode; + + // 二级货架Id + private Long shelvesId; + + // 二级货架编码 + private String shelvesCode; + + // 三级货区Id + private Long freightId; + + // 三级货区编码 + private String freightCode; + + // 关联商品数量 + private Integer goodsCount; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemGFVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemGFVo.java new file mode 100644 index 0000000..fc7d5e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemGFVo.java @@ -0,0 +1,24 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GoodsItemGFVo { + + private String images; + private Long itemId; + private String outerId; + private Integer price; + private Long productId; + private Integer quantity; + private String serviceSupport; + private Long skuId; + private String skuOuterId; + private String skuText; + private String title; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemPddVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemPddVo.java new file mode 100644 index 0000000..f5ec978 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemPddVo.java @@ -0,0 +1,30 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GoodsItemPddVo { + + private Integer goodsCount; + + private String goodsId; + + private String goodsImg; + + private String goodsName; + + private Double goodsPrice; + + private String goodsSpec; + + private String outerGoodsId; + + private String outerId; + + private String skuId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/MessageSubscribeVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/MessageSubscribeVo.java new file mode 100644 index 0000000..c7e3e5e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/MessageSubscribeVo.java @@ -0,0 +1,39 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MessageSubscribeVo { + + /** + * 平台 + */ + private String platformType; + + /** + * 消息主题集合 + */ + private List topicList; + + public String getPlatformType() { + return platformType; + } + + public void setPlatformType(String platformType) { + this.platformType = platformType; + } + + public List getTopicList() { + return topicList; + } + + public void setTopicList(List topicList) { + this.topicList = topicList; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/NoticeVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/NoticeVo.java new file mode 100644 index 0000000..caa7d1f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/NoticeVo.java @@ -0,0 +1,69 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.Notice; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 消息通知视图对象 t_notice + * + * @author yxy + * @date 2025-05-17 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Notice.class) +public class NoticeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 发件人 + */ + @ExcelProperty(value = "发件人") + private String sender; + + /** + * 收件人 + */ + @ExcelProperty(value = "收件人") + private String recipient; + + /** + * 消息 + */ + @ExcelProperty(value = "消息") + private String content; + + /** + * 状态 0 未读 1 已读 + */ + @ExcelProperty(value = "状态 0 未读 1 已读", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_yes_no") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PriceRuleVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PriceRuleVo.java new file mode 100644 index 0000000..8d30ebe --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PriceRuleVo.java @@ -0,0 +1,18 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 价格模版中的价格范围参数 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PriceRuleVo { + private int minPrice; + private int maxPrice; + private int adjustPercent; + private int adjustAmount; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningTaskVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningTaskVo.java new file mode 100644 index 0000000..03817b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningTaskVo.java @@ -0,0 +1,74 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.RunningTask; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 执行的任务视图对象 t_running_task + * + * @author yxy + * @date 2025-07-23 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = RunningTask.class) +public class RunningTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 任务id + */ + @ExcelProperty(value = "任务id") + private Long taskId; + + /** + * 任务名称 + */ + @ExcelProperty(value = "任务名称") + private String taskName; + + /** + * 优先级 + */ + @ExcelProperty(value = "优先级") + private Long priority; + + /** + * 内容json字符串 + */ + @ExcelProperty(value = "内容json字符串") + private String data; + + /** + * 状态 0 未执行 1 执行中 2 执行完成 + */ + @ExcelProperty(value = "状态 0 未执行 1 执行中 2 执行完成") + private String status; + + /** + * 任务执行完返回的数据 + */ + @ExcelProperty(value = "任务执行完返回的数据") + private String callBackData; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SaveGoodsVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SaveGoodsVo.java new file mode 100644 index 0000000..0a14cce --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SaveGoodsVo.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.domain.vo; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SaveGoodsVo { + + // 三级货区Id + private List freightIdList; + + // 保存商品规则:0-不修改直接保存货号 1-按照系统默认规则保存货号 + @NotNull(message = "保存商品规则不能为空") + private Integer saveArtNoRule; + + // 店铺Id + @NotNull(message = "店铺Id不能为空") + private Long shopId; + + // 任务Id + @NotNull(message = "任务Id不能为空") + private Long taskId; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopContextVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopContextVo.java new file mode 100644 index 0000000..f0acc4d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopContextVo.java @@ -0,0 +1,57 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.ShopContext; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 店铺设置商品描述视图对象 t_shop_context + * + * @author yxy + * @date 2025-09-30 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ShopContext.class) +public class ShopContextVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 店铺id + */ + @ExcelProperty(value = "店铺id") + private Long shopId; + + /** + * 商品描述 + */ + @ExcelProperty(value = "商品描述") + private String context; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopGoodsPublishedVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopGoodsPublishedVo.java new file mode 100644 index 0000000..36dafd0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopGoodsPublishedVo.java @@ -0,0 +1,131 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.ShopGoodsPublished; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 记录发布数据视图对象 t_shop_goods_published + * + * @author yxy + * @date 2025-04-11 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ShopGoodsPublished.class) +public class ShopGoodsPublishedVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 图书主键 + */ + @ExcelProperty(value = "图书主键") + private String shopGoodsId; + + private String goodsName; + /** + * 发布的店铺ids + */ + @ExcelProperty(value = "发布的店铺id") + private String shopId; + + private String shopName; + + /** + * 平台商品id + */ + @ExcelProperty(value = "平台商品id") + private String platformId; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + + /** + * 商品编码 + */ + private String itemNumber; + /** + * 书图片 + */ + private String bookPic = ""; + /** + * isbn + */ + private String isbn; + /** + * 品相 + */ + private String conditionCode; + /** + * 商品售价 + */ + private Long price; + /** + * 创建时间 + */ + private Date createTime; + + /** + * 修改时间 + */ + private Date updateTime; + + /** + * 线上商品数量 + */ + private Long inventory; + /** + * 线上商品 + */ + private String onlineProducts; + /** + * 供应商 + */ + private String supplier; + /** + * 创建人 + */ + private String createBy; + /** + * 线上商品id + */ + private Long onlineId; + /** + * 店铺类型 + */ + private Integer shopType; + + /** + * 三方店铺Id + */ + private Long mallId; + + /** + * 货号 + */ + private String artNo; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopImgVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopImgVo.java new file mode 100644 index 0000000..8bd0e83 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopImgVo.java @@ -0,0 +1,75 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.ShopImg; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 店铺图片视图对象 t_shop_img + * + * @author yxy + * @date 2025-03-17 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ShopImg.class) +public class ShopImgVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 父id + */ + @ExcelProperty(value = "父id") + private Long pid; + + /** + * 相对路径 + */ + @ExcelProperty(value = "相对路径") + private String relativePath; + + /** + * 绝对路径 + */ + @ExcelProperty(value = "绝对路径") + private String absolutePath; + + /** + * 类型 1封面水印 2商详水印 3 商详头图 4 商详尾图 5 轮播尾图 + */ + @ExcelProperty(value = "类型 1封面水印 2商详水印 3 商详头图 4 商详尾图 5 轮播尾图") + private String type; + + /** + * 图片顺序 + */ + @ExcelProperty(value = "图片顺序") + private Long imgOrder; + + /** + * 店铺状态(0正常 1停用) + */ + @ExcelProperty(value = "店铺状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TBookAuditVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TBookAuditVo.java new file mode 100644 index 0000000..12fab47 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TBookAuditVo.java @@ -0,0 +1,103 @@ +package org.dromara.zhishu.domain.vo; + +import jakarta.persistence.Column; +import org.dromara.zhishu.domain.TBookAudit; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 图书审核管理视图对象 t_book_audit + * + * @author Lion Li + * @date 2025-04-18 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TBookAudit.class) +public class TBookAuditVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 审核图书id + */ + @ExcelProperty(value = "审核图书id") + private Long id; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 产品编码 + */ + @ExcelProperty(value = "产品编码") + private String productId; + + /** + * 商品名称 + */ + @ExcelProperty(value = "商品名称") + private String goodsName; + + /** + * isbn + */ + @ExcelProperty(value = "isbn") + private String isbn; + + /** + * 货号 + */ + @ExcelProperty(value = "货号") + private String artNo; + + /** + * 标准售价 + */ + @ExcelProperty(value = "标准售价") + private Long price; + + /** + * 品相 + */ + @ExcelProperty(value = "品相") + private String conditionCode; + + /** + * 商品编号 + */ + @ExcelProperty(value = "商品编号") + private String itemNumber; + + /** + * 审核状态(0 通过 1 未通过 2 待审核) + */ + @ExcelProperty(value = "审核状态(0 通过 1 未通过 2 待审核)") + private String status; + + /** + * 库存 + */ + @ExcelProperty(value = "库存") + private Long inventory; + + /** + * 书图片 + */ + @ExcelProperty(value = "书图片") + private String bookPic; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TFreightVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TFreightVo.java new file mode 100644 index 0000000..b489ea7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TFreightVo.java @@ -0,0 +1,116 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.zhishu.domain.TFreight; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 三级货区管理视图对象 t_freight + * + * @author Lion Li + * @date 2025-04-19 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TFreight.class) +public class TFreightVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 货位id + */ + @ExcelProperty(value = "三级货区id") + private Long id; + + /** + * 货架id + */ +// @ExcelProperty(value = "货架id") + private Long shelvesId; + + /** + * 货位编码 + */ + @ExcelProperty(value = "货区编码") + private String code; + + /** + * 货位名称 + */ + @ExcelProperty(value = "三级货区名称") + private String name; + + + /** + * 货位单位 + */ +// @ExcelProperty(value = "货区单位") + private String unit; + + /** + * 货位容量 + */ +// @ExcelProperty(value = "货位容量") + private Long capMax; + + /** + * 货号 + */ +// @ExcelProperty(value = "货号") +// private String artNo; + + @ExcelProperty(value = "二级货区名称名称") + private String shelvesName; + + /** + * 仓库状态(0正常 1停用) + */ + @ExcelProperty(value = "货区状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 二级货区编码 + */ + private String shelvesCode; + + /** + * 完整code + */ + private String comcode; + + private Integer level; + + /** + * 书品数量 + */ + private Long sheNumber; + + /** + * 书品库存总数 + */ + private Long inventory; + + /** + * 书品分类数量 + */ + private Long categoryNumber; + + + /** + * 是否开启分销 0否 1是 + */ + private String allowDistribution; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopOrderVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopOrderVo.java new file mode 100644 index 0000000..8a6bd84 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopOrderVo.java @@ -0,0 +1,409 @@ +package org.dromara.zhishu.domain.vo; + +import com.baomidou.mybatisplus.annotation.TableLogic; +import org.dromara.zhishu.domain.TShopOrder; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + + +/** + * 订单视图对象 t_shop_order + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TShopOrder.class) +public class TShopOrderVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 订单Id + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 三方平台订单编号 + */ + private String orderSn; + + /** + * 订单来源类型 1-拼多多 2-孔夫子 + */ + private Integer orderSourceType; + + /** + * 订单异常类型集合(json字符串):inventoryException-库存异常 goodsSourceUnknownException-未知商品来源 + */ + private String orderExceptionType; + + /** + * 订单异常类型集合:inventoryException-库存异常 goodsSourceUnknownException-未知商品来源 + */ + private List orderExceptionTypeList; + + /** + * 店铺id + */ + private String shopId; + + /** + * 店铺名称 + */ + private String shopName; + + /** + * 地址 + */ + private String address; + + /** + * 详细地址 + */ + private String addressMask; + + /** + * 售后状态 0:无售后 2:买家申请退款,待商家处理 3:退货退款,待商家处理 4:商家同意退款,退款中 5:平台同意退款,退款中 6:驳回退款,待买家处理 7:已同意退货退款,待用户发货 8:平台处理中 9:平台拒绝退款,退款关闭 10:退款成功 11:买家撤销 12:买家逾期未处理,退款失败 13:买家逾期,超过有效期 14:换货补寄待商家处理 15:换货补寄待用户处理 16:换货补寄成功 17:换货补寄失败 18:换货补寄待用户确认完成 21:待商家同意维修 22:待用户确认发货 24:维修关闭 25:维修成功 27:待用户确认收货 31:已同意拒收退款,待用户拒收 32:补寄待商家发货 33:同意召回后退款,待商家召回 + */ + private Integer afterSalesStatus; + + /** + * 买家留言信息 + */ + private String buyerMemo; + + /** + * 成交状态:0:未成交、1:已成交、2:已取消 + */ + private Integer confirmStatus; + + /** + * 成交时间 + */ + private String confirmTime; + + /** + * 订单创建时间 + */ + private String createdTime; + + /** + * 是否当日发货,1-是,0-否 + */ + private String deliveryOneDay; + + /** + * 折扣金额,单位:元,折扣金额=平台优惠+商家优惠+团长免单优惠金额 + */ + private BigDecimal discountAmount; + + /** + * 多多支付立减金额,单位:元 + */ + private BigDecimal duoDuoPayReduction; + + /** + * 是否多多批发 + */ + private Integer duoduoWholesale; + + /** + * 商品金额 + */ + private BigDecimal goodsAmount; + + /** + * 仓库编码 + */ + private String depotCode; + + /** + * 仓库编码 + */ + private String orderDepotInfo; + + /** + * 仓库id + */ + private String depotId; + + /** + * 支付申报订单号 + */ + private String depotName; + + /** + * 仓库类型,1:自有仓 2:订阅仓 两者都不是则传空 + */ + private Integer depotType; + + /** + * 货品id + */ + private Long wareId; + + /** + * 货品名称 + */ + private String wareName; + + /** + * 货品编码 + */ + private String wareSn; + + /** + * 货品类型(0:普通货品:1:组合货品) + */ + private Integer wareType; + + /** + * 订单状态 + */ + private Integer orderStatus; + + /** + * 支付金额 + */ + private BigDecimal payAmount; + + /** + * 支付单号 + */ + private String payNo; + + /** + * 支付时间 + */ + private String payTime; + + /** + * 支付方式 + */ + private String payType; + + /** + * 平台优惠金额 + */ + private BigDecimal platformDiscount; + + /** + * 邮费 + */ + private BigDecimal postage; + + /** + * 预售时间 + */ + private String preSaleTime; + + /** + * 承诺送达时间 + */ + private String promiseDeliveryTime; + + /** + * 确认收货时间 + */ + private String receiveTime; + + /** + * 省份 + */ + private String province; + + /** + * 省份编码 + */ + private String provinceId; + + /** + * 市 + */ + private String city; + + /** + * 市编码 + */ + private String cityId; + + /** + * 区,乡镇 + */ + private String town; + + /** + * 区县编码 + */ + private String townId; + + /** + * 收件人地址 + */ + private String receiverAddress; + + /** + * 收件人地址 + */ + private String receiverAddressMask; + + /** + * 收件人姓名 + */ + private String receiverName; + + /** + * 收件人姓名 + */ + private String receiverNameMask; + + /** + * 确认收货时间 + */ + private String receiverPhone; + + /** + * 收件人手机号(打码) + */ + private String receiverPhoneMask; + + /** + * 售后状态 + */ + private Integer refundStatus; + + /** + * 订单备注 + */ + private String remark; + + /** + * 1-红色,2-黄色,3-绿色,4-蓝色,5-紫色 + */ + private String remarkTag; + + /** + * 订单备注标记名称 + */ + private String remarkTagName; + + /** + * 退货包运费,1:是,0:否 + */ + private Integer returnFreightPayer; + + /** + * 订单审核状态(0-正常订单, 1-审核中订单) + */ + private Integer riskControlStatus; + + /** + * 是否门店自提 + */ + private Integer selfContained; + + /** + * 商家优惠金额 + */ + private BigDecimal sellerDiscount; + + /** + * 缺货处理状态 -1:无缺货处理 0: 缺货待处理 1缺货已处理 + */ + private Integer stockOutHandleStatus; + + /** + * 全国联保,1:是,0:否 + */ + private Integer supportNationwideWarranty; + + /** + * 快递单号 + */ + private String trackingNumber; + + /** + * 以旧换新国家补贴金额,单位:元 + */ + private BigDecimal tradeInNationalSubsidyAmount; + + /** + * 订单类型 0-普通订单 ,1- 定金订单 + */ + private Integer tradeType; + + /** + * 订单的更新时间 + */ + private String updatedAt; + + /** + * 催发货时间 + */ + private String urgeShippingTime; + + /** + * 预约配送日期 + */ + private String yypsDate; + + /** + * 预约配送时段 + */ + private String yypsTime; + + /** + * 合单ID2 + */ + private String openAddressId2; + + /** + * 店铺状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 租户编码 + */ + @TableLogic + private String tenantId; + + /** + * 商品列表(JsonString) + */ + private String itemList; + + /** + * 商品列表 + */ + private List orderItemList; + + /** + * 额外附属信息 + */ + private String extraInfo; + + + private Boolean label; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UpdateBookVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UpdateBookVo.java new file mode 100644 index 0000000..84b4e7a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UpdateBookVo.java @@ -0,0 +1,41 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = UpdateBookVo.class) +public class UpdateBookVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @ExcelProperty(value = "书号(必填)") + private String bookNum; + + @ExcelProperty(value = "价格") + private String price; + + @ExcelProperty(value = "库存") + private String stock; + + @ExcelProperty(value = "商品编码") + private String code; + + @ExcelProperty(value = "书名") + private String bookName; + + @ExcelProperty(value = "规格编码") + private String artNo; + +// @ExcelProperty(value = "商品图片") +// private String bookImgUrl; + + private String logMsg; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserAccountVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserAccountVo.java new file mode 100644 index 0000000..0a742ea --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserAccountVo.java @@ -0,0 +1,75 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.UserAccount; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 账号管理视图对象 t_user_account + * + * @author yxy + * @date 2026-02-25 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = UserAccount.class) +public class UserAccountVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 出入帐账户类型 0 出账 1 入账 + */ + @ExcelProperty(value = "出入帐账户类型 0 出账 1 入账") + private String type; + + /** + * 账号类型 + */ + @ExcelProperty(value = "账号类型") + private String accountType; + + /** + * 账号名称 + */ + @ExcelProperty(value = "账号名称") + private String accountName; + + /** + * 账号 + */ + @ExcelProperty(value = "账号") + private String account; + + /** + * 是否默认账号 0 否 1 是 + */ + @ExcelProperty(value = "是否默认账号 0 否 1 是") + private String isDefault; + + /** + * 店铺状态(0正常 1停用) + */ + @ExcelProperty(value = "店铺状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserTAuditVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserTAuditVo.java new file mode 100644 index 0000000..66e59f9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserTAuditVo.java @@ -0,0 +1,143 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.UserTAudit; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 列表视图对象 t_audit + * + * @author Lion Li + * @date 2025-04-02 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = UserTAudit.class) +public class UserTAuditVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @ExcelProperty(value = "ID") + private Long id; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户ID") + private Long userId; + + /** + *用户昵称 + */ + @ExcelProperty(value = "用户昵称") + private String userName; + + /** + * 管理员ID + */ + @ExcelProperty(value = "管理员ID") + private Long adminId; + + /** + * 审核状态(0通过 1未通过) + */ + @ExcelProperty(value = "审核状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "审核状态(0通过 1未通过)") + private String status; + + /** + * 企业名称 + */ + @ExcelProperty(value = "企业名称") + private String companyName; + + /** + * 企业类型 + */ + @ExcelProperty(value = "企业类型") + private String companyType ; + + /** + * 联系人名 + */ + @ExcelProperty(value = "联系人名") + private String contactPerson; + + /** + * 联系方式 + */ + @ExcelProperty(value = "联系方式") + private String contactPhone;; + + /** + * 邮箱 + */ + @ExcelProperty(value = "邮箱") + private String email; + + /** + * 身份证图片 + */ + private String cardIdentity; + + + /** + * 营业执照名称 + */ + private String licenseName; + + /** + * 营业执照编号 + */ + private String licenseNumber; + + + /** + * 营业执照 + */ + @ExcelProperty(value = "营业执照") + private String license; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + /** + * 地址 + */ + private String adress; + + /** + * 经营许可证 + */ + private String businessLicense; + + /** + * 营业执照过期时间 + */ + private String licenseTime; + + + /** + * 经营许可证过期时间 + */ + + private String businessLicenseTime; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WarehouseSettingsVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WarehouseSettingsVo.java new file mode 100644 index 0000000..041e7fc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WarehouseSettingsVo.java @@ -0,0 +1,117 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.WarehouseSettings; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + + + +/** + * 设置视图对象 warehouse_settings + * + * @author yxy + * @date 2025-12-19 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = WarehouseSettings.class) +public class WarehouseSettingsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 设置模板名称 + */ + @ExcelProperty(value = "设置模板名称") + private String settingName; + + /** + * 库存同步形式 0 下单减库存 1 支付减库存 + */ + @ExcelProperty(value = "库存同步形式 0 下单减库存 1 支付减库存") + private Long stockSynchronizeType; + + /** + * 是否自动下发 0 否 1 是 + */ + @ExcelProperty(value = "是否自动下发 0 否 1 是") + private Long autoIssue; + + /** + * 是否开启亏损保护 0 否 1 是 + */ + private Long lossProtection; + + /** + * 利润下限 + */ + private BigDecimal profitFloor; + + /** + * 是否启用 0 否 1 是 + */ + @ExcelProperty(value = "是否启用 0 否 1 是") + private Long status; + + /** + * 是否删除 0 否 1 是 + */ + @ExcelProperty(value = "是否删除 0 否 1 是") + private Long delFlag; + + /** + * 退款后是否自动回退库存 0否 1是 + */ + @ExcelProperty(value = "退款后是否自动回退库存 0否 1是") + private Long stockRollback; + + /** + * 创建人id + */ + @ExcelProperty(value = "创建人id") + private Long createBy; + + /** + * 创建时间时间戳 + */ + @ExcelProperty(value = "创建时间时间戳") + private Long createAt; + + /** + * 修改人id + */ + @ExcelProperty(value = "修改人id") + private Long updateBy; + + /** + * 修改时间时间戳 + */ + @ExcelProperty(value = "修改时间时间戳") + private Long updateAt; + + /** + * 店铺id + */ + private String shopIds; + + /** + * 规则数据 + */ + private String userSettingsAttributeListStr; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/XyBindVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/XyBindVo.java new file mode 100644 index 0000000..75d84b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/XyBindVo.java @@ -0,0 +1,44 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.baomidou.mybatisplus.annotation.TableLogic; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.zhishu.domain.XyBind; + +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = XyBind.class) +public class XyBindVo implements Serializable { + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 闲管家名称 + */ + private String appName; + + /** + * 闲管家应用id + */ + private Long mallId; + + /** + * 闲管家应用密钥 + */ + private String token; + + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopImagesVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopImagesVo.java new file mode 100644 index 0000000..8e5d953 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopImagesVo.java @@ -0,0 +1,48 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.zhishu.domain.ZhishuShopImages; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 商品图片视图对象 zhishu_shop_images + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ZhishuShopImages.class) +public class ZhishuShopImagesVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private String id; + + /** + * 商品ID + */ + @ExcelProperty(value = "商品ID") + private String goodsId; + + /** + * 存放路径 + */ + @ExcelProperty(value = "存放路径") + private String path; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/BookParamsEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/BookParamsEnum.java new file mode 100644 index 0000000..225b078 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/BookParamsEnum.java @@ -0,0 +1,53 @@ +package org.dromara.zhishu.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +/* + 转换 图书api的字段 + */ + +@Getter +@AllArgsConstructor +public enum BookParamsEnum { + + ISBN("isbn", "isbn"), + + BOOK_NAME("bookName", "书名"), + + AUTHOR("author", "作者"), + + PRESS("press", "出版社"), + + PRESS_DATE("pressDate", "出版日期"), + + + PRICE("price", "价格(单位:分)"), + + PRESS_PLACE("pressPlace", "出版地"), + + PICTURES("pictures", "图片"), + + BOOK_DESC("bookDesc", "描述"), + + + BINDING("binding", "装订方式"), + + LANGUAGE("language", "语言"), + + FORMAT("format", "开本"), + + PAGES("pages", "页数"), + + EDITION("edition", "版次"), + + WORDS("words", "字数"); + + private final String params; + + /** + * SpEL 模板表达式,用于构建 SQL 查询条件 + */ + private final String name; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/IsQueryAllGoodsEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/IsQueryAllGoodsEnum.java new file mode 100644 index 0000000..db22d82 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/IsQueryAllGoodsEnum.java @@ -0,0 +1,45 @@ +package org.dromara.zhishu.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@AllArgsConstructor +public enum IsQueryAllGoodsEnum { + + YES(2, "是"), + + NO(1, "否"); + + /** + * code + */ + private final Integer code; + + /** + * message + */ + private final String msg; + + public static List getIsQueryAllGoodsEnumList() { + List isQueryAllGoodsEnumList = new ArrayList<>(); + for (IsQueryAllGoodsEnum item : values()) { + isQueryAllGoodsEnumList.add(item.getCode()); + } + return isQueryAllGoodsEnumList; + } + + public static IsQueryAllGoodsEnum valueOfCode(Integer code) { + for (IsQueryAllGoodsEnum type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + throw new ServiceException("未知操作库存类型code: " + code); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/MunicipalityEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/MunicipalityEnum.java new file mode 100644 index 0000000..ee84ab4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/MunicipalityEnum.java @@ -0,0 +1,36 @@ +package org.dromara.zhishu.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 直辖市区划枚举 + */ +@Getter +@AllArgsConstructor +public enum MunicipalityEnum { + + BEIJING(3216L, "110010", "北京"), + + SHANGHAI(3218L, "500010", "上海"), + + TIANJIN(3217L, "500010", "天津"), + + CHONGQING(3219L, "500010", "重庆"); + + /** + * 区划ID + */ + private final Long id; + + /** + * 区划编码 + */ + private final String code; + + /** + * 区划名称 + */ + private final String name; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OrderExceptionTypeEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OrderExceptionTypeEnum.java new file mode 100644 index 0000000..fd930e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OrderExceptionTypeEnum.java @@ -0,0 +1,48 @@ +package org.dromara.zhishu.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.exception.ServiceException; + +import java.util.ArrayList; +import java.util.List; + +/** + * 订单异常类型枚举 + */ +@Getter +@AllArgsConstructor +public enum OrderExceptionTypeEnum { + + INVENTORY_EXCEPTION("inventoryException", "库存异常"), + + GOODS_SOURCE_UNKNOWN_EXCEPTION("goodsSourceUnknownException", "未知商品来源"); + + /** + * code + */ + private final String code; + + /** + * message + */ + private final String msg; + + public static List getOrderExceptionTypeEnumList() { + List orderExceptionTypeEnumList = new ArrayList<>(); + for (OrderExceptionTypeEnum item : values()) { + orderExceptionTypeEnumList.add(item.getCode()); + } + return orderExceptionTypeEnumList; + } + + public static OrderExceptionTypeEnum valueOfCode(String code) { + for (OrderExceptionTypeEnum type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + throw new ServiceException("未知操作库存类型code: " + code); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddResCodeEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddResCodeEnum.java new file mode 100644 index 0000000..9ca5b3d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddResCodeEnum.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.enums; + +/* + 转换 图书api的字段 + */ + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum PddResCodeEnum { + + HAS_NEXT("has_next","是否有下一页"), + + ORDER_OK("order_info_get_response","详情正常回调"), + + ORDER_LIST_OK("order_list_get_response","详情正常回调"), + + ERR("error_response","错误请求"), + ORDER_LIST("order_list","列表正常回调返参"), + + ORDER_SN_INCREMENT_GET_RESPONSE("order_sn_increment_get_response","订单增量回调"), + ORDER_SN_LIST("order_sn_list","订单增量回调返参"); + + private final String code; + private final String message; + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ArtNoMoveMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ArtNoMoveMapper.java new file mode 100644 index 0000000..baae69e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ArtNoMoveMapper.java @@ -0,0 +1,8 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.ArtNoMove; +import org.dromara.zhishu.domain.vo.ArtNoMoveVo; + +public interface ArtNoMoveMapper extends BaseMapperPlus { +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/EmployeeMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/EmployeeMapper.java new file mode 100644 index 0000000..f3a7a7e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/EmployeeMapper.java @@ -0,0 +1,22 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.vo.EmployeeVo; +import java.util.List; + +@Mapper +public interface EmployeeMapper { + + @InterceptorIgnore(tenantLine = "true") + List getEmployeeInfo(String userId); + + @InterceptorIgnore(tenantLine = "true") + int addEmployee(EmployeeVo employeeVo ); + + @InterceptorIgnore(tenantLine = "true") + int updateEmployee(EmployeeVo employeeVo); + + @InterceptorIgnore(tenantLine = "true") + int delEmployee(String id, Long userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PriceTemplateMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PriceTemplateMapper.java new file mode 100644 index 0000000..a1b5936 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PriceTemplateMapper.java @@ -0,0 +1,32 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.zhishu.domain.PriceTemplate; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.vo.PriceTemplateVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.vo.TaskVo; + +/** + * 价格模板Mapper接口 + * + * @author yxy + * @date 2025-03-17 + */ +@Mapper +public interface PriceTemplateMapper extends BaseMapperPlus { + + @Override + @DataPermission({ + @DataColumn(key = "userName", value = "create_by") + }) + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + PriceTemplate priceByPlatformId(String platformId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PrinterMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PrinterMapper.java new file mode 100644 index 0000000..fcc0fbb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PrinterMapper.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.Printer; +import org.dromara.zhishu.domain.vo.PrinterVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 打印机设置Mapper接口 + * + * @author yxy + * @date 2026-03-06 + */ +public interface PrinterMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopContextMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopContextMapper.java new file mode 100644 index 0000000..ae7c481 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopContextMapper.java @@ -0,0 +1,17 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.ShopContext; +import org.dromara.zhishu.domain.vo.ShopContextVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 店铺设置商品描述Mapper接口 + * + * @author yxy + * @date 2025-09-30 + */ +public interface ShopContextMapper extends BaseMapperPlus { + + + ShopContextVo selectByShopId(Long shopId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodIsbnMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodIsbnMapper.java new file mode 100644 index 0000000..1a8c4ab --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodIsbnMapper.java @@ -0,0 +1,11 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.ShopGoodIsbn; +import org.dromara.zhishu.domain.vo.ShopGoodIsbnVo; +@Mapper +public interface ShopGoodIsbnMapper extends BaseMapperPlus { + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopMapper.java new file mode 100644 index 0000000..e39d867 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopMapper.java @@ -0,0 +1,91 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.zhishu.domain.vo.PriceTemplateVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 店铺主表Mapper接口 + * + * @author yxy + * @date 2025-03-10 + */ +@Mapper +public interface ShopMapper extends BaseMapperPlus { + + @Override + @DataPermission({ + @DataColumn(key = "userName", value = "create_by") + }) + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + default

> P selectVoPage2(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + @Override + @DataPermission({ + @DataColumn(key = "userName", value = "create_by") + }) + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + + + + + ShopVo selectByMallId(String mallId); + + List selectListByMallId(Long mallId); + + /** + * 根据id查询一样的mallId数据 + * @param id + * @return + */ + List selectMallIdsById(Long id); + + ShopVo selectByToken(String token); + + ShopVo selectByShopName(String shopName); + + List selectByAccount(String account); + + List getShopIdByCreateBy(Long createBy); + + List getShopIdByUserId(Long userId); + + List getShopListByType(String type, Long userId); + + List getShopIdByUserIdAndExpirationTime(Long userId); + + List selectCorrelationByUserId(Long userId); + + List selectShopName(List idList); + + PriceTemplateVo selectByName(Long shopId); + + Shop selectShopByPddMallId(String pddMallId); + + int updateShopSkuSpec(String id, String skuSpec); + + ShopVo selectBygoofishShopName(String shopKey); + + Boolean checkIsExist(String shopKey); + + List selectByUserId(Long account); + + List selectByIds(List ids); +} + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/StockChangeLogMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/StockChangeLogMapper.java new file mode 100644 index 0000000..949bef9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/StockChangeLogMapper.java @@ -0,0 +1,17 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.StockChangeLog; +import org.dromara.zhishu.domain.vo.StockChangeLogVo; + +import java.util.List; + +@Mapper +public interface StockChangeLogMapper extends BaseMapperPlus { + + List selectByShopGoodsIdAndCreateBy( + @Param("shopGoodsId") String shopGoodsId, + @Param("aboutId") String aboutId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/SyncLogMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/SyncLogMapper.java new file mode 100644 index 0000000..9eb6173 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/SyncLogMapper.java @@ -0,0 +1,47 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.SyncLog; + +import java.util.List; + +/** + * 迁移日志Mapper接口 + * + * @author yxy + * @date 2026-06-06 + */ +@Mapper +public interface SyncLogMapper { + + /** + * 根据ID查询迁移日志 + */ + @InterceptorIgnore(tenantLine = "true") + SyncLog selectById(Long id); + + /** + * 查询迁移日志列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectList(SyncLog syncLog); + + /** + * 新增迁移日志 + */ + @InterceptorIgnore(tenantLine = "true") + int insert(SyncLog syncLog); + + /** + * 更新迁移日志 + */ + @InterceptorIgnore(tenantLine = "true") + int update(SyncLog syncLog); + + /** + * 根据ID删除迁移日志 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteById(Long id); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TBookAuditMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TBookAuditMapper.java new file mode 100644 index 0000000..d1150b2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TBookAuditMapper.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.mapper; + + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TBookAudit; +import org.dromara.zhishu.domain.vo.TBookAuditVo; + +/** + * 图书审核管理Mapper接口 + * + * @author Lion Li + * @date 2025-04-18 + */ +@Mapper +public interface TBookAuditMapper extends BaseMapperPlus { + + TBookAudit selectGoods(Long id); + + Integer insertGoods(TBookAudit tBookAudit); + + void updateInventory(long newInventory, Long userId, String letterCode, String artNo, long price, String barcode); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TDepotMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TDepotMapper.java new file mode 100644 index 0000000..c9bc687 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TDepotMapper.java @@ -0,0 +1,96 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TDepot; +import org.dromara.zhishu.domain.bo.TDepotBo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TFreightVo; +import org.dromara.zhishu.domain.vo.TShelvesVo; + +import java.util.Collection; +import java.util.List; + +/** + * 仓库信息设置Mapper接口 + * + * @author Lion Li + * @date 2025-03-26 + */ +@Mapper +public interface TDepotMapper extends BaseMapperPlus { + + + String selectByName(Long userId); + + + List selectByShe(Long id); + + + void insertbatchFre(String s, List numbers1); + + + void deleteByIdShe(Collection ids); + + + void deleteByIdFre(Collection sheList); + + + void insertbatch(Long id, Long sheQuantityMax, List numbers); + + List nameList(Long userId,String phoneNumber,String status); + + + Integer selectByUser(Long userId, String code,String depotName); + + List selectByids(Collection ids); + + String selectByDCode(Long depotId,Long userId);//查询仓库code + + TDepotVo selectDepotByCode(String artNo); + +// @InterceptorIgnore(tenantLine = "true", dataPermission = "false") + String selectByCode(Long userId,Long depotId); + + Integer selectIsbn(String part); + + Integer insertIsbn(Long isbn, String newisbn); + + Integer selectByNewIsbn(long oldisbn, String newisbn); + + + + List querySheNameList(String depotId); + + List queryFreNameList(String sheId); + + Page selectVo1(Page build,@Param("bo") TDepotBo bo); + + List selectV(Long userId); + +// List selectByCodes(Long userId, Collection ids); + +// Integer selectCounts(Long userId, List codeList); + + Long selectSheCount(Long id); + + List selectSheList(Long id); + +// Integer selectFreCount(Long id); + + List selectFreList(Long id); + + String selectTemName(Long templateId); + +// Long selectGoodsCount(String artNo, Long userId); + + Integer selectCount(Long userId, Collection ids); + + List selectDepotIdByUserIdAndCode(Long userId, String code); + + List selectArtNoLists(Long userId); + + Integer selectByUserAndExcludeCurrent(@Param("userId") Long userId, @Param("name") String name, @Param("excludeId") Long excludeId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TDistrictMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TDistrictMapper.java new file mode 100644 index 0000000..b7ae5b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TDistrictMapper.java @@ -0,0 +1,25 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TDistrict; +import org.dromara.zhishu.domain.bo.TDistrictBo; +import org.dromara.zhishu.domain.vo.TDistrictVo; + +import java.util.List; + +@Mapper +public interface TDistrictMapper extends BaseMapperPlus { + + + List selectDistrictList(); + + List selectDistrictByPid(String pid); + + List selectCityList(TDistrictVo vo); + + List selectAreaList(TDistrictVo vo); + + List selectMunicipalityAreaList(@Param("municipalityIdList") List municipalityIdList); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopDepotAotuMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopDepotAotuMapper.java new file mode 100644 index 0000000..8df49df --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopDepotAotuMapper.java @@ -0,0 +1,58 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.TShopDepotAotu; +import org.dromara.zhishu.domain.bo.TShopDepotAotuBo; +import org.dromara.zhishu.domain.vo.TShopDepotAotuVo; + +import java.util.List; + +/** + * 店铺自动发布仓库关联Mapper接口 + */ +@Mapper +public interface TShopDepotAotuMapper extends BaseMapper { + + /** + * 根据ID查询详情 + */ + TShopDepotAotuVo selectVoById(@Param("id") Long id); + + /** + * 使用原生SQL分页查询 + */ + Page selectVoPageBySql(@Param("page") Page page, @Param("sql") String sql, @Param("params") Object[] params); + + /** + * 使用原生SQL列表查询 + */ + List selectVoListBySql(@Param("sql") String sql, @Param("params") Object[] params); + + /** + * 根据条件查询分页列表 + * + * @param page 分页参数 + * @param bo 查询条件 + * @return 分页结果 + */ + Page selectVoPageByCondition(@Param("page") Page page, @Param("bo") TShopDepotAotuBo bo); + + /** + * 根据条件查询列表 + * + * @param bo 查询条件 + * @return 结果列表 + */ + List selectVoListByCondition(@Param("bo") TShopDepotAotuBo bo); + + /** + * 校验仓库和店铺自动发布 + * @param shopId 店铺id + * @param depotId 仓库id + * @return 结果列表 + */ + List selectByShopIdAndDepotId(@Param("shopId") String shopId, @Param("depotId") Long depotId); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopGoodsPublishedMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopGoodsPublishedMapper.java new file mode 100644 index 0000000..007f4f9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopGoodsPublishedMapper.java @@ -0,0 +1,188 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.dto.TShopGoodsPublishedDto; + +import java.util.List; + +/** + * 已发布商品信息Mapper接口 + */ +@Mapper +public interface TShopGoodsPublishedMapper { + + // ==================== 表管理 ==================== + + /** + * 检查表是否存在 + * + * @return 存在数量 + */ + @InterceptorIgnore(tenantLine = "true") + int checkTableExists(); + + /** + * 创建表 + */ + @InterceptorIgnore(tenantLine = "true") + void createTable(); + + // ==================== 插入操作 ==================== + + /** + * 插入单条数据 + * + * @param dto 已发布商品信息 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int insert(@Param("dto") TShopGoodsPublishedDto dto); + + /** + * 批量插入 + * + * @param list 已发布商品列表 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int batchInsert(@Param("list") List list); + + // ==================== 删除操作 ==================== + + /** + * 根据ID删除 + * + * @param id 主键ID + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteById(@Param("id") Long id); + + /** + * 根据条件删除 + * + * @param erpShopId erp店铺id + * @param shopId 平台店铺id + * @param productId 商品id + * @param warehouseId 仓库id + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteByCondition(@Param("erpShopId") Long erpShopId, + @Param("shopId") Long shopId, + @Param("productId") Long productId, + @Param("warehouseId") Long warehouseId); + + /** + * 批量删除 + * + * @param ids ID列表 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int batchDeleteByIds(@Param("ids") List ids); + + /** + * 删除所有数据 + * + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteAll(); + + // ==================== 更新操作 ==================== + + /** + * 根据ID更新 + * + * @param dto 已发布商品信息 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int updateById(@Param("dto") TShopGoodsPublishedDto dto); + + // ==================== 查询操作 ==================== + + /** + * 根据ID查询 + * + * @param id 主键ID + * @return 已发布商品信息 + */ + @InterceptorIgnore(tenantLine = "true") + TShopGoodsPublishedDto selectById(@Param("id") Long id); + + /** + * 根据ERP店铺ID查询列表 + * + * @param erpShopId erp店铺id + * @return 已发布商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByErpShopId(@Param("erpShopId") Long erpShopId); + + /** + * 根据平台店铺ID查询列表 + * + * @param shopId 平台店铺id + * @return 已发布商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByShopId(@Param("shopId") Long shopId); + + /** + * 根据商品ID查询 + * + * @param productId 商品id + * @return 已发布商品信息 + */ + @InterceptorIgnore(tenantLine = "true") + TShopGoodsPublishedDto selectByProductId(@Param("productId") Long productId); + + /** + * 分页条件查询 + * + * @param dto 查询条件(包含分页参数) + * @return 已发布商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByCondition(@Param("dto") TShopGoodsPublishedDto dto); + + /** + * 条件查询总数 + * + * @param dto 查询条件 + * @return 总数 + */ + @InterceptorIgnore(tenantLine = "true") + int selectCountByCondition(@Param("dto") TShopGoodsPublishedDto dto); + + /** + * 查询所有 + * + * @return 已发布商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectAll(); + + /** + * 统计总记录数 + * + * @return 总记录数 + */ + @InterceptorIgnore(tenantLine = "true") + int countAll(); + + /** + * 根据ERP店铺ID和商品ID查询 + * + * @param erpShopId erp店铺id + * @param productId 商品id + * @return 已发布商品信息 + */ + @InterceptorIgnore(tenantLine = "true") + TShopGoodsPublishedDto selectByErpShopIdAndProductId(@Param("erpShopId") Long erpShopId, + @Param("productId") Long productId); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopMessageSubscribeMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopMessageSubscribeMapper.java new file mode 100644 index 0000000..a285442 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopMessageSubscribeMapper.java @@ -0,0 +1,10 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.TShopMessageSubscribe; + +@Mapper +public interface TShopMessageSubscribeMapper extends BaseMapper { + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopOrderDetailMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopOrderDetailMapper.java new file mode 100644 index 0000000..acba38d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopOrderDetailMapper.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.TShopOrderDetail; +import org.dromara.zhishu.domain.vo.TShopOrderDetailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 订单详情Mapper接口 + * + * @author Lion Li + * @date 2025-03-13 + */ +@Mapper +public interface TShopOrderDetailMapper extends BaseMapperPlus { + + Page customPageList(@Param("page") Page page, LambdaQueryWrapper lqw); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopOrderMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopOrderMapper.java new file mode 100644 index 0000000..46c1a03 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShopOrderMapper.java @@ -0,0 +1,32 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.zhishu.domain.TShopOrder; +import org.dromara.zhishu.domain.bo.TShopOrderBo; +import org.dromara.zhishu.domain.vo.TShopOrderVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 订单Mapper接口 + * + * @author Lion Li + * @date 2025-03-13 + */ +@Mapper +public interface TShopOrderMapper extends BaseMapperPlus { + + + Page customPageList(@Param("page") Page page,@Param("request") LambdaQueryWrapper lqw); + + Page queryOrderList(Page build,@Param("bo") TShopOrderBo bo); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TUserPlatformMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TUserPlatformMapper.java new file mode 100644 index 0000000..e7ab90b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TUserPlatformMapper.java @@ -0,0 +1,18 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.dromara.zhishu.domain.TUserPlatform; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface TUserPlatformMapper extends BaseMapper { + /** + * 根据平台ID查询用户平台关联 + * + * @param platformId 平台ID + * @return 用户平台关联信息 + */ + TUserPlatform selectByPlatformId(String platformId); + + void insertTUserPlatform(TUserPlatform userPlatform); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TaskPauseMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TaskPauseMapper.java new file mode 100644 index 0000000..3c7b4ab --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TaskPauseMapper.java @@ -0,0 +1,20 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.TaskPause; + +/** + * 暂停任务表 + * + * @author yxy + * @date 2025-11-13 + */ +public interface TaskPauseMapper { + + @InterceptorIgnore(tenantLine = "true") + int insert(TaskPause taskPause); + + @InterceptorIgnore(tenantLine = "true") + int deleteByTaskId(Long taskId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserAccountMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserAccountMapper.java new file mode 100644 index 0000000..f3e84a9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserAccountMapper.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.UserAccount; +import org.dromara.zhishu.domain.vo.UserAccountVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 账号管理Mapper接口 + * + * @author yxy + * @date 2026-02-25 + */ +public interface UserAccountMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WaveDetailMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WaveDetailMapper.java new file mode 100644 index 0000000..737b43e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WaveDetailMapper.java @@ -0,0 +1,94 @@ +package org.dromara.zhishu.mapper; + + +import org.apache.ibatis.annotations.MapKey; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.WaveDetail; +import org.dromara.zhishu.domain.vo.EmployeeInfoVo; + +import java.util.List; +import java.util.Map; + +/** + * 波次信息Mapper接口 + * + * @author Lion Li + * @date 2026-01-22 + */ +@Mapper +public interface WaveDetailMapper { + + /** + * 批量插入波次信息 + * + * @param list 波次信息列表 + * @return 插入数量 + */ + int insertBatch(@Param("list") List list); + + Long getFreightId(@Param("create_by")String create_by, @Param("deportCode") String deportCode, @Param("shelvesCode") String shelvesCode, @Param("freightCode") String freightCode); + + Integer getIsJoinDistribution(@Param("create_by")String create_by, @Param("deportCode") String deportCode, @Param("shelvesCode") String shelvesCode, @Param("freightCode") String freightCode); + + Long getWaveId(); + + String getEmployeeId(@Param("name")String name, @Param("userId")String userId); + + int insertEmployeeInfo(@Param("employeeInfo")EmployeeInfoVo employeeInfo); + + /** + * 从employeeInfo表统计count的和 + * @param userId 所属用户id + * @param wave 工作波次 + * @return count的和 + */ + Long getEmployeeInfoCountSum(@Param("userId")String userId, @Param("wave")String wave); + + /** + * 从wave_employee表查询员工id + * @param userId 所属用户id + * @param name 员工姓名 + * @return 员工id + */ + String getWaveEmployeeId(@Param("userId")String userId, @Param("name")String name); + + /** + * 从wave_employee表查询员工姓名 + * @param employeeId 所属用户id + * @return 员工姓名 + */ + @MapKey("name") + Map getWaveEmployeeName(@Param("employeeId")String employeeId); + + /** + * 检查wave表中是否存在记录 + * @param staffId 人员ID + * @param belongAccountId 所属账号 + * @return 存在返回1,不存在返回0 + */ + int checkWaveExists(@Param("staffId")String staffId, @Param("belongAccountId")String belongAccountId); + + /** + * 更新wave表记录 + * @param staffId 人员ID + * @param belongAccountId 所属账号 + * @param count 数量 + * @param updatedTime 更新时间 + * @return 更新影响行数 + */ + int updateWaveCount(@Param("staffId")String staffId, @Param("belongAccountId")String belongAccountId, @Param("count")Long count, @Param("updatedTime")Long updatedTime); + + /** + * 插入wave表记录 + * @param staffId 人员ID + * @param staffName 人员姓名 + * @param belongAccountId 所属账号 + * @param count 数量 + * @param createdTime 创建时间 + * @param updatedTime 更新时间 + * @return 插入影响行数 + */ + int insertWave(@Param("staffId")String staffId, @Param("staffName")String staffName, @Param("belongAccountId")String belongAccountId, @Param("count")Long count, @Param("createdTime")Long createdTime, @Param("updatedTime")Long updatedTime); +} + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/XyCategoryMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/XyCategoryMapper.java new file mode 100644 index 0000000..2a31b3b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/XyCategoryMapper.java @@ -0,0 +1,17 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.vo.XyCategoryVo; + +import java.util.List; + +@Mapper +public interface XyCategoryMapper { + /** + * 查询类目列表 + * + * @return 类目列表 + */ + List selectXyCategoryList(); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopImagesMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopImagesMapper.java new file mode 100644 index 0000000..ce0b8c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopImagesMapper.java @@ -0,0 +1,29 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.MapKey; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.ZhishuShopImages; +import org.dromara.zhishu.domain.vo.ZhishuShopImagesVo; + +import java.util.List; +import java.util.Map; + +/** + * 商品图片Mapper接口 + * + * @author Lion Li + * @date 2025-03-13 + */ +@Mapper +public interface ZhishuShopImagesMapper extends BaseMapperPlus { + + + + List selectShopImagesByShopId(String goodsId); + @MapKey("shopId") + List> batchQueryFirstPathByGoodsIds(List goodsIds); +// @MapKey("shopId") +// Map batchQueryFirstPathByGoodsIds(@Param("goodsIds") List goodsIds); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/scheduled/PddOrderIncrementJob.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/scheduled/PddOrderIncrementJob.java new file mode 100644 index 0000000..d2c6296 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/scheduled/PddOrderIncrementJob.java @@ -0,0 +1,79 @@ +package org.dromara.zhishu.scheduled; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import jakarta.annotation.Resource; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.domain.TShopOrder; +import org.dromara.zhishu.domain.dto.PddOrderIncrementQuery; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.mapper.TShopOrderMapper; +import org.dromara.zhishu.service.PddRequestService; +import org.dromara.zhishu.util.PddRequestUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Queue; + + +@Component +public class PddOrderIncrementJob { + + @Resource + ShopMapper shopMapper; + @Resource + PddRequestService pddRequestService; + +// @Value("${pdd.app.clientId}") +// private String clientId; +// +// @Value("${pdd.app.clientSecret}") +// private String clientSecret; + + + //todo 第一次新增店铺的 需要写一个从授权到最后的整个时间 +// @Scheduled(cron="*/5 * * * * *") + public void increment() { + + List shopList = shopMapper.selectList(null); + + //先查询上次的更新时间 + + for (Shop shop : shopList) { + + PddOrderIncrementQuery pddOrderIncrementQuery = new PddOrderIncrementQuery(); + + pddOrderIncrementQuery.setAccess_token(shop.getToken()); + + pddOrderIncrementQuery.setPage(1); + //发货状态,1-待发货,2-已发货待签收,3-已签收,5-全部 + pddOrderIncrementQuery.setOrder_status(5); + //订单类型(是否抽奖订单),0-全部,1-非抽奖订单,2-抽奖订单 + pddOrderIncrementQuery.setIs_lucky_flag(0); + // 售后状态,1-无售后或售后关闭,2-售后处理中,3-退款中,4-退款成功 5-全部 + pddOrderIncrementQuery.setRefund_status(5); + pddOrderIncrementQuery.setUse_has_next(true); + + long start_updated_at = shop.getStartUpdatedAt(); + long end_updated_at = start_updated_at + 3; + + pddOrderIncrementQuery.setEnd_updated_at(end_updated_at); + pddOrderIncrementQuery.setStart_updated_at(start_updated_at); + // todo 写成异步的 + pddRequestService.getIncrementRequest(pddOrderIncrementQuery); + //修改店铺的下一次更新订单时间 + shop.setStartUpdatedAt(end_updated_at); + shopMapper.updateById(shop); + + } + + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IDepotOrderService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IDepotOrderService.java new file mode 100644 index 0000000..6b13baa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IDepotOrderService.java @@ -0,0 +1,71 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.DepotOrderVo; +import org.dromara.zhishu.domain.bo.DepotOrderBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 仓库订单信息Service接口 + * + * @author yxy + * @date 2025-06-03 + */ +public interface IDepotOrderService { + + /** + * 查询仓库订单信息 + * + * @param id 主键 + * @return 仓库订单信息 + */ + DepotOrderVo queryById(Long id); + + /** + * 分页查询仓库订单信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 仓库订单信息分页列表 + */ + TableDataInfo queryPageList(DepotOrderBo bo, PageQuery pageQuery); + + + DepotOrderVo selectDepotOrderById(String id); + + /** + * 查询符合条件的仓库订单信息列表 + * + * @param bo 查询条件 + * @return 仓库订单信息列表 + */ + List queryList(DepotOrderBo bo); + + /** + * 新增仓库订单信息 + * + * @param bo 仓库订单信息 + * @return 是否新增成功 + */ + Boolean insertByBo(DepotOrderBo bo); + + /** + * 修改仓库订单信息 + * + * @param bo 仓库订单信息 + * @return 是否修改成功 + */ + Boolean updateByBo(DepotOrderBo bo); + + /** + * 校验并批量删除仓库订单信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IExcelTaskService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IExcelTaskService.java new file mode 100644 index 0000000..1381ef1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IExcelTaskService.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.bo.ExcelTaskBo; +import org.dromara.zhishu.domain.vo.ExcelTaskVo; + +import java.util.Collection; +import java.util.List; + +/** + * 任务列表Service接口 + * + * @author yxy + * @date 2025-03-21 + */ +public interface IExcelTaskService { + + /** + * 查询任务列表 + * + * @param id 主键 + * @return 任务列表 + */ + ExcelTaskVo queryById(Long id); + + /** + * 分页查询任务列表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 任务列表分页列表 + */ + TableDataInfo queryPageList(ExcelTaskBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的任务列表列表 + * + * @param bo 查询条件 + * @return 任务列表列表 + */ + List queryList(ExcelTaskBo bo); + + /** + * 新增任务列表 + * + * @param bo 任务列表 + * @return 是否新增成功 + */ + Boolean insertByBo(ExcelTaskBo bo); + + /** + * 修改任务列表 + * + * @param bo 任务列表 + * @return 是否修改成功 + */ + Boolean updateByBo(ExcelTaskBo bo); + + /** + * 校验并批量删除任务列表信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IFastMailService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IFastMailService.java new file mode 100644 index 0000000..e2f7233 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IFastMailService.java @@ -0,0 +1,82 @@ +package org.dromara.zhishu.service; + +import org.apache.ibatis.annotations.Param; +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.vo.FastMailVo; +import org.dromara.zhishu.domain.bo.FastMailBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 快递打单账号管理Service接口 + * + * @author yxy + * @date 2025-06-06 + */ +public interface IFastMailService { + + /** + * 查询快递打单账号管理 + * + * @param id 主键 + * @return 快递打单账号管理 + */ + FastMailVo queryById(Long id); + + FastMailVo selectByUserIdAndType(String userId,String type); + + /** + * 分页查询快递打单账号管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 快递打单账号管理分页列表 + */ + TableDataInfo queryPageList(FastMailBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的快递打单账号管理列表 + * + * @param bo 查询条件 + * @return 快递打单账号管理列表 + */ + List queryList(FastMailBo bo); + + + List queryListApi(Long userId); + + /** + * 新增快递打单账号管理 + * + * @param bo 快递打单账号管理 + * @return 是否新增成功 + */ + R insertByBo(FastMailBo bo); + + /** + * 修改快递打单账号管理 + * + * @param bo 快递打单账号管理 + * @return 是否修改成功 + */ + R updateByBo(FastMailBo bo); + + /** + * 校验并批量删除快递打单账号管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据面单类型删除数据 + * @param fastMailType + * @return + */ + int deleteByFastMailType(Long userId,String fastMailType); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IGoodsAutoFailService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IGoodsAutoFailService.java new file mode 100644 index 0000000..042bf1d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IGoodsAutoFailService.java @@ -0,0 +1,75 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.GoodsAutoFailVo; +import org.dromara.zhishu.domain.bo.GoodsAutoFailBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 自动发布失败Service接口 + * + * @author yxy + * @date 2025-09-29 + */ +public interface IGoodsAutoFailService { + + /** + * 查询自动发布失败 + * + * @param id 主键 + * @return 自动发布失败 + */ + GoodsAutoFailVo queryById(Long id); + + /** + * 获取数据总数 + * @param bo + * @return + */ + Long selectAllNum(GoodsAutoFailBo bo); + + /** + * 分页查询自动发布失败列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 自动发布失败分页列表 + */ + TableDataInfo queryPageList(GoodsAutoFailBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的自动发布失败列表 + * + * @param bo 查询条件 + * @return 自动发布失败列表 + */ + List queryList(GoodsAutoFailBo bo); + + /** + * 新增自动发布失败 + * + * @param bo 自动发布失败 + * @return 是否新增成功 + */ + Boolean insertByBo(GoodsAutoFailBo bo); + + /** + * 修改自动发布失败 + * + * @param bo 自动发布失败 + * @return 是否修改成功 + */ + Boolean updateByBo(GoodsAutoFailBo bo); + + /** + * 校验并批量删除自动发布失败信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IKongFzService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IKongFzService.java new file mode 100644 index 0000000..bdf041a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IKongFzService.java @@ -0,0 +1,27 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.Map; + +/** + * Pdd接口Service + * + * @author yxy + * @date 2025-05-8 + */ +public interface IKongFzService { + + +// void goodAdd(String shopId, ZhishuShopGoods zhishuShopGoods, ShopDetailVo vo); + + /** + * 修改商品库存接口 + * itemId 孔夫子商品id + * number 库存 + */ + void goodUpdateStock(String token,String itemId,String number); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/INoticeService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/INoticeService.java new file mode 100644 index 0000000..2153ee5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/INoticeService.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.NoticeVo; +import org.dromara.zhishu.domain.bo.NoticeBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 消息通知Service接口 + * + * @author yxy + * @date 2025-05-17 + */ +public interface INoticeService { + + /** + * 查询消息通知 + * + * @param id 主键 + * @return 消息通知 + */ + NoticeVo queryById(Long id); + + /** + * 分页查询消息通知列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 消息通知分页列表 + */ + TableDataInfo queryPageList(NoticeBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的消息通知列表 + * + * @param bo 查询条件 + * @return 消息通知列表 + */ + List queryList(NoticeBo bo); + + /** + * 新增消息通知 + * + * @param bo 消息通知 + * @return 是否新增成功 + */ + Boolean insertByBo(NoticeBo bo); + + /** + * 修改消息通知 + * + * @param bo 消息通知 + * @return 是否修改成功 + */ + Boolean updateByBo(NoticeBo bo); + + /** + * 校验并批量删除消息通知信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IProductService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IProductService.java new file mode 100644 index 0000000..d8bf60b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IProductService.java @@ -0,0 +1,42 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.SinglePrint; +import org.dromara.zhishu.domain.bo.SinglePrintBo; + +import java.util.Map; + +/** + * 进销存商品列表 + * + * @author yxy + * @date 2026-06-02 + */ +public interface IProductService { + + + /** + * 获取用户仓库信息 + */ + Map getMappingList(); + + + /** + * 查询列表 + * @param bo + * @return + */ + TableDataInfo queryPageList(Map bo); + + + /** + * 发布商品 + */ + void releaseGoods(Map map); + + /** + * 自动发布接口 + */ + void releaseGoodsAuto(Map map); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningTaskService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningTaskService.java new file mode 100644 index 0000000..a2607c9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningTaskService.java @@ -0,0 +1,79 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.vo.RunningTaskNumVo; +import org.dromara.zhishu.domain.vo.RunningTaskVo; +import org.dromara.zhishu.domain.bo.RunningTaskBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 执行的任务Service接口 + * + * @author yxy + * @date 2025-07-23 + */ +public interface IRunningTaskService { + + List selectGetShopGoodsList(Long shopId,Long pageNum,Long pageSize); + + List> selectLogByTaskId(Long taskId); + + Long selectGetShopGoodsNum(Long shopId); + + Map selectTaskStatus(); + + List selectTaskAllNum(Long taskId); + + Long selectTaskIsRunning(Long taskId); + + Long selectShopTaskByGetShopGoods(Long shopId); + + Long selectTaskStatusByTaskType(Long shopId,String taskType); + + Long selectTaskStatusByTaskTypeAndIsbn(Long shopId,String taskType,String isbn); + + Long selectTaskStatusRunningCount(); + + List selectTaskByGroupShopMd5(); + + /** + * 查询正在执行中的任务 + * @return + */ + List selectTaskGroupShop(String taskType); + + List selectTaskShopNum(Long taskId,Long shopId); + /** + * 新增执行的任务 + * + * @param runningTask 执行的任务 + * @return 是否新增成功 + */ + Boolean insert(RunningTask runningTask); + + Boolean batchInsert(List list); + + /** + * 修改执行的任务 暂停/恢复/中止 + * @param runningTask + * @return + */ + Boolean update(RunningTask runningTask); + + /** + * 获取任务池运行状态 + * @param ip + * @param host + * @param url + * @return + */ + Map getJavaTaskPool(String ip,String host,String url); + + Boolean updataStatus(Long shopId,Long taskId); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopGoodIsbnService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopGoodIsbnService.java new file mode 100644 index 0000000..7f987a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopGoodIsbnService.java @@ -0,0 +1,4 @@ +package org.dromara.zhishu.service; + +public interface IShopGoodIsbnService { +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopGoodsPublishedService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopGoodsPublishedService.java new file mode 100644 index 0000000..4328e69 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopGoodsPublishedService.java @@ -0,0 +1,189 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.PlatformIdUpdateVO; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.domain.bo.ShopGoodsPublishedBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 记录已发布书籍Service接口 + * + * @author yxy + * @date 2025-04-11 + */ +public interface IShopGoodsPublishedService { + + /** + * 查询记录已发布书籍 + * + * @param id 主键 + * @return 记录已发布书籍 + */ + ShopGoodsPublishedVo queryById(Long id); + + /** + * 根据shop_goods_id批量查询 + * @param shopGoodsIds 商品ID列表 + * @return 查询结果列表 + */ + List selectByShopGoodsIds(List shopGoodsIds,Long shopId); + + List selectListByShopsId(Long shopId); + + /** + * 根据店铺id和货号查询当前店铺这个商品是否在已发布商品表中存在记录 + * @param shopId + * @param artNo + * @return + */ + List selectShopGoodsPublishedByShopIdAndArtNo(Long shopId,String artNo); + + + ShopGoodsPublishedVo selectDataById(Long id); + + TableDataInfo selectDataList(ShopGoodsPublishedBo bo, PageQuery pageQuery); + + /** + * 分页查询记录已发布书籍列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 记录已发布书籍分页列表 + */ + TableDataInfo queryPageList(ShopGoodsPublishedBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的记录已发布书籍列表 + * + * @param bo 查询条件 + * @return 记录已发布书籍列表 + */ + List queryList(ShopGoodsPublishedBo bo); + + /** + * 新增记录已发布书籍 + * + * @param bo 记录已发布书籍 + * @return 是否新增成功 + */ + Boolean insertByBo(ShopGoodsPublishedBo bo); + + /** + * 修改记录已发布书籍 + * + * @param bo 记录已发布书籍 + * @return 是否修改成功 + */ + Boolean updateByBo(ShopGoodsPublishedBo bo); + + /** + * 校验并批量删除记录已发布书籍信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 一键删除 + * @return + */ + String deleteAll(Long shopId); + + /** + * 根据店铺id删除 + * @param shopId + * @return + */ + String deleteByShopId(Long shopId); + + /** + * 根据店铺id查询商品列表 + * + * @param shopId + * @return + */ + List selectGoodsListByShopId(Long shopId, List platformIds); + + List selectGoodsListByShopId(Long shopId); + + /** + * 根据店铺id和商品id查询商品 + * + * @param shopId + * @param platformId + * @return + */ + ShopGoodsPublishedVo queryByPlatformId(String shopId, String platformId); + + /** + * 根据商品id和店铺id查询 + * + * @param shopId 店铺id + * @param shopGoodsId 商品id + * @return + */ + ShopGoodsPublishedVo queryByShopIdAndShopGoodsId(String shopId, String shopGoodsId); + + /** + * 根据商品id查询商品列表 + * + * @param shopGoodsId + * @return + */ + List queryByShopGoodsId(String shopGoodsId); + + /** + * 商品发布驳回-类目修改cat_id + * + * @param shopType + * @param mallId + * @param platformId + * @return + */ + Boolean uodateCatId(String shopType, Long mallId, String platformId); + + /** + * 根据店铺id和商品id删除商品 + * + * @param shopType + * @param mallId + * @param platformId + * @return + */ + Boolean delShopGoodsPublished(String shopType, Long mallId, String platformId, String rejectComment); + + /** + * 批量查询商品发布状态 + * + * @param goodsIds 商品ID列表 + * @param shopIds 店铺ID列表 + * @return 商品发布状态列表 + */ + List> selectPublishedStatus(List goodsIds, List shopIds); + + List getPlatFormIdsByShopId(Long shopId); + + void batchUpdateKfzPlatformId(List platformIdUpdateVOList); + + void insertLog(String shopType,Long mallId, String platformId,String offshelftime); + + /** + * 查询总数 + * @param bo + * @return + */ + Long selectCount(ShopGoodsPublishedBo bo); + + /** + * 已发布商品记录校验店铺商品 + */ + void verifyShopGoodsPublished(String shopId); +} + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopService.java new file mode 100644 index 0000000..774c9fe --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopService.java @@ -0,0 +1,180 @@ +package org.dromara.zhishu.service; + +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.validation.constraints.NotNull; +import org.dromara.zhishu.domain.bo.EncryptionDataBo; +import org.dromara.zhishu.domain.dto.request.UpdateTokenRequest; +import org.dromara.zhishu.domain.dto.response.GetWlnShopListResponse; +import org.dromara.zhishu.domain.vo.DecryptDataVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 店铺主表Service接口 + * + * @author yxy + * @date 2025-03-10 + */ +public interface IShopService { + + /** + * 查询店铺主表 + * + * @param id 主键 + * @return 店铺主表 + */ + ShopVo queryById(Long id); + + /** + * 根据店铺类型查询店铺列表 + * @param type + * @return + */ + List queryByType(String type, Long userId); + + /** + * 根据三方店铺id查询数据数量 + * + * @param mallId + * @return + */ + ShopVo selectByMallId(String mallId); + + List selectListByMallId(Long mallId); + + List selectMallIdsById(Long id); + + ShopVo selectByToken(String token); + + ShopVo selectByShopName(String shopName); + + ShopVo selectByGoofishShopKey(String shopKey); + + Boolean checkIsExist(String shopKey); + + List selectByAccount(String account); + + /** + * 分页查询店铺主表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺主表分页列表 + */ + TableDataInfo queryPageList(ShopBo bo, PageQuery pageQuery); + + /** + * 分页查询店铺主表列表(邀请码) + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺主表分页列表 + */ + TableDataInfo queryPageListInvite(ShopBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的店铺主表列表 + * + * @param bo 查询条件 + * @return 店铺主表列表 + */ + List queryList(ShopBo bo); + + /** + * 新增店铺主表 + * + * @param bo 店铺主表 + * @return 是否新增成功 + */ + Boolean insertByBo(ShopBo bo); + + /** + * 修改店铺主表 + * + * @param bo 店铺主表 + * @return 是否修改成功 + */ + Boolean updateByBo(ShopBo bo); + + /** + * 校验并批量删除店铺主表信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取店铺绑定的仓库 + */ + Object getShopDepotByShopId(Long shopId); + + /** + * 绑定仓库到店铺 + */ + boolean bindDepotToShop(Long shopId, List depotId); + + /** + * 校验三方店铺与本系统店铺关联 + * + * @return + */ + int selectShopAssociationMall(ShopBo shopBo); + + Boolean updateTime(Long shopId, Long startUpdatedAt); + + ShopVo queryByMailId(Long mailId, Integer shopType); + + ShopVo queryByMailIdbyUseing(Long mailId, Integer shopType); + + Boolean updateToken(UpdateTokenRequest request); + + List getShopId(Long userId); + + List getShopIdByUserIdAndExpirationTime(Long userId); + + List selectCorrelationByUserId(Long userId); + + Boolean updateShopIsSynOrder(@NotNull(message = "主键不能为空") Long shopId, int status); + + List getWlnShopList(@NotNull(message = "页码不能为空") Integer page, @NotNull(message = "条数不能为空") Integer limit, @NotNull(message = "店铺Id不能为空") Long shopId, String shopNick); + + Boolean authorizationWln(Long shopId, String shopName, String shopNick); + + Map encryptionData(EncryptionDataBo bo) throws JsonProcessingException; + + DecryptDataVo decryptionData(String data); + + JSONObject decryptDataVoList(String data); + + Object getDecryptedUrlList(String data); + + void updateTokenByPddMallId(String pddMallId, String accessToken); + + int updateShopSkuSpec(String id, String skuSpec); + + /** + * 查看调用次数 + * @param shopVo 店铺信息 + * @return + */ + Long checkUsageCount(ShopVo shopVo); + + /** + * 修改调用次数 + * @param shopVo + * @param usageCount + */ + void updateUsageCount(ShopVo shopVo ,Long usageCount); + + + List selectByIds(List ids); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISinglePrintService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISinglePrintService.java new file mode 100644 index 0000000..f65ab1f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISinglePrintService.java @@ -0,0 +1,69 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.SinglePrint; +import org.dromara.zhishu.domain.bo.SinglePrintBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 单票打印Service接口 + * + * @author yxy + * @date 2026-03-27 + */ +public interface ISinglePrintService { + + /** + * 查询单票打印 + * + * @param id 主键 + * @return 单票打印 + */ + SinglePrint queryById(Long id); + + /** + * 根据快递单号查询 + * + * @param mailNo 快递单号 + * @return 单票打印 + */ + SinglePrint queryByMailNo(String mailNo); + + /** + * 分页查询单票打印列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 单票打印分页列表 + */ + TableDataInfo queryPageList(SinglePrintBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的单票打印列表 + * + * @param bo 查询条件 + * @return 单票打印列表 + */ + List queryList(SinglePrintBo bo); + + + /** + * 校验并批量删除单票打印信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据快递单号删除 + * + * @param mailNo 快递单号 + * @return 是否删除成功 + */ + Boolean deleteByMailNo(String mailNo); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITDepotService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITDepotService.java new file mode 100644 index 0000000..cdb4a54 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITDepotService.java @@ -0,0 +1,101 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.bo.TDepotBo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TFreightVo; +import org.dromara.zhishu.domain.vo.TShelvesVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 仓库信息设置Service接口 + * + * @author Lion Li + * @date 2025-03-26 + */ +public interface ITDepotService { + + /** + * 查询仓库信息设置 + * + * @param id 主键 + * @return 仓库信息设置 + */ + TDepotVo queryById(Long id); + + /** + * 根据仓库code查询仓库信息 + * @param artNo + * @return + */ + TDepotVo selectDepotByCode(String artNo); + + /** + * 分页查询仓库信息设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 仓库信息设置分页列表 + */ + TableDataInfo queryPageList(TDepotBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的仓库信息设置列表 + * + * @param bo 查询条件 + * @return 仓库信息设置列表 + */ + List queryList(TDepotBo bo); + + List selectList(TDepotBo bo); + + /** + * 新增仓库信息设置 + * + * @param bo 仓库信息设置 + * @return 是否新增成功 + */ + Boolean insertByBo(TDepotBo bo); + + /** + * 修改仓库信息设置 + * + * @param bo 仓库信息设置 + * @return 是否修改成功 + */ + Boolean updateByBo(TDepotBo bo); + + /** + * 校验并批量删除仓库信息设置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid,Long LocalUserId); + + + List queryNameList(String phoneNumber); + + List querySheNameList(String depotId); + + List queryFreNameList(String sheId); + + + Map getIds(String depotName, String freightName, String shelvesName); + + List queryShelvesList(Long id); + + List queryTFreightList(Long id); + + + List queryListAll(); + + List selectDepotIdByUserIdAndCode(Long userId, String code); + + List selectArtNoLists(Long userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITLogisticsService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITLogisticsService.java new file mode 100644 index 0000000..3a8d39c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITLogisticsService.java @@ -0,0 +1,74 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.zhishu.domain.bo.TLogisticsBo; +import org.dromara.zhishu.domain.vo.TLogisticsVo; + +import java.util.Collection; +import java.util.List; + +/** + * 物流管理Service接口 + * + * @author Lion Li + * @date 2025-04-22 + */ +public interface ITLogisticsService { + + /** + * 查询物流管理 + * + * @param id 主键 + * @return 物流管理 + */ + TLogisticsVo queryById(Long id); + + /** + * 分页查询物流管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 物流管理分页列表 + */ + TableDataInfo queryPageList(TLogisticsBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的物流管理列表 + * + * @param bo 查询条件 + * @return 物流管理列表 + */ + List queryList(TLogisticsBo bo); + + /** + * 新增物流管理 + * + * @param bo 物流管理 + * @return 是否新增成功 + */ + Boolean insertByBo(TLogisticsBo bo); + + /** + * 修改物流管理 + * + * @param bo 物流管理 + * @return 是否修改成功 + */ + Boolean updateByBo(TLogisticsBo bo); + + /** + * 校验并批量删除物流管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + List queryNameList(); + + List getList(Long userId); + + List queryNameListByXcx(Long userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopOrderDetailService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopOrderDetailService.java new file mode 100644 index 0000000..a0b8c1c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopOrderDetailService.java @@ -0,0 +1,78 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.TShopOrderDetailVo; +import org.dromara.zhishu.domain.bo.TShopOrderDetailBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 订单详情Service接口 + * + * @author Lion Li + * @date 2025-03-13 + */ +public interface ITShopOrderDetailService { + + /** + * 查询订单详情 + * + * @param id 主键 + * @return 订单详情 + */ + TShopOrderDetailVo queryById(Long id); + + /** + * 分页查询订单详情列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 订单详情分页列表 + */ + TableDataInfo queryPageList(TShopOrderDetailBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的订单详情列表 + * + * @param bo 查询条件 + * @return 订单详情列表 + */ + List queryList(TShopOrderDetailBo bo); + + /** + * 新增订单详情 + * + * @param bo 订单详情 + * @return 是否新增成功 + */ + Boolean insertByBo(TShopOrderDetailBo bo); + + /** + * 修改订单详情 + * + * @param bo 订单详情 + * @return 是否修改成功 + */ + Boolean updateByBo(TShopOrderDetailBo bo); + + /** + * 校验并批量删除订单详情信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + + /** + * 批量订单详情 + * + * @param ids + * @param isValid + * @return + */ + void insertBatchOrderDetail(String itemList,String orderSn,Long orderId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopOrderService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopOrderService.java new file mode 100644 index 0000000..d6c74dc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopOrderService.java @@ -0,0 +1,167 @@ +package org.dromara.zhishu.service; + +import com.google.gson.JsonArray; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.TShopOrder; +import org.dromara.zhishu.domain.dto.request.UpdateIsSynOrderRequest; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryRequest; +import org.dromara.zhishu.domain.dto.request.OrderListByShopIdRequest; +import org.dromara.zhishu.domain.dto.PddOrderQueryDto; +import org.dromara.zhishu.domain.vo.TShopOrderVo; +import org.dromara.zhishu.domain.bo.TShopOrderBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +/** + * 订单Service接口 + * + * @author Lion Li + * @date 2025-03-13 + */ +public interface ITShopOrderService { + /** + * 查询订单 + * + * @param id 主键 + * @return 订单 + */ + TShopOrderVo queryById(Long id); + + /** + * 分页查询订单列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 订单分页列表 + */ + TableDataInfo queryPageList(TShopOrderBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的订单列表 + * + * @param bo 查询条件 + * @return 订单列表 + */ + List queryList(TShopOrderBo bo); + + /** + * 新增订单 + * + * @param bo 订单 + * @return 是否新增成功 + */ + Boolean insertByBo(TShopOrderBo bo); + + /** + * 修改订单 + * + * @param bo 订单 + * @return 是否修改成功 + */ + Boolean updateByBo(TShopOrderBo bo); + + + + Boolean updateBy(TShopOrder bo); + /** + * 校验并批量删除订单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取平台订单 + * @param queryDto + * @return + */ + R getInterShopOrder(PddOrderQueryDto queryDto); + + /** + * 批量插入平台订单 + * @param jsonArray + */ + void insertPddIncrementOrder(JsonArray jsonArray); + + /** + * 自定义分页查询 + * @param bo + * @param pageQuery + * @return + */ + TableDataInfo customPageList(TShopOrderBo bo, PageQuery pageQuery); + + /** + * 根据店铺id查询订单列表 + * @param request + * @return + */ + List listByShopId(OrderListByShopIdRequest request); + + /** + * 批量插入订单 + * @param orderList + * @return + */ + void insertOrUpdateOrderBatch(List orderList); + + /** + * 根据订单编号查询订单 + * @param orderSn + * @return + */ + TShopOrderVo listByOrderSn(String orderSn); + + /** + * 定时同步孔网订单 + * @return + */ + void syncKfzOrderTask(); + + /** + * 获取配送方式列表 + * @param shopId + * @param orderSourceType + * @return + */ + List deliveryMethodList(Long shopId, Integer orderSourceType); + + /** + * 订单发货 + * @param request + * @return + */ + Boolean orderDelivery(OrderDeliveryRequest request); + + /** + * 同步历史订单 + * @param days + * @param shopIdList + * @return + */ + void syncKfzHistoryOrder(@NotNull(message = "重新拉取历史订单天数不能为空") Integer days, @NotEmpty(message = "同步店铺不能为空") List shopIdList); + + /** + * 同步历史订单回调 + */ + void syncKfzHistoryOrderCallBack(Long shopId); + + /** + * 修改店铺订单同步状态 + * @param request + */ + void updateIsSynOrder(UpdateIsSynOrderRequest request); + + TShopOrderBo findSHopOrderByid(String id); + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITaskService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITaskService.java new file mode 100644 index 0000000..8987560 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITaskService.java @@ -0,0 +1,136 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.vo.TaskVo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 任务列表Service接口 + * + * @author yxy + * @date 2025-03-21 + */ +public interface ITaskService { + + /** + * 查询任务列表 + * + * @param id 主键 + * @return 任务列表 + */ + TaskVo queryById(Long id); + + TaskVo selectByFileName(String fileName); + + List selectRunningTask(Integer pageSize,Integer pageNum); + + int selectRunningTaskCount(); + /** + * 分页查询任务列表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 任务列表分页列表 + */ + TableDataInfo queryPageList(TaskBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的任务列表列表 + * + * @param bo 查询条件 + * @return 任务列表列表 + */ + List queryList(TaskBo bo); + + /** + * 新增任务列表 + * + * @param bo 任务列表 + * @return 是否新增成功 + */ + Boolean insertByBo(TaskBo bo); + + void addGoods(Map map, TaskBo taskBo, Long userId); + + void addGoodsCenter(Map map, TaskBo taskBo, Long userId); + + void editGoodsPrice(Map map, TaskBo taskBo, Long userId); + + void editGoodsStock(Map map, TaskBo taskBo, Long userId); + + /** + * 修改两件折扣 + * @param map + * @param taskBo + * @param userId + */ +// void editTwoPiecesDiscount(Long shopId); + + void editGoodsIsOnSale(Map map, TaskBo taskBo, Long userId); + + void updateGoodsTask(Map map, TaskBo taskBo, Long userId); + + void stockSynchronize(Map map,TaskBo taskBo,Long userId); + + void deleteShopGoods(Map map, TaskBo taskBo, Long userId); + + int zanTing(String threadId); + + public int huanXing(String threadId); + + /** + * 修改任务列表 + * + * @param bo 任务列表 + * @return 是否修改成功 + */ + Boolean updateByBo(TaskBo bo); + + /** + * 校验并批量删除任务列表信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + void editTaskDataNum(String shopIds, Long dataNum, String taskType); + + + Map handlePullTask(TaskVo taskVo); + + Map handleOtherTask(TaskVo taskVo); + + Task getTaskBoById(String id); + + Task getTaskBoByRelationId(String id); + + + List getShopsBatch(List ids) ; + + List getShopDetailsBatch(List ids); + + /** + * 暂停任务 + * @param taskId + * @return + */ + Boolean taskPause(Long taskId); + + /** + * 恢复任务 + * @param taskId + * @return + */ + Boolean taskRecover(Long taskId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserTAuditService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserTAuditService.java new file mode 100644 index 0000000..c219752 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserTAuditService.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.UserTAuditVo; +import org.dromara.zhishu.domain.bo.UserTAuditBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 列表Service接口 + * + * @author Lion Li + * @date 2025-04-02 + */ +public interface IUserTAuditService { + + /** + * 查询列表 + * + * @param id 主键 + * @return 列表 + */ + UserTAuditVo queryById(Long id); + + /** + * 分页查询列表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 列表分页列表 + */ + TableDataInfo queryPageList(UserTAuditBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的列表列表 + * + * @param bo 查询条件 + * @return 列表列表 + */ + List queryList(UserTAuditBo bo); + + /** + * 新增列表 + * + * @param bo 列表 + * @return 是否新增成功 + */ + Boolean insertByBo(UserTAuditBo bo); + + /** + * 修改列表 + * + * @param bo 列表 + * @return 是否修改成功 + */ + Boolean updateByBo(UserTAuditBo bo); + + /** + * 校验并批量删除列表信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + UserTAuditVo getAuditLog(); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWarehouseSettingsAttributeService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWarehouseSettingsAttributeService.java new file mode 100644 index 0000000..aa7d46c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWarehouseSettingsAttributeService.java @@ -0,0 +1,16 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.WarehouseSettingsAttribute; + +import java.util.List; + +public interface IWarehouseSettingsAttributeService { + + /** + * 查询规则属性列表 + * @param warehouseSettingsAttribute + * @return + */ + List selectList(WarehouseSettingsAttribute warehouseSettingsAttribute); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/NewUserService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/NewUserService.java new file mode 100644 index 0000000..565baee --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/NewUserService.java @@ -0,0 +1,8 @@ +package org.dromara.zhishu.service; + + +import org.dromara.zhishu.domain.bo.NewUserBo; + +public interface NewUserService { + boolean insertByBo(NewUserBo newUserBo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsRejectionService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsRejectionService.java new file mode 100644 index 0000000..0ebd11e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsRejectionService.java @@ -0,0 +1,34 @@ +package org.dromara.zhishu.service; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.ShopGoodsRejection; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; + +import java.awt.print.Pageable; +import java.util.List; + +public interface ShopGoodsRejectionService { + + boolean save(ShopGoodsRejection shopGoodsRejection); + + boolean delete(Long id); + + boolean update(ShopGoodsRejection shopGoodsRejection); + + ShopGoodsRejection findById(Long id); + + List findAll(); + + List findByShopId(String shopId); + + List findByPlatformId(String platformId); + + List search(ShopGoodsRejection condition); + + TableDataInfo searchWithPage(ShopGoodsRejection bo, PageQuery pageQuery); + + int count(ShopGoodsRejection condition); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsService.java new file mode 100644 index 0000000..c6cc454 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsService.java @@ -0,0 +1,211 @@ +package org.dromara.zhishu.service; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.zhishu.domain.dto.ShopGoodsDto; + +import java.util.List; +import java.util.Map; + +/** + * 商品信息Service接口 + */ +public interface ShopGoodsService { + + // ==================== 表管理 ==================== + + /** + * 检查表是否存在 + * @param tableName 表名 + * @return 是否存在 + */ + boolean checkTableExists(String tableName); + + /** + * 创建表 + * @param tableName 表名 + */ + void createTable(String tableName); + + /** + * 初始化表(如果不存在则创建) + * @param tableName 表名 + */ + void initTable(String tableName); + + // ==================== 插入操作 ==================== + + /** + * 插入单条数据 + * @param tableName 表名 + * @param shopGoods 商品信息 + * @return 影响行数 + */ + int insert(String tableName, ShopGoodsDto shopGoods); + + /** + * 批量插入 + * @param tableName 表名 + * @param list 商品列表 + * @return 影响行数 + */ + int batchInsert(String tableName, List list); + + // ==================== 删除操作 ==================== + + /** + * 根据ID删除 + * @param tableName 表名 + * @param id 主键ID + * @return 影响行数 + */ + int deleteById(String tableName, Long id); + + /** + * 根据条件删除 + * @param tableName 表名 + * @param trilateralId 商品id + * @param isbn ISBN号 + * @param shopId 店铺id + * @param isOnSale 上下架状态 + * @return 影响行数 + */ + int deleteByCondition(String tableName, String trilateralId, String isbn, String shopId, String isOnSale); + + /** + * 批量删除 + * @param tableName 表名 + * @param ids ID列表 + * @return 影响行数 + */ + int batchDeleteByIds(String tableName, List ids); + + /** + * 删除所有数据 + * @param tableName 表名 + * @return 影响行数 + */ + int deleteAll(String tableName); + + // ==================== 更新操作 ==================== + + /** + * 根据ID更新 + * @param tableName 表名 + * @param shopGoods 商品信息 + * @return 影响行数 + */ + int updateById(String tableName, ShopGoodsDto shopGoods); + + /** + * 更新上下架状态 + * @param tableName 表名 + * @param trilateralId 商品id + * @param isOnSale 上下架状态 + * @return 影响行数 + */ + int updateOnSaleStatus(String tableName, String trilateralId, String isOnSale); + + /** + * 批量更新上下架状态 + * @param tableName 表名 + * @param trilateralIds 商品id列表 + * @param isOnSale 上下架状态 + * @return 影响行数 + */ + int batchUpdateOnSaleStatus(String tableName, List trilateralIds, String isOnSale); + + // ==================== 查询操作 ==================== + + /** + * 根据ID查询 + * @param tableName 表名 + * @param id 主键ID + * @return 商品信息 + */ + ShopGoodsDto selectById(String tableName, Long id); + + /** + * 根据商品ID查询 + * @param tableName 表名 + * @param trilateralId 商品id + * @return 商品信息 + */ + ShopGoodsDto selectByTrilateralId(String tableName, String trilateralId); + + /** + * 根据ISBN查询列表 + * @param tableName 表名 + * @param isbn ISBN号 + * @return 商品列表 + */ + List selectByIsbn(String tableName, String isbn); + + /** + * 根据店铺ID查询列表 + * @param tableName 表名 + * @param shopId 店铺id + * @return 商品列表 + */ + List selectByShopId(String tableName, String shopId); + + /** + * 分页条件查询 + * @param tableName 表名 + * @param shopGoodsDto 查询条件(包含分页参数) + * @return 商品列表 + */ + List selectByCondition(String tableName, ShopGoodsDto shopGoodsDto); + + /** + * 条件查询总数 + * @param tableName 表名 + * @param shopGoodsDto 查询条件 + * @return 总数 + */ + int selectCountByCondition(String tableName, ShopGoodsDto shopGoodsDto); + + /** + * 查询所有商品 + * @param tableName 表名 + * @return 商品列表 + */ + List selectAll(String tableName); + + /** + * 统计在售商品数量 + * @param tableName 表名 + * @return 在售商品数量 + */ + int countOnSale(String tableName); + + /** + * 统计总记录数 + * @param tableName 表名 + * @return 总记录数 + */ + int countAll(String tableName); + + /** + * 根据商品编码查询 + * @param tableName 表名 + * @param goodsCode 商品编码 + * @return 商品信息 + */ + ShopGoodsDto selectByGoodsCode(String tableName, String goodsCode); + + /** + * 根据SKU编码查询 + * @param tableName 表名 + * @param skuCode sku编号 + * @return 商品信息 + */ + ShopGoodsDto selectBySkuCode(String tableName, String skuCode); + + /** + * 批量查询是否存在 + * @param tableName 表名 + * @param trilateralIds 商品id列表 + * @return 存在映射 + */ + List> batchCheckExists(String tableName, List trilateralIds); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/StockChangeLogService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/StockChangeLogService.java new file mode 100644 index 0000000..1e87123 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/StockChangeLogService.java @@ -0,0 +1,10 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.StockChangeLogVo; + +import java.util.List; + +public interface StockChangeLogService { + + List selectShopStockLogbyCreateBy(String id,String createBy); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/TShopGoodsPublishedService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/TShopGoodsPublishedService.java new file mode 100644 index 0000000..ea2a38e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/TShopGoodsPublishedService.java @@ -0,0 +1,167 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.dto.TShopGoodsPublishedDto; + +import java.util.List; + +/** + * 已发布商品信息Service接口 + */ +public interface TShopGoodsPublishedService { + + // ==================== 表管理 ==================== + + /** + * 检查表是否存在 + * + * @return 是否存在 + */ + boolean checkTableExists(); + + /** + * 创建表 + */ + void createTable(); + + /** + * 初始化表(如果不存在则创建) + */ + void initTable(); + + // ==================== 插入操作 ==================== + + /** + * 插入单条数据 + * + * @param dto 已发布商品信息 + * @return 影响行数 + */ + int insert(TShopGoodsPublishedDto dto); + + /** + * 批量插入 + * + * @param list 已发布商品列表 + * @return 影响行数 + */ + int batchInsert(List list); + + // ==================== 删除操作 ==================== + + /** + * 根据ID删除 + * + * @param id 主键ID + * @return 影响行数 + */ + int deleteById(Long id); + + /** + * 根据条件删除 + * + * @param erpShopId erp店铺id + * @param shopId 平台店铺id + * @param productId 商品id + * @param warehouseId 仓库id + * @return 影响行数 + */ + int deleteByCondition(Long erpShopId, Long shopId, Long productId, Long warehouseId); + + /** + * 批量删除 + * + * @param ids ID列表 + * @return 影响行数 + */ + int batchDeleteByIds(List ids); + + /** + * 删除所有数据 + * + * @return 影响行数 + */ + int deleteAll(); + + // ==================== 更新操作 ==================== + + /** + * 根据ID更新 + * + * @param dto 已发布商品信息 + * @return 影响行数 + */ + int updateById(TShopGoodsPublishedDto dto); + + // ==================== 查询操作 ==================== + + /** + * 根据ID查询 + * + * @param id 主键ID + * @return 已发布商品信息 + */ + TShopGoodsPublishedDto selectById(Long id); + + /** + * 根据ERP店铺ID查询列表 + * + * @param erpShopId erp店铺id + * @return 已发布商品列表 + */ + List selectByErpShopId(Long erpShopId); + + /** + * 根据平台店铺ID查询列表 + * + * @param shopId 平台店铺id + * @return 已发布商品列表 + */ + List selectByShopId(Long shopId); + + /** + * 根据商品ID查询 + * + * @param productId 商品id + * @return 已发布商品信息 + */ + TShopGoodsPublishedDto selectByProductId(Long productId); + + /** + * 分页条件查询 + * + * @param dto 查询条件(包含分页参数) + * @return 已发布商品列表 + */ + List selectByCondition(TShopGoodsPublishedDto dto); + + /** + * 条件查询总数 + * + * @param dto 查询条件 + * @return 总数 + */ + int selectCountByCondition(TShopGoodsPublishedDto dto); + + /** + * 查询所有 + * + * @return 已发布商品列表 + */ + List selectAll(); + + /** + * 统计总记录数 + * + * @return 总记录数 + */ + int countAll(); + + /** + * 根据ERP店铺ID和商品ID查询 + * + * @param erpShopId erp店铺id + * @param productId 商品id + * @return 已发布商品信息 + */ + TShopGoodsPublishedDto selectByErpShopIdAndProductId(Long erpShopId, Long productId); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/BookCenterClient.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/BookCenterClient.java new file mode 100644 index 0000000..159c386 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/BookCenterClient.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.service.client; + +import com.dtflys.forest.annotation.Get; +import com.dtflys.forest.annotation.Query; +import com.dtflys.forest.annotation.Var; +import org.dromara.zhishu.domain.dto.response.GetBookByISBNResponse; +import org.springframework.stereotype.Service; + +@Service +public interface BookCenterClient { + + /** + * 查询-ISBN + * + * @param myURL + * @return + */ + @Get(value = "{myURL}/api/bookBase/getBookByISBN", dataType = "json") + GetBookByISBNResponse getBookByISBN(@Var("myURL") String myURL, @Query("isbn") String isbn); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/FileClient.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/FileClient.java new file mode 100644 index 0000000..eee5b85 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/FileClient.java @@ -0,0 +1,33 @@ +package org.dromara.zhishu.service.client; + +import com.dtflys.forest.annotation.*; +import org.dromara.common.core.domain.R; +import org.springframework.stereotype.Service; + +@Service +public interface FileClient { + + /** + * 文件上传 + * + * @param myURL 调用url + * @param fileBase64 Base64上传(四选一) + * @param subDir 次级目录名 + * @param fileName 文件名(网络路径/Base64/Byte[]必传) + * @return json响应 + */ + @Post(value = "{myURL}/upload", dataType = "json", headers = "Content-Type: multipart/form-data") + R upload(@Var("myURL") String myURL, @Body("file_base64") String fileBase64, @Body("sub_dir") String subDir, @Body("file_name") String fileName); + + /** + * 获取文件 + * + * @param myURL 调用url + * @param filePath 文件路径 + * @param returnType 返回类型:url-网络路径 base64-Base64编码 byte_array-byte[]十六进制字符串 + * @return json响应 + */ + @Get(value = "{myURL}/get", dataType = "json") + R get(@Var("myURL") String myURL, @Query("file_path") String filePath, @Query("return_type") String returnType); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/LogClient.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/LogClient.java new file mode 100644 index 0000000..cbdc8ff --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/LogClient.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.service.client; + +import com.dtflys.forest.annotation.Body; +import com.dtflys.forest.annotation.Post; +import com.dtflys.forest.annotation.Var; +import org.dromara.zhishu.domain.dto.request.AddTaskLogRequest; +import org.dromara.zhishu.domain.dto.response.AddTaskLogResponse; +import org.springframework.stereotype.Service; + + +@Service +public interface LogClient { + + /** + * 添加任务日志 + * + * @param myURL + * @return + */ + @Post(value = "{myURL}/api/task", dataType = "json") + AddTaskLogResponse addTaskLog(@Var("myURL") String myURL, @Body AddTaskLogRequest request); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/ItemListJsonStringParseStrategyFactory.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/ItemListJsonStringParseStrategyFactory.java new file mode 100644 index 0000000..f031f30 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/ItemListJsonStringParseStrategyFactory.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.service.factory; + +import org.dromara.zhishu.service.strategy.*; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class ItemListJsonStringParseStrategyFactory implements ApplicationContextAware { + + private static ApplicationContext context; + + private static final Map>> strategyClasses = new HashMap<>(); + + static { + // 可以继续添加其他的消息类型对应的策略 + strategyClasses.put(1, ItemListJsonStringParsePddStrategy.class); + strategyClasses.put(2, ItemListJsonStringParseKWStrategy.class); + strategyClasses.put(5, ItemListJsonStringParseGFStrategy.class); + } + + public static ItemListJsonStringParseStrategy getStrategy(Integer type) { + Class> strategyClass = strategyClasses.get(type); + if (strategyClass != null) { + return context.getBean(strategyClass); + } + return null; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + context = applicationContext; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/OrderStrategyFactory.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/OrderStrategyFactory.java new file mode 100644 index 0000000..53b3954 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/OrderStrategyFactory.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.service.factory; + +import org.dromara.zhishu.service.strategy.*; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class OrderStrategyFactory implements ApplicationContextAware { + + private static ApplicationContext context; + + private static final Map> strategyClasses = new HashMap<>(); + + static { + // 可以继续添加其他的消息类型对应的策略 + strategyClasses.put(1, OrderPddStrategy.class); + strategyClasses.put(2, OrderKWStrategy.class); + strategyClasses.put(5, OrderGFStrategy.class); + } + + public static OrderStrategy getStrategy(Integer type) { + Class strategyClass = strategyClasses.get(type); + if (strategyClass != null) { + return context.getBean(strategyClass); + } + return null; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + context = applicationContext; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/AccountServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/AccountServiceImpl.java new file mode 100644 index 0000000..4a73a87 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/AccountServiceImpl.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.Account; +import org.dromara.zhishu.domain.ProfitSharingLog; +import org.dromara.zhishu.service.IAccountService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequiredArgsConstructor +@Service +public class AccountServiceImpl implements IAccountService { + + @Override + public TableDataInfo queryPageList(Account bo, PageQuery pageQuery) { + Map params = new HashMap<>(); + params.put("page",pageQuery.getPageNum()); + params.put("pageSize",pageQuery.getPageSize()); + + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + params.put("gs_id",userId); + } + + if (bo.getType() != null){ + params.put("type",bo.getType()); + } + + if (bo.getTradeType() != null){ + params.put("trade_type",bo.getTradeType()); + } + + if (StringUtils.isNotEmpty(bo.getAccountNo())){ + params.put("account_no",bo.getAccountNo()); + } + + if (bo.getTradeStatus() != null){ + params.put("trade_status",bo.getTradeStatus()); + } + + if (!bo.getParams().isEmpty()){ + params.put("created_time_start",bo.getParams().get("startTime")); + params.put("created_time_end",bo.getParams().get("endTime")); + } + + String dataStr = InterfaceUtils.getInterfaceGetWithParams("https://go.order.service.buzhiyushu.cn","/api/account/getAccount",params); + Map dataMap = JsonUtil.transferToObj(dataStr,Map.class); + List list = (List) dataMap.get("data"); + int total = (int) dataMap.get("total"); + Page result = new Page<>(pageQuery.getPageNum(),pageQuery.getPageSize(),total); + result.setRecords(list); + return TableDataInfo.build(result); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/BookBaseInfoServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/BookBaseInfoServiceImpl.java new file mode 100644 index 0000000..b870516 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/BookBaseInfoServiceImpl.java @@ -0,0 +1,1625 @@ +package org.dromara.zhishu.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import io.reactivex.rxjava3.core.Completable; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.*; +import org.dromara.zhishu.domain.bo.*; +import org.dromara.zhishu.domain.vo.BaseInfoPricingVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.enums.BookParamsEnum; +import org.dromara.zhishu.domain.dto.BookBaseInfoDto; +import org.dromara.zhishu.domain.excel.BaseInfoExcel; +import org.dromara.zhishu.domain.vo.BookBaseInfoVo; +import org.dromara.zhishu.mapper.BookBaseInfoMapper; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.mapper.TaskMapper; +import org.dromara.zhishu.service.IBookBaseInfoService; +import org.dromara.zhishu.util.*; +import org.dromara.zhishu.service.IUserRechargeService; +import org.dromara.zhishu.domain.bo.UserRechargeBo; +import org.jetbrains.annotations.NotNull; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.stereotype.Service; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.RestTemplate; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +import static org.dromara.zhishu.util.InterfaceUtils.getInterface; + +/** + * 基础信息Service业务层处理 + * + * @author Lion Li + * @date 2025-03-08 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class BookBaseInfoServiceImpl implements IBookBaseInfoService { + + private final BookBaseInfoMapper baseMapper; + + private final ISysConfigService configService; + + private final PricingUrlUtil pricingUrlUtil; + + private final TaskMapper taskMapper; + + private final ShopMapper shopMapper; + + private final SysUserMapper sysUserMapper; + + private final IUserRechargeService userRechargeService; + + + @Autowired + private RestTemplate restTemplate; + @Autowired + private ShopServiceImpl shopServiceImpl; + + /** + * 查询基础信息 + * + * @param id 主键 + * @return 基础信息 + */ + @Override + public BookBaseInfoVo queryById(String id) { + BookBaseInfoBo bo = new BookBaseInfoBo(); + bo.setId(id); + return getBookBaseInfo(bo); + } + + /** + * 查询书籍数据 + * + * @param isbn + * @return + */ + @Override + public BookBaseInfoVo getBookByIsbn(String isbn) { + BookBaseInfoBo bo = new BookBaseInfoBo(); + bo.setIsbn(isbn); + return getBookBaseInfo(bo); + } + + + @Override + public BookBaseInfoVo getBookData(String isbn) { + BookBaseInfoBo bo = new BookBaseInfoBo(); + bo.setIsbn(isbn); + BookBaseInfoVo vo = getBookBaseInfo(bo); + if (vo == null) { + System.out.println("----------------调用PHP→爬虫接口"); + //调用接口查询孔夫子 + String kongfzIp = configService.selectConfigByKey("kongfz.ip"); + String bookinfoStr = getInterface(kongfzIp, "/api/kfz/getBookInfoF/" + isbn); + System.out.println("------------调用接口返回数据:" + bookinfoStr); + if (bookinfoStr == null || bookinfoStr.equals("")) { + vo = getBookBaseInfo(bo); + return vo; + } + Map bookinfoMap = JsonUtil.transferToObj(bookinfoStr, Map.class); + if (bookinfoMap.get("code").toString().equals("200")) { + System.out.println("查询成功"); + Map data = (Map) bookinfoMap.get("data"); + String bookInfoListStr = JsonUtil.transferToJson(data.get("product")); + List bookInfoList = JsonUtil.transferToObj(bookInfoListStr, List.class); + String bookInfo = JsonUtil.transferToJson(bookInfoList.get(0)); + System.out.println("查询的商品信息:" + bookInfoListStr); + vo = JsonUtil.transferToObj(bookInfo, BookBaseInfoVo.class); + } + } + return vo; + } + + @Override + public TableDataInfo getBookDataByIsbn(String isbn) { + String goUrl = configService.selectConfigByKey("centerBook.url"); +// String goUrl = "http://localhost:9009/api"; + String path = "/es/searchByISBN?isbn=" + isbn; + + String responseStr = InterfaceUtils.getInterfaceForBaseInfo(goUrl, path); + + if (StringUtils.isEmpty(responseStr)) { + return TableDataInfo.build(Collections.emptyList()); + } + + JSONObject json = JSON.parseObject(responseStr); + + if (!json.containsKey("data")) { + return TableDataInfo.build(Collections.emptyList()); + } + + // 解析 data 字段 + JSONObject dataJson = json.getJSONObject("data"); + BookBaseInfoVo result = dataJson.toJavaObject(BookBaseInfoVo.class); + + // ⭐⭐ 使用 List 包装成分页结构 + return TableDataInfo.build(Collections.singletonList(result)); + } + + /** + * 更新中心书籍 + * @param bo + * @return + */ + @Override + public Boolean updateCentBookByIsbn(BookUpdateInfoBo bo) { + + // 外部接口域名 + String phpUrl = configService.selectConfigByKey("centerBook.url"); +// String phpUrl = "http://localhost:9009"; + + // 外部接口路径 + String path = "/es/updateBookFieldsByISBN"; + + // 组装入参 JSON + JSONObject params = new JSONObject(); + params.put("isbn", bo.getIsbn()); + + JSONObject data = getJsonObject(bo); + + params.put("data", data); + System.out.println("调用外部接口参数: " + params); +// System.out.println("调用外部接口参数: " + params.toJSONString()); +// log.info("调用外部接口参数: {}", params.toJSONString()); + + // ----------- 调用外部接口POST ----------- + String responseStr = InterfaceUtils.getInterfacePost(phpUrl, path, params); + System.out.println("外部接口响应: " + responseStr); +// log.info("外部接口响应: {}", responseStr); + + if (responseStr == null) { + return false; + } + + try { + JSONObject resp = JSONObject.parseObject(responseStr); + + // 外部响应格式示例: + // { + // "code": 200, + // "data": { "updated": 1, ... }, + // "message": "success" + // } + + Integer code = resp.getInteger("code"); + if (code != 200) { + return false; + } + + JSONObject dataResp = resp.getJSONObject("data"); + if (dataResp == null) { + return false; + } + + Integer updated = dataResp.getInteger("updated"); + return updated != null && updated == 1; + + } catch (Exception e) { + System.out.println("解析外部接口响应失败"+ e); +// log.error("解析外部接口响应失败: {}", e.getMessage(), e); + return false; + } + } + + @NotNull + private static JSONObject getJsonObject(BookUpdateInfoBo bo) { + JSONObject data = new JSONObject(); + + // book_name:非空且非空串 + String bookName = bo.getBookName(); + if (bookName != null && !"".equals(bookName)) { + data.put("book_name", bookName); + } + + // book_pic 部分(不做非空判断,保持原样) + JSONObject bookPicObj = new JSONObject(); + bookPicObj.put("localPath", bo.getBookPic() != null ? bo.getBookPic().getLocalPath() : ""); + bookPicObj.put("pddPath", bo.getBookPic() != null ? bo.getBookPic().getPddPath() : ""); + data.put("book_pic", bookPicObj); + + // book_pic_s 部分(不做非空判断,保持原样) + JSONObject bookPicSObj = new JSONObject(); + bookPicSObj.put("localPath", bo.getBookPicS() != null ? bo.getBookPicS().getLocalPath() : ""); + bookPicSObj.put("pddResponse", bo.getBookPicS() != null ? bo.getBookPicS().getPddResponse() : ""); + data.put("book_pic_s", bookPicSObj); + + // book_pic_b:非空且非空串 + String bookPicB = bo.getBookPicB(); + if (bookPicB != null && !"".equals(bookPicB)) { + data.put("book_pic_b", bookPicB); + } + + // book_pic_w:非空且非空串 + String bookPicW = bo.getBookPicW(); + if (bookPicW != null && !"".equals(bookPicW)) { + data.put("book_pic_w", bookPicW); + } + + // author:非空且非空串 + String author = bo.getAuthor(); + if (author != null && !"".equals(author)) { + data.put("author", author); + } + + // category:非空且非空串 + String category = bo.getCategory(); + if (category != null && !"".equals(category)) { + data.put("category", category); + } + + // publisher:非空且非空串 + String publisher = bo.getPublisher(); + if (publisher != null && !"".equals(publisher)) { + data.put("publisher", publisher); + } + + // publication_time:非空且非空串(假设为字符串类型) + String publicationTime = bo.getPublicationTime(); + if (publicationTime != null && !"".equals(publicationTime)) { + data.put("publication_time", publicationTime); + } + + // binding_layout:非空且非空串 + String bindingLayout = bo.getBindingLayout(); + if (bindingLayout != null && !"".equals(bindingLayout)) { + data.put("binding_layout", bindingLayout); + } + + // update_time:时间戳,只需判断非 null + String updateTime = bo.getUpdateTimeTimestamp(); + if (updateTime != null && !"".equals(updateTime)) { + data.put("update_time", updateTime); + } + + return data; + } + + /** + * 查询单条数据 + * + * @param bo + * @return + */ + public BookBaseInfoVo getBookBaseInfo(BookBaseInfoBo bo) { + String path = "/bookBase/getBookBaseInfoAll" + getpamp(bo, null, null, "1", "10"); + String phpUrl = configService.selectConfigByKey("php.url"); + String BookBaseInfoVoStr = InterfaceUtils.getInterface(phpUrl, path); + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); + BookBaseInfoPhp bookBaseInfoPhp = JsonUtil.transferToObj(BookBaseInfoVoStr, BookBaseInfoPhp.class); + if (bookBaseInfoPhp.getData().size() > 0) { + return bookBaseInfoPhp.getData().get(0); + } else { + return null; + } + } + + + public String getpamp(BookBaseInfoBo bo, BookNumberRageBo number, BookBaseInfoDto dto, String page, String per_page) { + String pamp = ""; + + if (bo == null) { + return ""; + } + if (number == null) { + number = new BookNumberRageBo(); + } + if (dto == null) { + dto = new BookBaseInfoDto(); + } + if (StringUtils.isNotEmpty(bo.getId())) { + pamp += "&id=" + bo.getId(); + } + if (StringUtils.isNotEmpty(bo.getIsbn())) { + pamp += "&isbn=" + bo.getIsbn(); + } + if (StringUtils.isNotEmpty(bo.getBookName())) { + pamp += "&book_name=" + bo.getBookName(); + } + if (StringUtils.isNotEmpty(bo.getIsBookPic())) { + pamp += "&book_pic=" + bo.getIsBookPic(); + } + if (StringUtils.isNotEmpty(bo.getAuthor())) { + pamp += "&author=" + bo.getAuthor(); + } + if (StringUtils.isNotEmpty(bo.getEditor())) { + pamp += "&editor=" + bo.getEditor(); + } + if (StringUtils.isNotEmpty(bo.getBindingLayout())) { + pamp += "&binding_layout=" + bo.getBindingLayout(); + } + if (StringUtils.isNotEmpty(bo.getPublisher())) { + pamp += "&publisher=" + bo.getPublisher(); + } + if (StringUtils.isNotEmpty(bo.getEdition())) { + pamp += "&edition=" + bo.getEdition(); + } + if (StringUtils.isNotEmpty(bo.getFormat())) { + pamp += "&format=" + bo.getFormat(); + } + if (StringUtils.isNotEmpty(bo.getLanguages())) { + pamp += "&languages=" + bo.getLanguages(); + } + if (StringUtils.isNotEmpty(bo.getPublicationTime())) { + pamp += "&publication_time=" + bo.getPublicationTime(); + } + if (StringUtils.isNotEmpty(bo.getPrintTime())) { + pamp += "&print_time=" + bo.getPrintTime(); + } + if (StringUtils.isNotEmpty(bo.getPaper())) { + pamp += "&paper=" + bo.getPaper(); + } + if (StringUtils.isNotEmpty(bo.getPages())) { + pamp += "&pages=" + bo.getPages(); + } + if (StringUtils.isNotEmpty(bo.getWordage())) { + pamp += "&wordage=" + bo.getWordage(); + } + if (StringUtils.isNotEmpty(bo.getFixPrice())) { + pamp += "&fix_price=" + bo.getFixPrice(); + } + + if(StringUtils.isNotEmpty(bo.getCategory())){ + pamp += "&category=" + bo.getCategory(); + } + + if (StringUtils.isNotEmpty(bo.getContent())) { + pamp += "&content=" + bo.getContent(); + } + if (StringUtils.isNotEmpty(bo.getRemark())) { + pamp += "&remark=" + bo.getRemark(); + } + if (StringUtils.isNotEmpty(bo.getCreateDept() + "") && bo.getCreateDept() != null) { + pamp += "&create_dept=" + bo.getCreateDept(); + } + if (StringUtils.isNotEmpty(bo.getCreateBy() + "") && bo.getCreateBy() != null) { + pamp += "&create_by=" + bo.getCreateBy(); + } + if (StringUtils.isNotEmpty(bo.getUpdateBy() + "") && bo.getUpdateBy() != null) { + pamp += "&update_by=" + bo.getUpdateBy(); + } + if (StringUtils.isNotEmpty(bo.getKongfz_categories()) && bo.getKongfz_categories() != null) { + pamp += "&kongfz_categories=" + bo.getKongfz_categories(); + } + if (StringUtils.isNotEmpty(bo.getKongfz_include() + "") && bo.getKongfz_include() != null) { + pamp += "&kongfz_include=" + bo.getKongfz_include(); + } + + /** + * 创建时间 + */ +// if(StringUtils.isNotEmpty(dto.getPublicationStartTime()) && StringUtils.isNotEmpty(dto.getPublicationEndTime())){ +// pamp += "&create_time="+dto.getPublicationStartTime()+","+dto.getPublicationEndTime(); +// } + // 选品中心时间筛选 + if (StringUtils.isNotEmpty(dto.getPublicationStartTime()) && dto.getPublicationEndTime() != null) { + bo.setPublicationTime(dto.getPublicationStartTime() + "," + dto.getPublicationEndTime()); + } + if (StringUtils.isNotEmpty(bo.getPublicationTime())) { + String[] split = bo.getPublicationTime().split(","); + if (split.length < 2 || split[0].length() != 4 || split[1].length() != 4) { + throw new IllegalArgumentException("publiction_time 格式错误,应为两个4位年份,例如:2020,2021"); + } + + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + + // 开始时间 + LocalDateTime dateTimestart = LocalDateTime.parse(split[0] + "0101080000", formatter); + long startTime = dateTimestart.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond(); + + // 结束时间 + LocalDateTime dateTimeEnd = LocalDateTime.parse(split[1] + "0101080000", formatter); + long endTime = dateTimeEnd.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond(); + bo.setPublicationTimes(startTime + "," + endTime); + pamp += "&publication_time=" + bo.getPublicationTimes(); + } + + if (StringUtils.isNotEmpty(bo.getUpdateTime() + "") && bo.getUpdateTime() != null) { + pamp += "&update_time=" + bo.getUpdateTime(); + } + + + if (bo.getBuy_counts() != null) { + pamp += "&buy_counts=" + bo.getBuy_counts(); + } + + if (bo.getSell_counts() != null) { + pamp += "&sell_counts=" + bo.getSell_counts(); + } + +// 新增的数据(0-正常、1-异常) + if (bo.getVioBook() != null) { + pamp += "&vio_book=" + bo.getVioBook(); + } + if (bo.getBookSet() != null) { + pamp += "&book_set=" + bo.getBookSet(); + } + if (bo.getOnenumMbooks() != null) { + pamp += "&onenum_mbooks=" + bo.getOnenumMbooks(); + } + if (bo.getIllPublisher() != null) { + pamp += "&ill_publisher=" + bo.getIllPublisher(); + } + if (bo.getIllAuthor() != null) { + pamp += "&ill_author=" + bo.getIllAuthor(); + } + //是否是核价 + if (bo.getIspricing()!=null) { + pamp += "&is_pricing=" + bo.getIspricing(); + } + +// if(StringUtils.isNotEmpty(number.getMin1()) && StringUtils.isNotEmpty(number.getMax1())){ +// pamp += "&buy_count="+number.getMin1()+","+number.getMax1(); +// } +// if(StringUtils.isNotEmpty(number.getMin2()) && StringUtils.isNotEmpty(number.getMax2())){ +// pamp += "&sell_count="+number.getMin2()+","+number.getMax2(); +// } + if (bo.getSaleSelect() != null) { + pamp += "&saleSelect=" + bo.getSaleSelect(); + } + if (StringUtils.isNotEmpty(page)) { + pamp += "&page=" + page; + } + if (StringUtils.isNotEmpty(per_page)) { + pamp += "&per_page=" + per_page; + } + // 拼接分类 categoryType + if (StringUtils.isNotEmpty(bo.getCategoryType())) { + pamp += "&categoryType=" + bo.getCategoryType(); + } + // 拼接图片类型 picType + if (StringUtils.isNotEmpty(bo.getPicType())) { + pamp += "&picType=" + bo.getPicType(); + } + // 拼接套装书 + if (StringUtils.isNotEmpty(String.valueOf(bo.getIsSuit()))) { + pamp += "&isSuit=" + bo.getIsSuit(); + } + // 拼接全部销量范围 + if (StringUtils.isNotEmpty(bo.getTotalSale_range())) { + pamp += "&totalSale_range=" + bo.getTotalSale_range(); + } else if (dto != null && StringUtils.isNotEmpty(dto.getTotalSale_range())) { + pamp += "&totalSale_range=" + dto.getTotalSale_range(); + } + // 拼接页数 + if (StringUtils.isNotEmpty(bo.getPage_count())) { + pamp += "&page_count=" + bo.getPage_count(); + } else if (dto != null && StringUtils.isNotEmpty(dto.getPage_count())) { + pamp += "&page_count=" + dto.getPage_count(); + } + // 拼接字数 + if (StringUtils.isNotEmpty(bo.getWord_count())) { + pamp += "&word_count=" + bo.getWord_count(); + } else if (dto != null && StringUtils.isNotEmpty(dto.getWord_count())) { + pamp += "&word_count=" + dto.getWord_count(); + } + + // 处理店铺类型、是否驳回、是否违规参数 + // is_return 直接传递原值 + if (bo.getIs_return() != null) { + pamp += "&is_return=" + bo.getIs_return(); + } + if (bo.getIs_filter() != null) { + pamp += "&is_filter=" + bo.getIs_filter(); + } + if (bo.getShopType() != null) { + pamp += "&shopType=" + bo.getShopType(); + } + + // is_filter 根据 shopType 转换为特定的格式 + // shopType=0且is_filter=1 -> 100000 + // shopType=1且is_filter=1 -> 010000 + // shopType=2且is_filter=1 -> 001000 + // shopType=3且is_filter=1 -> 000100 + // is_filter=0 或其他情况 -> 000000 +// if (bo.getIs_filter() != null) { +// String filterValue; +// if (bo.getIs_filter() == 1 && bo.getShopType() != null) { +// // 根据shopType转换为对应格式 +// filterValue = switch (bo.getShopType()) { +// case 0 -> "100000"; +// case 1 -> "010000"; +// case 2 -> "001000"; +// case 3 -> "000100"; +// default -> "000000"; +// }; +// } else { +// // is_filter为0或其他情况,默认传递000000 +// filterValue = "000000"; +// } +// pamp += "&is_filter=" + filterValue; +// } + + // shopType 不需要传递到外部接口,只在内部使用 + + pamp = "?" + pamp.substring(1, pamp.length()); + + return pamp; + } + + @Override + public int delectByIsbn(String isbn) { + return baseMapper.delectByIsbn(isbn); + } + + + /** + * 分页查询基础信息列表 + * + * @param pageQuery 分页参数 + * @return 基础信息分页列表 + */ + @Override + public TableDataInfo queryPageList(BookBaseInfoDto dto, BookNumberRageBo number, PageQuery pageQuery) { + + BookBaseInfoBo bo = new BookBaseInfoBo(); + BeanUtils.copyProperties(dto, bo); + bo.setIspricing(false); + bo.setPublicationTime(null); + String goUrl = configService.selectConfigByKey("centerBook.url"); +// String goUrl = "http://192.168.101.213:9009/api"; +// String goUrl = "http://localhost:9009/api"; + String path = "/es/getBookBaseInfoES"+ getpamp(bo, number, dto, pageQuery.getPageNum().toString(), pageQuery.getPageSize().toString()); + System.out.println("根据条件获取中心书库数据集合1:" + path); + String BookBaseInfoVoStr = InterfaceUtils.getInterfaceForBaseInfo(goUrl, path); + System.out.println("根据条件获取中心书库数据集合3:" + BookBaseInfoVoStr); + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeysKeepAbbr(BookBaseInfoVoStr); + System.out.println("经过驼峰转换后的数据:" + BookBaseInfoVoStr); + BookBaseInfoPhp bookBaseInfoPhp = JsonUtil.transferToObj(BookBaseInfoVoStr, BookBaseInfoPhp.class); + Page result = new Page<>(); + result.setRecords(bookBaseInfoPhp.getData()); + result.setTotal(Long.parseLong(bookBaseInfoPhp.getTotal())); + result.setCurrent(Long.parseLong(bookBaseInfoPhp.getCurrentPage())); + result.setSize(Long.parseLong(bookBaseInfoPhp.getPerPage())); + System.out.println("根据条件获取中心书库数据集合4:" + JsonUtil.transferToJson(bookBaseInfoPhp.getData())); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的基础信息列表 + * + * @param bo 查询条件 + * @return 基础信息列表 + */ + @Override + public List queryList(BookBaseInfoBo bo) { + String path = "/bookBase/getBookBaseInfo" + getpamp(bo, null, null, "1", "10"); + String phpUrl = configService.selectConfigByKey("php.url"); + String BookBaseInfoVoStr = InterfaceUtils.getInterface(phpUrl, path); + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); + BookBaseInfoPhp bookBaseInfoPhp = JsonUtil.transferToObj(BookBaseInfoVoStr, BookBaseInfoPhp.class); + System.out.println("根据条件获取中心书库数据集合:" + JsonUtil.transferToJson(bookBaseInfoPhp.getData())); + return bookBaseInfoPhp.getData(); + } + + /** + * 新增基础信息 + * + * @param bo 基础信息 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(BookBaseInfoBo bo) { + BookBaseInfo add = MapstructUtils.convert(bo, BookBaseInfo.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改基础信息 + * + * @param bo 基础信息 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(EditBookInfoBo bo) { +// String path ="/bookBase/setBookBaseInfoBookName"; +// String phpUrl = configService.selectConfigByKey("php.url"); + String path = "/bookBase/putBookBaseName"; + String phpUrl = configService.selectConfigByKey("centerBook.url"); +// String phpUrl = "http://192.168.101.213:9009/api"; +// String phpUrl = "http://localhost:9009/api"; + + Map params = new HashMap<>(); + params.put("id", bo.getId()); + params.put("book_name", bo.getBookName()); + //通过post请求php + String BookBaseInfoVoStr = InterfaceUtils.getInterfacePost(phpUrl, path, params); + // 解析 JSON 字符串 + JSONObject jsonObject = JSONObject.parseObject(BookBaseInfoVoStr); + // 获取 code 字段 + int code = jsonObject.getIntValue("code"); + if (code == 200) { + return true; + } else { + return false; + } + } + + @Override + public Boolean updateByIsbn(BookBaseInfoBo bo) { + return baseMapper.updateByIsbn(bo) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(BookBaseInfo entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除基础信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + @Override + public void importExcel(List list) { + + // 导入excel 获取全部的isbn + List isbnStrs = list.stream().map(BaseInfoExcel::getIsbn).toList(); + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().in(BookBaseInfo::getIsbn, isbnStrs); + // 通过isbn获取 数据库存的信息 + List bookBaseInfos = this.baseMapper.selectList(); + // 取出 所有的isbn信息 + List dbs = bookBaseInfos.stream().map(BookBaseInfo::getIsbn).toList(); + // 取出数据库不存在的 isbn + List notInDBs = isbnStrs.stream().filter(item -> !dbs.contains(item)).toList(); + // 循环一个个新增 + for (String notInDB : notInDBs) { + String url = "https://data.isbn.work/openApi/getInfoByIsbn?appKey=ae1718d4587744b0b79f940fbef69e77&isbn=" + notInDB; + + String res = ""; + try { + res = HttpUtils.sendGet(url, new HashMap<>()); + } catch (Exception e) { + throw new RuntimeException(e); + } + + if (ObjectUtils.isNotEmpty(res)) { + + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); + //字符串转换成对象 + JsonObject obj = gson.fromJson(res, JsonObject.class); + + + if (obj.get("success").toString().equals("true")) { + + //对象及数组 + JsonObject asJsonArray = obj.get("data").getAsJsonObject(); + + String isbn = asJsonArray.get(BookParamsEnum.ISBN.getParams()).getAsString(); + String bookName = asJsonArray.get(BookParamsEnum.BOOK_NAME.getParams()).getAsString(); + String author = asJsonArray.get(BookParamsEnum.AUTHOR.getParams()).getAsString(); + String press = asJsonArray.get(BookParamsEnum.PRESS.getParams()).getAsString(); + String pressDate = asJsonArray.get(BookParamsEnum.PRESS_DATE.getParams()).getAsString(); +// String pressPlace = asJsonArray.get(BookParamsEnum.PRESS_PLACE.getParams()).getAsString(); + + // todo 上传图片到oss + String pictures = asJsonArray.get(BookParamsEnum.PICTURES.getParams()).getAsString(); + String bookDesc = asJsonArray.get(BookParamsEnum.BOOK_DESC.getParams()).getAsString(); + String binding = asJsonArray.get(BookParamsEnum.BINDING.getParams()).getAsString(); + String language = asJsonArray.get(BookParamsEnum.LANGUAGE.getParams()).getAsString(); + String format = asJsonArray.get(BookParamsEnum.FORMAT.getParams()).getAsString(); + String pages = asJsonArray.get(BookParamsEnum.PAGES.getParams()).getAsString(); + String edition = asJsonArray.get(BookParamsEnum.EDITION.getParams()).getAsString(); + String words = asJsonArray.get(BookParamsEnum.WORDS.getParams()).getAsString(); + + + BookBaseInfo bookBaseInfo = new BookBaseInfo(); + bookBaseInfo.setBookName(bookName); + // todo 上传图片到oss +// bookBaseInfo.setBookPic(); + bookBaseInfo.setIsbn(isbn); // isbn + bookBaseInfo.setAuthor(author); // 作者 +// bookBaseInfo.setEditor(author); 编辑 + bookBaseInfo.setBindingLayout(binding); //装帧 + bookBaseInfo.setPublisher(press); // 出版社 + bookBaseInfo.setEdition(edition); // 版次 + bookBaseInfo.setFormat(format); // 开本 + bookBaseInfo.setPublicationTime(pressDate); //出版日期 +// bookBaseInfo.setPaper(page); 纸张 + bookBaseInfo.setPages(pages); //页数 + bookBaseInfo.setWordage(words); //字数 +// bookBaseInfo.setFixPrice(pages); 定价 +// bookBaseInfo.setContent(pressDate); 内容 + bookBaseInfo.setRemark(bookDesc); // 备注(书本描述) + bookBaseInfo.setLanguages(language); + + + bookBaseInfo.setPublicationTime(pressDate); + +// baseList.add(bookBaseInfo); + baseMapper.insert(bookBaseInfo); + + } + ; + System.out.println(res); + } + + + } + } + + @Override + public Map getList() { + + List list1 = baseMapper.getList1(); + List list2 = baseMapper.getList1(); + Map map = new HashMap<>(); + + map.put("list1", list1); + map.put("list2", list2); + + return map; + } + + @Override + public BookBaseInfoVo getIsbnInfo(String isbn) { + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("isbn", isbn); + queryWrapper.eq("del_flag", "0"); + return baseMapper.selectVoByIsdn(queryWrapper); + } + + @Override + public BookBaseInfoVo getIsbnList(String isbn) { + BookBaseInfoVo bookBaseInfoVo = baseMapper.selectIsbnList(isbn); + return bookBaseInfoVo; + } + + @Override + public List getBookListByBookName(String bookName) { + return baseMapper.selectByBookName(bookName); + } + + @Override + public List selectBookPicList() { + return baseMapper.selectBookPic(); + } + + @Override + public List queryBookPicList(BookBaseInfoBo bo) { + // 使用分页方式获取所有数据 + List allData = new ArrayList<>(); + int pageSize = 1000; // 每页获取1000条数据 + int currentPage = 1; + boolean hasMore = true; + + while (hasMore) { + String path = "/bookBase/getBookBaseInfo" + getpamp(bo, null, null, + String.valueOf(currentPage), String.valueOf(pageSize)); + String phpUrl = configService.selectConfigByKey("php.url"); + String BookBaseInfoVoStr = InterfaceUtils.getInterface(phpUrl, path); + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); + BookBaseInfoPhp bookBaseInfoPhp = JsonUtil.transferToObj(BookBaseInfoVoStr, BookBaseInfoPhp.class); + + List pageData = bookBaseInfoPhp.getData(); + if (pageData != null && !pageData.isEmpty()) { + allData.addAll(pageData); + currentPage++; + } else { + hasMore = false; + } + + // 添加日志记录进度 + System.out.println("已获取 " + allData.size() + " 条数据"); + } + + return allData; + } + + // 写一个 异步的 + + public String getData(JsonObject asJsonArray, String params) { + + String res = ""; + try { + + res = asJsonArray.get(params).getAsString(); + + } catch (Exception e) { + e.printStackTrace(); + } + return res; + + } + + //批量设置违规信息 + @Override + public int updateByIllge(IllBaseInfoBo bo) { + // post setBookBaseInfoToIll + //将bo.getids改成列表或数组 + + + String ids = bo.getIds().stream().map(Object::toString).collect(Collectors.joining(",")); + String path = "/bookBase/putBookBaseInfoToIll"; + String phpUrl = configService.selectConfigByKey("centerBook.url"); +// String phpUrl = "http://192.168.101.213:9009/api"; +// String phpUrl = "http://localhost:9009/api"; +// String path ="/bookBase/setBookBaseInfoToIll"; +// String phpUrl = configService.selectConfigByKey("php.url"); + + Map params = new HashMap<>(); + params.put("ids", ids); + params.put("vio_book", bo.getVioBook()); + params.put("book_set", bo.getBookSet()); + params.put("onenum_mbooks", bo.getOnenumMbooks()); + params.put("ill_publisher", bo.getIllPublisher()); + params.put("ill_author", bo.getIllAuthor()); + //通过post请求php + String BookBaseInfoVoStr = InterfaceUtils.getInterfacePost(phpUrl, path, params); + // 解析 JSON 字符串 + JSONObject jsonObject = JSONObject.parseObject(BookBaseInfoVoStr); + // 获取 code 字段 + int code = jsonObject.getIntValue("code"); + if (code == 200) { + return 1; + } else { + return 0; + } + } + + @Override + public TableDataInfo queryPagePricingList(BookBaseInfoDto dto, BookNumberRageBo number, PageQuery pageQuery) { + BookBaseInfoBo bo = new BookBaseInfoBo(); + BeanUtils.copyProperties(dto, bo); + bo.setIspricing(true); + bo.setIllAuthor(0); + bo.setIllPublisher(0); + bo.setOnenumMbooks(0); + bo.setBookSet(0); + bo.setVioBook(0); + bo.setPublicationTime(null); +// String path = "/bookBase/getBookBaseInfo" + getpamp(bo, number, dto, pageQuery.getPageNum().toString(), pageQuery.getPageSize().toString()); +// String phpUrl = configService.selectConfigByKey("php.url"); +// String path = "/bookBase/getRandomBookBaseInfo" + getpamp(bo, number, dto, pageQuery.getPageNum().toString(), pageQuery.getPageSize().toString()); + String phpUrl = configService.selectConfigByKey("centerBook.url"); +// String phpUrl = "http://192.168.101.213:9009/api"; +// String phpUrl = "http://localhost:9009/api"; + String path = "/es/getBookBaseInfoES" + getpamp(bo, number, dto, pageQuery.getPageNum().toString(), pageQuery.getPageSize().toString()); + String BookBaseInfoVoStr = InterfaceUtils.getInterface(phpUrl, path); + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); + BookBaseInfoPhp bookBaseInfoPhp = JsonUtil.transferToObj(BookBaseInfoVoStr, BookBaseInfoPhp.class); + + + + + Page result = new Page<>(); + //将数据转换成BaseInfoPricingVo + List records1 = new ArrayList<>(bookBaseInfoPhp.getData()); // 返回可修改的 ArrayList + List records = records1.stream().map(item -> { + + return new BaseInfoPricingVo(item.getBookName(), item.getIsbn(), "0", item.getBookSet(), item.getPublisher(), item.getAuthor()); +// if (item.getBookSet() != null && item.getBookSet() == 1) { +// return new BaseInfoPricingVo(item.getBookName(), item.getIsbn(), "0", 1, item.getPublisher(), item.getAuthor()); +// } else if (item.getBookSet() != null && item.getBookSet() == 0) { +// return new BaseInfoPricingVo(item.getBookName(), item.getIsbn(), "0", 0, item.getPublisher(), item.getAuthor()); +// } else { +// return new BaseInfoPricingVo(item.getBookName(), item.getIsbn(), "0", 0, item.getPublisher(), item.getAuthor()); +// } + + }).toList(); + result.setRecords(records); + result.setTotal(Long.parseLong(bookBaseInfoPhp.getTotal())); + result.setCurrent(Long.parseLong(bookBaseInfoPhp.getCurrentPage())); + result.setSize(Long.parseLong(bookBaseInfoPhp.getPerPage())); + return TableDataInfo.build(result); + } + + + /** + * 加密链接 + * + * @param bo + * @param pageQuery + * @return + */ + @Override + public String pricingLink(BookBaseInfoBo bo, PageQuery pageQuery) { + //获取当前用户id + Long userId = LoginHelper.getUserId(); + int total = bo.getTotal(); // 总数据量,例如:321881 + if (total == 0){ + return "暂无数据"; + } + int numbers = bo.getNumbers() * 100; + List taskMapList = new ArrayList<>(); + + List shopIds = bo.getShopIds(); + for(Long shopId : shopIds){ + //获取时间戳 + long timeStamp = System.currentTimeMillis(); + ShopVo shopVo = shopMapper.selectVoById(shopId); + String fileName = getDataName(bo, userId, timeStamp); + Task task = getTask(shopId.toString(), shopVo.getShopName(), fileName, "0", "1", "0", userId, Long.parseLong(String.valueOf(total))); + taskMapper.insert(task); + + Map taskMap = new HashMap(); + taskMap.put("taskId", task.getId().toString()); + taskMap.put("shopId", shopId.toString()); + taskMap.put("shopType",shopVo.getShopType()); + taskMapList.add(taskMap); + } + Map resMap = new HashMap<>(); + resMap.put("number", numbers+""); + resMap.put("total", total+""); + //获取查询条件url + String url = getUrl(bo); + resMap.put("qureyApiUrl",url); + resMap.put("taskMapList", taskMapList); + + return pricingUrlUtil.getPricingUrl(JsonUtil.transferToJson(resMap)); + } + + + /** + * 拼接文件名 + * + * @param bo + * @param userId + * @param timeStamp + * @return + */ + private String getDataName(BookBaseInfoBo bo, Long userId, long timeStamp) { + StringBuilder dataName = new StringBuilder(); + dataName.append("中心书库发布"); + if (bo.getBookName() != null && !bo.getBookName().equals("")) { + dataName.append("bN_").append(bo.getBookName()).append(";"); + } + if (bo.getBookPic() != null && !bo.getBookPic().equals("")) { + dataName.append("bP_").append(bo.getBookPic()).append(";"); + } + if (bo.getIsbn() != null && !bo.getIsbn().equals("")) { + dataName.append("isbn_").append(bo.getIsbn()).append(";"); + } + if (bo.getAuthor() != null && !bo.getAuthor().equals("")) { + dataName.append("Aut_").append(bo.getAuthor()).append(";"); + } + if (bo.getPublisher() != null && !bo.getPublisher().equals("")) { + dataName.append("Pub_").append(bo.getPublisher()).append(";"); + } + if (bo.getPublicationTimes() != null && !bo.getPublicationTimes().equals("")) { + dataName.append("PT_").append(bo.getPublicationTimes()).append(";"); + } + if (bo.getVioBook() != null) { + dataName.append("VB_").append(bo.getVioBook()).append(";"); + } + if (bo.getBookSet() != null) { + dataName.append("BS_").append(bo.getBookSet()).append(";"); + } + if (bo.getOnenumMbooks() != null) { + dataName.append("OMS_").append(bo.getOnenumMbooks()).append(";"); + } + if (bo.getIllPublisher() != null) { + dataName.append("IllP_").append(bo.getIllPublisher()).append(";"); + } + if (bo.getIllAuthor() != null) { + dataName.append("IA_").append(bo.getIllAuthor()).append(";"); + } + if (bo.getBuy_counts() != null && !bo.getBuy_counts().equals("")) { + dataName.append("BCS_").append(bo.getBuy_counts()).append(";"); + } + if (bo.getSell_counts() != null && !bo.getSell_counts().equals("")) { + dataName.append("SCS_").append(bo.getSell_counts()).append(";"); + } + dataName.append("userId_").append(userId).append(";"); + dataName.append("rand_").append(timeStamp); + return dataName.toString(); + } + + /** + * 拼接 url + * + * @param bo + * @param + * @param + * @return + */ + private String getUrl(BookBaseInfoBo bo) { + String path = "https://api.buzhiyushu.cn"; + StringBuilder url = new StringBuilder(); + url.append(path).append("/zhishu/baseInfo/pricing/list?"); + + if (bo.getBookName() != null && !bo.getBookName().equals("")) { + String bookName = urlJiami(bo.getBookName()); + url.append("bookName=").append(bookName).append("&"); + } + if (bo.getBookPic() != null && !bo.getBookPic().equals("")) { + String bookPic = urlJiami(bo.getBookPic()); + url.append("bookPic=").append(bookPic).append("&"); + } + if (bo.getIsbn() != null && !bo.getIsbn().equals("")) { + String isbn = urlJiami(bo.getIsbn()); + url.append("isbn=").append(isbn).append("&"); + } + if (bo.getAuthor() != null && !bo.getAuthor().equals("")) { + String author = urlJiami(bo.getAuthor()); + url.append("author=").append(author).append("&"); + } + if (bo.getPublisher() != null && !bo.getPublisher().equals("")) { + String publisher = urlJiami(bo.getPublisher()); + url.append("publisher=").append(publisher).append("&"); + } + if (bo.getVioBook() != null) { + String vioBook = urlJiami(bo.getVioBook()); + url.append("vio_book=").append(vioBook).append("&"); + } + if (bo.getBookSet() != null) { + String bookSet = urlJiami(bo.getBookSet()); + url.append("book_set=").append(bookSet).append("&"); + } + if (bo.getOnenumMbooks() != null) { + String onenumMbooks = urlJiami(bo.getOnenumMbooks()); + url.append("onenum_mbooks=").append(onenumMbooks).append("&"); + } + if (bo.getIllPublisher() != null) { + String illPublisher = urlJiami(bo.getIllPublisher()); + url.append("ill_publisher=").append(illPublisher).append("&"); + } + + if (bo.getIsBookPic() != null) { + String isBookPic = urlJiami(bo.getIsBookPic()); + url.append("book_pic=").append(isBookPic).append("&"); + } + + if(bo.getSaleSelect()!=null){ + String saleSelect = urlJiami(bo.getSaleSelect()); + url.append("saleSelect=").append(saleSelect).append("&"); + } + if(bo.getCategory()!=null&&!bo.getCategory().equals("")){ + String category = urlJiami(bo.getCategory()); + url.append("category=").append(category).append("&"); + } + if (bo.getIllAuthor() != null) { + String illAuthor = urlJiami(bo.getIllAuthor()); + url.append("ill_author=").append(illAuthor).append("&"); + } + if (bo.getPublicationTimes() != null && !bo.getPublicationTimes().equals("")) { + String publictionTimes = urlJiami(bo.getPublicationTimes()); + url.append("publiction_times=").append(publictionTimes).append("&"); + } + if (bo.getBuy_counts() != null && !bo.getBuy_counts().equals("")) { + String buyCounts = urlJiami(bo.getBuy_counts()); + url.append("buy_counts=").append(buyCounts).append("&"); + } + if (bo.getSell_counts() != null && !bo.getSell_counts().equals("")) { + String sellCounts = urlJiami(bo.getSell_counts()); + url.append("sell_counts=").append(sellCounts); + } + + // 添加缺失的参数 + if (bo.getShopType() != null) { + String shopType = urlJiami(bo.getShopType()); + url.append("&shopType=").append(shopType); + } + if (bo.getIs_return() != null) { + String isReturn = urlJiami(bo.getIs_return()); + url.append("&is_return=").append(isReturn); + } + if (bo.getIs_filter() != null) { + String isFilter = urlJiami(bo.getIs_filter()); + url.append("&is_filter=").append(isFilter); + } + if (bo.getCategoryType() != null && !bo.getCategoryType().equals("")) { + String categoryType = urlJiami(bo.getCategoryType()); + url.append("&categoryType=").append(categoryType); + } + if (bo.getIsSuit() != null) { + String isSuit = urlJiami(bo.getIsSuit()); + url.append("&isSuit=").append(isSuit); + } + if (bo.getTotalSale_range() != null && !bo.getTotalSale_range().equals("")) { + String totalSaleRange = urlJiami(bo.getTotalSale_range()); + url.append("&totalSale_range=").append(totalSaleRange); + } + if (bo.getPage_count() != null && !bo.getPage_count().equals("")) { + String page_count = urlJiami(bo.getPage_count()); + url.append("&page_count=").append(page_count); + } + if (bo.getWord_count() != null && !bo.getWord_count().equals("")) { + String word_count = urlJiami(bo.getWord_count()); + url.append("&word_count=").append(word_count); + } + if (bo.getKongfz_categories() != null && !bo.getKongfz_categories().equals("")) { + String kongfzCategories = urlJiami(bo.getKongfz_categories()); + url.append("&kongfz_categories=").append(kongfzCategories); + } + if (bo.getKongfz_include() != null) { + String kongfzInclude = urlJiami(bo.getKongfz_include()); + url.append("&kongfz_include=").append(kongfzInclude); + } + + +// try { +// String encodedText = URLEncoder.encode(url.toString(), StandardCharsets.UTF_8.toString()); +// return encodedText; +// } catch (UnsupportedEncodingException e) { +// throw new RuntimeException(e); +// } + return url.toString(); + } + + /** + * 参数加密 + * + * @param obj + * @return + */ + private String urlJiami(Object obj) { + try { + String encodedText = URLEncoder.encode(obj.toString(), StandardCharsets.UTF_8.toString()); + return encodedText; + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + /** + * 解密 + * + * @param link + * @return + */ + @Override + public Map pricingLinkDec(String link) { + try { + String dec = pricingUrlUtil.decrypt(link); + return JsonUtil.transferToObj(dec, Map.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 获取用户是否是会员 + * + * @return + */ + @Override + public Boolean getUserVip(Integer type) { + //获取当前用户id + Long userId = LoginHelper.getUserId(); + String path = "/user/vipInfo" + "?user_id=" + userId + "&type=" + type.toString(); + String goUrl = configService.selectConfigByKey("go.url"); + String BookBaseInfoVoStr = InterfaceUtils.getInterface(goUrl, path); + BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); + JSONObject jsonObject = JSONObject.parseObject(BookBaseInfoVoStr); + boolean isVip = jsonObject.getJSONObject("data").getBoolean("isVip"); + System.out.println(isVip); + return isVip; + } + + + /** + * @param shopIds 店铺id + * @param shopNames 店铺名称 + * @param fileName 文件名称 + * @param satus 状态 + * @param taskType 任务类型 + * @param taskStatus 任务状态 + * @param userId 用户id + * @param currentBatchSize 执行数据条数 + * @return + */ + public Task getTask(String shopIds, String shopNames, String fileName, String satus, String taskType, String taskStatus, Long userId, Long currentBatchSize) { + Task task = new Task(); + task.setShopIds(shopIds); + task.setShopNames(shopNames); + task.setDataNum(currentBatchSize); + task.setStatus(satus); + task.setTaskType(taskType); + task.setFileName(fileName); + task.setTaskStatus(taskStatus); + task.setCreateBy(userId); + task.setUpdateBy(userId); + return task; + } + + + /** + * 创建任务 + * + * @param bo + * @return + */ + @Override + public Map insertTask(TaskBo bo) { + // 拆分字符串为 List + List idList = Arrays.stream(bo.getShopIds().split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .map(Long::valueOf) + .toList(); + List shopList = shopMapper.selectShopName(idList); + //获取shopList中的shopName和create_by + List shopNameList = shopList.stream() + .map(ShopVo::getShopName) + .toList(); + String shopName = String.join(",", shopNameList); + Long createBy = shopList.get(0).getCreateBy(); + + String dataName = "临时生成任务名"; + + if(bo.getTaskType().equals("UPDATE_GOODS_PRICE")){ + dataName = "改价任务"; + if(bo.getFileName() != null && StringUtils.isNotEmpty(bo.getFileName())){ + dataName += bo.getFileName(); + } + }else{ + BookBaseInfoBo baseInfoBo = new BookBaseInfoBo(); + long timeStamp = System.currentTimeMillis(); + dataName = getDataName(baseInfoBo, createBy, timeStamp); + } + Task task = getTask(bo.getShopIds(), shopName, dataName, bo.getStatus(), bo.getTaskType(), bo.getTaskStatus(), createBy, bo.getDataNum()); + int insert = taskMapper.insert(task); + task.getId(); + Map params = new HashMap<>(); + params.put("taskId", task.getId().toString()); + params.put("fileName", dataName); + if (insert > 0) { + return params; + } + return null; + } + + + @Override + public int addNewTask(Task task){ + return taskMapper.insert(task); + } + + + @Override + public Map setBalance() { + Map paramsVo = new HashMap<>(); + Long userId = LoginHelper.getUserId(); + + // 1. 获取高级搜索VIP价格(外部API) + Map params1 = new HashMap<>(); + params1.put("user_id", userId); + String path = "/user/getVipPrice"; + String goUrl = configService.selectConfigByKey("go.url"); + String BookBaseInfoVoStr1 = InterfaceUtils.getInterfaceGet(goUrl, path, params1); + BookBaseInfoVoStr1 = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr1); + JSONObject jsonObject = JSONObject.parseObject(BookBaseInfoVoStr1); + String price = jsonObject.getJSONObject("data").getString("price"); + BigDecimal price1 = new BigDecimal(price); + paramsVo.put("price", price1); + + // 2. 查询用户余额并校验 + SysUser sysUser = sysUserMapper.selectUserById(userId); + if (sysUser == null) { + paramsVo.put("status", 303); + paramsVo.put("message", "用户不存在"); + return paramsVo; + } + if (price1.compareTo(sysUser.getBalance()) > 0) { + paramsVo.put("status", 303); + paramsVo.put("message", "余额不足,付款金额:" + price1); + return paramsVo; + } + + // 3. 先调用外部API创建VIP(带重试),成功后才扣款 + Map vipResult = insertButtonVipWithRetry(userId, price1, 3); + String code = vipResult.get("code").toString(); + + if (!"200".equals(code)) { + // 外部API失败,不扣款,直接返回错误 + log.error("开通高级搜索VIP失败,不扣款: userId={}, price={}, error={}", userId, price1, vipResult.get("message")); + paramsVo.put("status", 400); + paramsVo.put("message", "开通VIP失败:" + vipResult.get("message")); + return paramsVo; + } + + // 4. 外部API成功,再扣款 + BigDecimal balanceOld = sysUser.getBalance(); + BigDecimal balanceNew = balanceOld.subtract(price1); + sysUser.setBalance(balanceNew); + int updateBalance = sysUserMapper.updateById(sysUser); + + if (updateBalance > 0) { + // 5. 写扣款日志到 t_user_recharge + UserRechargeBo rechargeBo = new UserRechargeBo(); + rechargeBo.setUserId(userId); + rechargeBo.setRechargPrice(price1); + rechargeBo.setRechargType("6"); + rechargeBo.setStatus("6"); + rechargeBo.setCommission(BigDecimal.ZERO); + rechargeBo.setLogTxt("高级搜索会员扣款"); + rechargeBo.setOriginalPrice(balanceOld); + rechargeBo.setUpdatePrice(balanceNew); + rechargeBo.setCreateBy(userId); + rechargeBo.setUpdateBy(userId); + userRechargeService.insertByBo(rechargeBo); + + log.info("高级搜索会员扣款成功: userId={}, price={}, balance: {}→{}", userId, price1, balanceOld, balanceNew); + paramsVo.put("status", 200); + paramsVo.put("message", "扣款成功"); + } else { + // 6. 补偿:VIP已开通但扣款失败,记录异常日志待人工处理 + log.error("【需人工处理】VIP已开通但扣款失败: userId={}, price={}, 需手动从余额扣除{}", userId, price1, price1); + paramsVo.put("status", 500); + paramsVo.put("message", "扣款失败,请尽快联系管理员处理(VIP已开通但未扣款)"); + } + + return paramsVo; + } + + /** + * 带重试机制调用外部VIP创建接口 + * 先调用外部API,成功后返回,失败则重试(最多maxRetries次) + */ + private Map insertButtonVipWithRetry(Long userId, BigDecimal price1, int maxRetries) { + Map result = new HashMap<>(); + + for (int i = 0; i < maxRetries; i++) { + try { + // 构建请求参数 + Calendar calendar = Calendar.getInstance(); + long nowTimeStamp = System.currentTimeMillis(); + calendar.setTimeInMillis(nowTimeStamp); + calendar.add(Calendar.MONTH, 1); + long timeStamp = calendar.getTimeInMillis(); + + Map params = new HashMap<>(); + params.put("user_id", userId); + params.put("rec_business_config_id", 1); + params.put("constraint_json", "{}"); + params.put("expiration_date", timeStamp); + params.put("title", "高级搜索会员"); + params.put("settled_cost_key", ""); + params.put("kickback_type", 2); + params.put("kickback_value", "0"); + params.put("resource_cost_type", 2); + params.put("resource_cost_value", 0); + params.put("service_rate", 0); + params.put("price", price1); + params.put("state", 1); + params.put("note", ""); + params.put("created_by", userId); + params.put("created_time", nowTimeStamp); + params.put("updated_by", userId); + params.put("updated_time", nowTimeStamp); + + String path1 = "/user/insertVipInfo"; + String goUrl = configService.selectConfigByKey("go.url"); + String responseStr = InterfaceUtils.getInterfacePost(goUrl, path1, params); + responseStr = JsonObjUtil.jsonToMapWithCamelKeys(responseStr); + JSONObject jsonObject1 = JSONObject.parseObject(responseStr); + String code = jsonObject1.getString("code"); + + result.put("code", code); + result.put("message", "200".equals(code) ? "成功" : "外部接口返回失败"); + if ("200".equals(code)) { + return result; // 成功直接返回 + } + // 接口返回非200,继续重试 + log.warn("外部VIP创建接口返回非200: code={}, 第{}次重试", code, i + 1); + } catch (Exception e) { + log.error("调用外部VIP创建接口异常,第{}次重试: {}", i + 1, e.getMessage()); + if (i < maxRetries - 1) { + try { + Thread.sleep(1000L * (i + 1)); // 递增等待 1s, 2s, 3s + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + break; + } + } + } + } + + // 所有重试均失败 + result.put("code", "500"); + result.put("message", "外部服务调用失败,已重试" + maxRetries + "次"); + return result; + } + + /** + * 兼容旧调用方(如 WxPayChatControlle),内部委托给带重试的新方法 + */ + public Map InsertButtonVip(Map paramsVo, BigDecimal price1) { + Long userId = LoginHelper.getUserId(); + Map vipResult = insertButtonVipWithRetry(userId, price1, 3); + String code = vipResult.get("code").toString(); + if ("200".equals(code)) { + paramsVo.put("status", 200); + paramsVo.put("message", "扣款成功"); + } else { + paramsVo.put("status", 400); + paramsVo.put("message", vipResult.get("message")); + } + return paramsVo; + } + + //新增会员 + @Override + public void insertUserInfo(UserRechargeBo bo,String title,Integer payType,Integer price) { + Long userId = LoginHelper.getUserId(); + // 获取当前日历实例 + Calendar calendar = Calendar.getInstance(); + long nowTimeStamp = System.currentTimeMillis(); + // 设置日历为当前时间 + calendar.setTimeInMillis(nowTimeStamp); + if (payType == 1) { + // payType为1时,添加一年 + calendar.add(Calendar.YEAR, 1); + } else { + // 其他情况,添加一个月 + calendar.add(Calendar.MONTH, 1); + } + long timeStamp = calendar.getTimeInMillis(); + Map params = new HashMap<>(); + params.put("id",bo.getId()); + params.put("user_id", userId); + params.put("rec_business_config_id", 2); + params.put("constraint_json", "{}"); // 必须传,可以是空JSON + params.put("expiration_date", timeStamp); // 30天后 + params.put("title", title); + params.put("settled_cost_key", ""); // 必须传,可以是空字符串 + params.put("kickback_type", 2); + params.put("kickback_value", "0"); // 必须传,默认0(根据业务调整) + params.put("resource_cost_type", 2); + params.put("resource_cost_value", 0); // 必须传,默认0(根据业务调整) + params.put("service_rate", 0); // 必须传,默认0(根据业务调整) + params.put("price",price); // 你的业务价格(分) + params.put("pay_status",1); + params.put("type",payType); + params.put("state", 1); + params.put("note", ""); // 必须传,可以是空字符串 + params.put("created_by", userId); + params.put("created_time", nowTimeStamp); + params.put("updated_by", userId); + params.put("updated_time", nowTimeStamp); + String path1 = "/user/insertVipInfo"; + String goUrl = configService.selectConfigByKey("go.url"); + String BookBaseInfoVoStr = InterfaceUtils.getInterfacePost(goUrl, path1, params); + } + +@Override +public Map getImageDite(Long isbn) { + Map result = new HashMap<>(); + result.put("success", false); // 默认失败 + + if (isbn == null) { + result.put("error", "ISBN不能为空"); + return result; + } + + String phpUrl = "http://175.27.224.66:9999/api/image-url?isbn=" + isbn; + + try { + // 使用 RestTemplate 替代 InterfaceUtils(推荐) + RestTemplate restTemplate = new RestTemplate(); + + // 设置超时(5秒连接,10秒读取) + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(6000); + factory.setReadTimeout(12000); + restTemplate.setRequestFactory(factory); + + // 发送 GET 请求 + ResponseEntity response = restTemplate.getForEntity(phpUrl, String.class); + + if (response.getStatusCode() != HttpStatus.OK) { + result.put("error", "PHP服务返回异常状态码: " + response.getStatusCode()); + return result; + } + + // 解析 JSON + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = mapper.readTree(response.getBody()); + + boolean success = rootNode.path("success").asBoolean(); + result.put("success", success); + + if (success) { + String imageUrl = rootNode.path("data").path("image_url").asText(); + result.put("image_url", imageUrl); + } else { + result.put("error", "PHP服务返回失败"); + } + } catch (ResourceAccessException e) { + // 超时或连接失败 + result.put("error", "PHP服务不可用: " + e.getMessage()); + } catch (Exception e) { + // 其他异常(JSON解析错误等) + result.put("error", "获取图片失败: " + e.getMessage()); + } + + return result; +} + private String parseBookPicNew(Object bookPicNewObj) { + ObjectMapper objectMapper = new ObjectMapper(); + if (bookPicNewObj == null) { + return null; + } + try { + if (bookPicNewObj instanceof String) { + // 处理字符串类型的 JSON + String jsonString = (String) bookPicNewObj; + // 检查字符串是否为空或不是有效的JSON格式 + if (jsonString.trim().isEmpty()) { + return null; + } + Map map = objectMapper.readValue(jsonString, + new TypeReference>() {}); + return map != null ? (String) map.get("pddPath") : null; + } else if (bookPicNewObj instanceof Map) { + // 处理已经是 Map 的情况 + @SuppressWarnings("unchecked") + Map map = (Map) bookPicNewObj; + Object pddPathObj = map.get("pddPath"); + if (pddPathObj instanceof String) { + return (String) pddPathObj; + } else if (pddPathObj != null) { + return pddPathObj.toString(); // 或者其他转换逻辑 + } + return null; + } + } catch (Exception e) { + // 更详细的错误信息 + System.err.println("解析 bookPicNew 失败: " + e.getMessage()); + // e.printStackTrace(); // 根据需要决定是否打印完整堆栈 + } + return null; + } +} + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ExcelTaskServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ExcelTaskServiceImpl.java new file mode 100644 index 0000000..61e2c04 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ExcelTaskServiceImpl.java @@ -0,0 +1,147 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.ExcelTask; +import org.dromara.zhishu.domain.bo.ExcelTaskBo; +import org.dromara.zhishu.domain.vo.ExcelTaskVo; +import org.dromara.zhishu.mapper.ExcelTaskMapper; +import org.dromara.zhishu.service.IExcelTaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 任务列表Service业务层处理 + * + * @author yxy + * @date 2025-03-21 + */ +@RequiredArgsConstructor +@Service +public class ExcelTaskServiceImpl implements IExcelTaskService { + + @Autowired + private final ExcelTaskMapper baseMapper; + + /** + * 查询任务列表 + * + * @param id 主键 + * @return 任务列表 + */ + @Override + public ExcelTaskVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询任务列表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 任务列表分页列表 + */ + @Override + public TableDataInfo queryPageList(ExcelTaskBo bo, PageQuery pageQuery) { + //获取当前用户id + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVo(pageQuery.build(), bo); + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的任务列表列表 + * + * @param bo 查询条件 + * @return 任务列表列表 + */ + @Override + public List queryList(ExcelTaskBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); +// return null; + } + + private LambdaQueryWrapper buildQueryWrapper(ExcelTaskBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(ExcelTask::getId); + lqw.eq(StringUtils.isNotBlank(bo.getTaskType()), ExcelTask::getTaskType, bo.getTaskType()); + lqw.eq(StringUtils.isNotBlank(bo.getDepotIds()), ExcelTask::getDepotIds, bo.getDepotIds()); + lqw.like(StringUtils.isNotBlank(bo.getFileName()), ExcelTask::getFileName, bo.getFileName()); + lqw.eq(bo.getDataNum() != null, ExcelTask::getDataNum, bo.getDataNum()); + lqw.eq(StringUtils.isNotBlank(bo.getTaskStatus()), ExcelTask::getTaskStatus, bo.getTaskStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ExcelTask::getStatus, bo.getStatus()); + return lqw; +// return null; + } + + + /** + * 新增任务列表 + * + * @param bo 任务列表 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ExcelTaskBo bo) { + ExcelTask add = MapstructUtils.convert(bo, ExcelTask.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + + /** + * 修改任务列表 + * + * @param bo 任务列表 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ExcelTaskBo bo) { + ExcelTask update = MapstructUtils.convert(bo, ExcelTask.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ExcelTask entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除任务列表信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + baseMapper.deleteExcelTask(ids); + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/GoodsAutoFailServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/GoodsAutoFailServiceImpl.java new file mode 100644 index 0000000..5d69176 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/GoodsAutoFailServiceImpl.java @@ -0,0 +1,156 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.GoodsAutoFailBo; +import org.dromara.zhishu.domain.vo.GoodsAutoFailVo; +import org.dromara.zhishu.domain.GoodsAutoFail; +import org.dromara.zhishu.mapper.GoodsAutoFailMapper; +import org.dromara.zhishu.service.IGoodsAutoFailService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 自动发布失败Service业务层处理 + * + * @author yxy + * @date 2025-09-29 + */ +@RequiredArgsConstructor +@Service +public class GoodsAutoFailServiceImpl implements IGoodsAutoFailService { + + private final GoodsAutoFailMapper baseMapper; + + /** + * 查询自动发布失败 + * + * @param id 主键 + * @return 自动发布失败 + */ + @Override + public GoodsAutoFailVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + + /** + * 获取数据总数 + * @param bo + * @return + */ + @Override + public Long selectAllNum(GoodsAutoFailBo bo){ + return baseMapper.selectAllNum(bo); + } + + /** + * 分页查询自动发布失败列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 自动发布失败分页列表 + */ + @Override + public TableDataInfo queryPageList(GoodsAutoFailBo bo, PageQuery pageQuery) { + + Long userId = LoginHelper.getUserId(); + + if(userId != 1){ + bo.setUserId(userId); + } + + bo.setPageNum((pageQuery.getPageNum() - 1) * pageQuery.getPageSize()); + bo.setPageSize(pageQuery.getPageSize()); + List list = baseMapper.selectList(bo); + + Page page = new Page<>(bo.getPageNum(), bo.getPageSize()); + page.setRecords(list); + + page.setTotal(selectAllNum(bo)); + + return TableDataInfo.build(page); + } + + /** + * 查询符合条件的自动发布失败列表 + * + * @param bo 查询条件 + * @return 自动发布失败列表 + */ + @Override + public List queryList(GoodsAutoFailBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(GoodsAutoFailBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(GoodsAutoFail::getId); + lqw.eq(bo.getGoodsId() != null, GoodsAutoFail::getGoodsId, bo.getGoodsId()); + return lqw; + } + + /** + * 新增自动发布失败 + * + * @param bo 自动发布失败 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(GoodsAutoFailBo bo) { + GoodsAutoFail add = MapstructUtils.convert(bo, GoodsAutoFail.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改自动发布失败 + * + * @param bo 自动发布失败 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(GoodsAutoFailBo bo) { + GoodsAutoFail update = MapstructUtils.convert(bo, GoodsAutoFail.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(GoodsAutoFail entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除自动发布失败信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/OrderExternalGoodsServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/OrderExternalGoodsServiceImpl.java new file mode 100644 index 0000000..5365caf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/OrderExternalGoodsServiceImpl.java @@ -0,0 +1,158 @@ +package org.dromara.zhishu.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.zhishu.domain.vo.FastMailVo; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; +import org.dromara.zhishu.service.IOrderExternalGoodsService; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequiredArgsConstructor +@Service +public class OrderExternalGoodsServiceImpl implements IOrderExternalGoodsService { + + private final IZhishuShopGoodsService zhishuShopGoodsService; + + @Override + public R getYundaPdf(FastMailVo fastMailVo,String erpOrderId,String printTemplateData,String type,String deliveryMode,String orderSn){ + Map res = new HashMap(); + String cusArea = ""; + // 创建快递单 + String orderStr = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/print/createOrder?orderId="+erpOrderId+"&partnerId="+fastMailVo.getPartnerId()+"&secret="+fastMailVo.getSecret()+"&type="+type+"&cusArea="+cusArea + "&deliveryMode="+deliveryMode+"&orderSn="+orderSn); + Map orderMap = JsonUtil.transferToObj(orderStr,Map.class); + if (orderMap.get("code").equals("200")){ + List dataList = (List) orderMap.get("data"); + Map data = (Map) dataList.get(0); + String mailNo = data.get("mail_no") == null ? data.get("mailno").toString() : data.get("mail_no").toString(); + // 运单号为空,代表下单失败 + if (StringUtils.isEmpty(mailNo)){ + res.put("code","500"); + res.put("msg",data.get("msg")); + return R.ok(res); + } + + String pdfStr = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/print/createBmOrderDaYin?mailno="+mailNo+"&partnerId="+fastMailVo.getPartnerId()+"&secret="+fastMailVo.getSecret()); + Map pdfMap = JsonUtil.transferToObj(pdfStr,Map.class); + if (pdfMap.get("code").equals("200")){ + res.put("code","200"); + res.put("msg","快递单获取成功"); + res.put("pdfInfo",pdfMap.get("pdfInfo")); + res.put("mailNo",mailNo); + res.put("printTemplateData",printTemplateData); + List> dataMapList = new ArrayList<>(); + // 打印的商品 + List erpGoodsOrderList = (List) orderMap.get("erpGoodsOrderList"); + for (Object erpOrderObject : erpGoodsOrderList){ + Map erpOrderMap = (Map) erpOrderObject; + Map itemMap = JsonUtil.transferToObj(erpOrderMap.get("itemList").toString(),Map.class); + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.queryById(erpOrderMap.get("erpGoodsId").toString()); + Map dataMap = new HashMap(); + dataMap.put("isbn",zhishuShopGoodsVo.getIsbn()); + dataMap.put("goodsName",itemMap.get("goodsName")); + dataMap.put("artNo",zhishuShopGoodsVo.getArtNo()); + dataMap.put("originalArtNo",zhishuShopGoodsVo.getOriginalArtNo()); + dataMap.put("goodsCount",itemMap.get("goodsCount")); + dataMapList.add(dataMap); + } + res.put("dataList",dataMapList); + return R.ok(res); + } + } + res.put("code","500"); + res.put("msg",orderMap.get("msg")); + return R.ok(res); + } + + @Override + public R getZtoPdf(FastMailVo fastMailVo,String erpOrderId,String printTemplateData,String type,String deliveryMode,String orderSn){ + Map res = new HashMap(); + String cusArea = ""; + String orderStr = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/print/createOrder?orderId="+erpOrderId+"&partnerId="+fastMailVo.getPartnerId()+"&secret="+fastMailVo.getSecret()+"&type="+type+"&cusArea="+cusArea + "&deliveryMode="+deliveryMode+"&orderSn="+orderSn); + Map orderMap = JsonUtil.transferToObj(orderStr,Map.class); + if (orderMap.get("code").equals("200")){ + // 重新拼接数据 + Map oldData = (Map) orderMap.get("data"); + Map bigMarkInfo = (Map) oldData.get("bigMarkInfo"); + // 发件人 + Map senderInfo = (Map) oldData.get("senderInfo"); + // 收件人 + Map receiveInfo = (Map) oldData.get("receiveInfo"); + // title + String title = bigMarkInfo.get("mark").toString(); + // 集 + String jiStr = bigMarkInfo.get("bagAddr").toString(); + // 快递单号 + String mailNo = oldData.get("billCode").toString(); + JSONObject sender = new JSONObject(); + sender.put("name",senderInfo.get("senderName").toString()); + sender.put("phone",senderInfo.get("senderMobile").toString()); + sender.put("address",senderInfo.get("senderAddress").toString()); + JSONObject receiver = new JSONObject(); + receiver.put("name",receiveInfo.get("receiverName").toString()); + receiver.put("phone",receiveInfo.get("receiverMobile").toString()); + receiver.put("address",receiveInfo.get("receiverProvince").toString() + receiveInfo.get("receiverCity").toString() + receiveInfo.get("receiverDistrict").toString() + receiveInfo.get("receiverAddress").toString()); + // 打印的商品 + List> dataMapList = new ArrayList<>(); + List erpGoodsOrderList = (List) orderMap.get("erpGoodsOrderList"); + for (Object erpOrderObject : erpGoodsOrderList){ + Map erpOrderMap = (Map) erpOrderObject; + Map itemMap = JsonUtil.transferToObj(erpOrderMap.get("itemList").toString(),Map.class); + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.queryById(erpOrderMap.get("erpGoodsId").toString()); + Map dataMap = new HashMap(); + dataMap.put("isbn",zhishuShopGoodsVo.getIsbn()); + dataMap.put("goodsName",itemMap.get("goodsName")); + dataMap.put("artNo",zhishuShopGoodsVo.getArtNo()); + dataMap.put("originalArtNo",zhishuShopGoodsVo.getOriginalArtNo()); + dataMap.put("goodsCount",itemMap.get("goodsCount")); + dataMapList.add(dataMap); + } + + Map resMap = new HashMap(); + resMap.put("code","200"); + resMap.put("title",title); + resMap.put("jiStr",jiStr); + resMap.put("mailNo",mailNo); + resMap.put("sender",sender); + resMap.put("receiver",receiver); + resMap.put("printTemplateData",printTemplateData); + resMap.put("dataList",dataMapList); + return R.ok(resMap); + } + res.put("code","500"); + res.put("msg",orderMap.get("msg")); + return R.ok(res); + } + + @Override + public R orderCreate(FastMailVo fastMailVo, String erpOrderId, String printTemplateData, String type, String deliveryMode, String orderSn) { + Map requestParam = new HashMap(); + // 订单id + requestParam.put("orderId",erpOrderId); + // 订单编号 + requestParam.put("orderSn",orderSn); + // 快递类型 + requestParam.put("type",type); + // 1 全部打印 0 单个打印 + requestParam.put("deliveryMode",deliveryMode); + // 快递账号信息 + requestParam.put("fastMailMap",JsonUtil.transferToJson(fastMailVo)); + // 创建订单 获取订单信息 + String orderStr = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/print/createOrderNew",requestParam); + Map orderMap = JsonUtil.transferToObj(orderStr,Map.class); + if (orderMap.get("code").equals("200")){ + return R.ok((Map) orderMap.get("expressDeliveryOrder")); + } + return R.fail("创建快递单失败"); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PddRequestServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PddRequestServiceImpl.java new file mode 100644 index 0000000..86fd0c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PddRequestServiceImpl.java @@ -0,0 +1,115 @@ +package org.dromara.zhishu.service.impl; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import com.pdd.pop.sdk.http.PopClient; +import com.pdd.pop.sdk.http.PopHttpClient; +import com.pdd.pop.sdk.http.api.pop.request.PddOrderNumberListIncrementGetRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddOrderNumberListIncrementGetResponse; +import jakarta.annotation.Resource; +import lombok.extern.log4j.Log4j2; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.zhishu.domain.dto.PddOrderIncrementQuery; +import org.dromara.zhishu.enums.PddResCodeEnum; +import org.dromara.zhishu.service.ITShopOrderService; +import org.dromara.zhishu.service.PddRequestService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +@Service +@Log4j2 +public class PddRequestServiceImpl implements PddRequestService { + + @Value("${pdd.app.clientId}") + private String clientId; + + @Value("${pdd.app.clientSecret}") + private String clientSecret; + + @Resource + ITShopOrderService tShopOrderService; + + + // 调用拼多多增量 获取订单 + public void getIncrementRequest(PddOrderIncrementQuery query){ + + //todo 获取所有的店铺列表 + PopClient client = new PopHttpClient(clientId, clientSecret); + PddOrderNumberListIncrementGetRequest request = new PddOrderNumberListIncrementGetRequest(); + + String startTimeStr = query.getStartTime(); + String endTimeStr = query.getEndTime(); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + long start_updated_at; + long end_updated_at; + + try { + // 解析时间并转换为时间戳 + start_updated_at = sdf.parse(startTimeStr).getTime() / 1000; + end_updated_at = sdf.parse(endTimeStr).getTime() /1000; + query.setStart_updated_at(start_updated_at); + query.setEnd_updated_at(end_updated_at); + + } catch (ParseException e) { + throw new RuntimeException(e); + } + + + request.setStartUpdatedAt(query.getStart_updated_at()); + request.setEndUpdatedAt(query.getEnd_updated_at()); + request.setIsLuckyFlag(query.getIs_lucky_flag()); + request.setOrderStatus(query.getOrder_status()); + request.setPage(query.getPage()); + request.setRefundStatus(query.getRefund_status()); + request.setTradeType(query.getTrade_type()); + request.setUseHasNext(true); + PddOrderNumberListIncrementGetResponse response = null; + try { + response = client.syncInvoke(request, query.getAccess_token()); + } catch (Exception e) { + throw new RuntimeException(e); + } + System.out.println(JsonUtil.transferToJson(response)); + String res = JsonUtil.transferToJson(response); + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); + //字符串转换成对象 + JsonObject obj = gson.fromJson(res, JsonObject.class); + + if (ObjectUtils.isNotEmpty(obj.get(PddResCodeEnum.ERR.getCode()))) { + //报错信息 + JsonObject error_response = obj.get(PddResCodeEnum.ERR.getCode()).getAsJsonObject(); + log.error("调取拼多多接口失败{}", error_response); + } + // 如果存在就继续去调用 + if( ObjectUtils.isNotEmpty(obj.get(PddResCodeEnum.HAS_NEXT.getCode())) && obj.get(PddResCodeEnum.ORDER_LIST_OK.getCode()).getAsBoolean()){ + query.setPage(query.getPage()+1); + getIncrementRequest(query); + } + + if (ObjectUtils.isNotEmpty(obj.get(PddResCodeEnum.ORDER_SN_INCREMENT_GET_RESPONSE.getCode()))) { + JsonArray asJsonArray = obj.getAsJsonObject(PddResCodeEnum.ORDER_SN_INCREMENT_GET_RESPONSE.getCode()).getAsJsonArray(PddResCodeEnum.ORDER_SN_LIST.getCode()); + if (ObjectUtils.isNotEmpty(asJsonArray)) { + // todo 写入数据库的操作 + tShopOrderService.insertPddIncrementOrder(asJsonArray); + } + } + } + + + + // todo 订单发货 + + + // todo 订单列表 已经提交的列表 + + // todo 订单列表 + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PriceTemplateServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PriceTemplateServiceImpl.java new file mode 100644 index 0000000..fba2284 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PriceTemplateServiceImpl.java @@ -0,0 +1,298 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import io.swagger.v3.oas.models.responses.ApiResponse; +import org.dromara.zhishu.util.JsonObjUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.dto.request.CalculatePriceByTemplateRequest; +import org.dromara.zhishu.domain.dto.response.CalculatePriceByTemplateResponse; +import org.dromara.zhishu.domain.vo.PriceRuleVo; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.PriceTemplateBo; +import org.dromara.zhishu.domain.vo.PriceTemplateVo; +import org.dromara.zhishu.domain.PriceTemplate; +import org.dromara.zhishu.mapper.PriceTemplateMapper; +import org.dromara.zhishu.service.IPriceTemplateService; +import org.dromara.zhishu.util.HttpUtils; +import com.fasterxml.jackson.core.type.TypeReference; +import org.springframework.web.client.RestTemplate; + +import java.util.*; +import java.util.HashMap; +import java.util.LinkedHashMap; + +/** + * 价格模板Service业务层处理 + * + * @author yxy + * @date 2025-03-17 + */ +@RequiredArgsConstructor +@Service +public class PriceTemplateServiceImpl implements IPriceTemplateService { + + private final PriceTemplateMapper baseMapper; + + /** + * 查询价格模板 + * + * @param id 主键 + * @return 价格模板 + */ + @Override + public PriceTemplateVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询价格模板列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 价格模板分页列表 + */ + @Override + public TableDataInfo queryPageList(PriceTemplateBo bo, PageQuery pageQuery) { +// 获取当前用户id + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的价格模板列表 + * + * @param bo 查询条件 + * @return 价格模板列表 + */ + @Override + public List queryList(PriceTemplateBo bo) { + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(PriceTemplateBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(PriceTemplate::getId); + lqw.eq(bo.getCreateBy() != null, PriceTemplate::getCreateBy, bo.getCreateBy()); + lqw.like(StringUtils.isNotBlank(bo.getTemplateName()), PriceTemplate::getTemplateName, bo.getTemplateName()); + lqw.eq(bo.getProportion() != null, PriceTemplate::getProportion, bo.getProportion()); + lqw.eq(bo.getAddAmount() != null, PriceTemplate::getAddAmount, bo.getAddAmount()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), PriceTemplate::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增价格模板 + * + * @param bo 价格模板 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(PriceTemplateBo bo) { + PriceTemplate add = MapstructUtils.convert(bo, PriceTemplate.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + +// String url = "http://localhost:30200/api/updatePriceTemplate"; + String url = "http://localhost:9099/api/updatePriceTemplate"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ID", add.getId().toString()); + + // 设置请求头 + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + try { + // 将请求对象转换为JSON字符串 + String jsonBody = HttpUtils.convertObjectToJson(requestBody); + + // 发送POST请求 + String response = HttpUtils.sendPost(url, headers, jsonBody); + System.out.println("调用updatePriceTemplate接口成功,响应: " + response); + } catch (Exception e) { + System.err.println("调用updatePriceTemplate接口失败: " + e.getMessage()); + e.printStackTrace(); + } + + // // 新增成功后添加到Redis + // insertPriceTemplateIntoRedis(bo); + } + return flag; + } + + /** + * 修改价格模板 + * + * @param bo 价格模板 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(PriceTemplateBo bo) { + PriceTemplate update = MapstructUtils.convert(bo, PriceTemplate.class); + validEntityBeforeSave(update); + boolean flag = baseMapper.updateById(update) > 0; + if (flag) { + + String url = "http://localhost:9099/api/updatePriceTemplate"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ID", bo.getId().toString()); + + // 设置请求头 + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + try { + // 将请求对象转换为JSON字符串 + String jsonBody = HttpUtils.convertObjectToJson(requestBody); + + // 发送POST请求 + String response = HttpUtils.sendPost(url, headers, jsonBody); + System.out.println("调用updatePriceTemplate接口成功,响应: " + response); + } catch (Exception e) { + System.err.println("调用updatePriceTemplate接口失败: " + e.getMessage()); + e.printStackTrace(); + } + } + + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(PriceTemplate entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除价格模板信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + @Override + public List getPriceByPlatformId(List requests) { + List list = new ArrayList<>(); + //遍历requests,并根据platformId查询出对应的商品信息 + for (CalculatePriceByTemplateRequest request : requests){ + PriceTemplate priceTemplate = baseMapper.priceByPlatformId(request.getPlatformId()); + if (priceTemplate == null){ + continue; + } + ObjectMapper mapper = new ObjectMapper(); + try { + List rules = mapper.readValue(priceTemplate.getRangePrice(), new TypeReference>() {}); + if(!rules.isEmpty()){ + // 默认使用第一个区间(如果都不匹配) + PriceRuleVo matchedRule = rules.get(0); + // 遍历所有区间,检查 request.getPrice() 是否在某个范围内 + for (PriceRuleVo rule : rules) { + if (request.getPrice() >= rule.getMinPrice() && request.getPrice() <= rule.getMaxPrice()) { + matchedRule = rule; // 找到匹配的区间 + break; + } + } + // 计算最终价格 + long adjustedPrice = request.getPrice() + matchedRule.getAdjustAmount() + (request.getPrice() * matchedRule.getAdjustPercent() / 100); + //解析并获取各个参数的值 + CalculatePriceByTemplateResponse calculatePriceByTemplateResponse =new CalculatePriceByTemplateResponse(); + calculatePriceByTemplateResponse.setPlatformId(request.getPlatformId()); + calculatePriceByTemplateResponse.setPrice(request.getPrice()); + calculatePriceByTemplateResponse.setSinglePrice(adjustedPrice+100); + calculatePriceByTemplateResponse.setGroupPrice(adjustedPrice); + list.add(calculatePriceByTemplateResponse); + } + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + return list; + } + + /** + * 向redis,db7中添加t_price_template数据 + * @param bo + */ +// public void insertPriceTemplateIntoRedis(PriceTemplateBo bo){ +// if (ObjectUtil.isEmpty(bo) || bo.getId() == null) { +// return; +// } +// +// try { +// // 处理rangePrice字段,确保所有数字向下取整 +// if (StringUtils.isNotBlank(bo.getRangePrice())) { +// ObjectMapper mapper = new ObjectMapper(); +// List rules = mapper.readValue(bo.getRangePrice(), new TypeReference>() {}); +// // 重新转换为JSON,确保所有数字都是整数 +// bo.setRangePrice(mapper.writeValueAsString(rules)); +// } +// +// String redisKey = bo.getId().toString(); +// // 构建t_price_template数据结构 +// Map priceTemplateData = new LinkedHashMap<>(); +// priceTemplateData.put("source_table", "t_price_template"); +// priceTemplateData.put("data", bo); +// String priceTemplateJson = JsonObjUtil.objectToJsonWithSnakeKeys(priceTemplateData); +// +// // 获取Redis中的List +// org.redisson.api.RList redisList = RedisUtils.getThirdClient().getList(redisKey); +// boolean updated = false; +// +// // 遍历List,更新对应source_table的数据 +// for (int i = 0; i < redisList.size(); i++) { +// String item = redisList.get(i); +// Map itemMap = JSONUtil.toBean(item, Map.class); +// if ("t_price_template".equals(itemMap.get("source_table"))) { +// redisList.set(i, priceTemplateJson); +// updated = true; +// break; +// } +// } +// +// // 如果没有找到对应数据,则添加新元素 +// if (!updated) { +// redisList.add(priceTemplateJson); +// } +// +// } catch (Exception e) { +// System.out.println(e.getMessage()); +// } +// } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PrinterServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PrinterServiceImpl.java new file mode 100644 index 0000000..942d602 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PrinterServiceImpl.java @@ -0,0 +1,149 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.PrintTemplate; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.PrinterBo; +import org.dromara.zhishu.domain.vo.PrinterVo; +import org.dromara.zhishu.domain.Printer; +import org.dromara.zhishu.mapper.PrinterMapper; +import org.dromara.zhishu.service.IPrinterService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 打印机设置Service业务层处理 + * + * @author yxy + * @date 2026-03-06 + */ +@RequiredArgsConstructor +@Service +public class PrinterServiceImpl implements IPrinterService { + + private final PrinterMapper baseMapper; + + /** + * 查询打印机设置 + * + * @param id 主键 + * @return 打印机设置 + */ + @Override + public PrinterVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询打印机设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 打印机设置分页列表 + */ + @Override + public TableDataInfo queryPageList(PrinterBo bo, PageQuery pageQuery) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + // 获取白名单 + if (userId != 1) { + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的打印机设置列表 + * + * @param bo 查询条件 + * @return 打印机设置列表 + */ + @Override + public List queryList(PrinterBo bo) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + // 获取白名单 + if (userId != 1) { + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(PrinterBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(Printer::getId); + lqw.eq(bo.getCreateBy() != null, Printer::getCreateBy, bo.getCreateBy()); + lqw.eq(StringUtils.isNotBlank(bo.getPrinter()), Printer::getPrinter, bo.getPrinter()); + lqw.like(StringUtils.isNotBlank(bo.getPrinterName()), Printer::getPrinterName, bo.getPrinterName()); + lqw.eq(StringUtils.isNotBlank(bo.getIsRemotePrinting()), Printer::getIsRemotePrinting, bo.getIsRemotePrinting()); + lqw.eq(bo.getUpdateTime() != null, Printer::getUpdateTime, bo.getUpdateTime()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Printer::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增打印机设置 + * + * @param bo 打印机设置 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(PrinterBo bo) { + Printer add = MapstructUtils.convert(bo, Printer.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改打印机设置 + * + * @param bo 打印机设置 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(PrinterBo bo) { + Printer update = MapstructUtils.convert(bo, Printer.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(Printer entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除打印机设置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ProfitSharingLogServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ProfitSharingLogServiceImpl.java new file mode 100644 index 0000000..f5f632e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ProfitSharingLogServiceImpl.java @@ -0,0 +1,52 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.ProfitSharingLog; +import org.dromara.zhishu.domain.vo.ErpGoodsOrderVo; +import org.dromara.zhishu.service.IProfitSharingLogService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequiredArgsConstructor +@Service +public class ProfitSharingLogServiceImpl implements IProfitSharingLogService { + @Override + public TableDataInfo queryPageList(ProfitSharingLog bo, PageQuery pageQuery) { + Map params = new HashMap<>(); + params.put("page",pageQuery.getPageNum()); + params.put("pageSize",pageQuery.getPageSize()); + + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + params.put("created_by",userId); + } + + if (StringUtils.isNotEmpty(bo.getOrderSn())){ + params.put("order_sn",bo.getOrderSn()); + } + + if (!bo.getParams().isEmpty()){ + params.put("created_time_start",bo.getParams().get("startTime")); + params.put("created_time_end",bo.getParams().get("endTime")); + } + + String dataStr = InterfaceUtils.getInterfaceGetWithParams("https://go.order.service.buzhiyushu.cn","/api/profitsharing/getList",params); + Map dataMap = JsonUtil.transferToObj(dataStr,Map.class); + List list = (List) dataMap.get("data"); + int total = (int) dataMap.get("total"); + Page result = new Page<>(pageQuery.getPageNum(),pageQuery.getPageSize(),total); + result.setRecords(list); + return TableDataInfo.build(result); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodIsbnServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodIsbnServiceImpl.java new file mode 100644 index 0000000..3efdd5a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodIsbnServiceImpl.java @@ -0,0 +1,10 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.service.IShopGoodIsbnService; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class ShopGoodIsbnServiceImpl implements IShopGoodIsbnService { +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsPublishedServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsPublishedServiceImpl.java new file mode 100644 index 0000000..e0e5399 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsPublishedServiceImpl.java @@ -0,0 +1,705 @@ +package org.dromara.zhishu.service.impl; + +import ch.qos.logback.core.joran.util.beans.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.core.exception.base.BaseException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysOss; +import org.dromara.zhishu.domain.*; +import org.dromara.zhishu.domain.bo.FilterSetBo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.vo.FilterSetVo; +import org.dromara.zhishu.domain.vo.PlatformIdUpdateVO; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.mapper.BookBaseInfoMapper; +import org.dromara.zhishu.mapper.RunningTaskByShopMapper; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.util.CnumberUtils; +import org.dromara.zhishu.util.UploadUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.ShopGoodsPublishedBo; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.mapper.ShopGoodsPublishedMapper; + +import java.time.Duration; +import java.util.*; +import java.util.stream.Collectors; + +import static org.dromara.common.mybatis.core.mapper.BaseMapperPlus.log; + +/** + * 记录已发布书籍Service业务层处理 + * + * @author yxy + * @date 2025-04-11 + */ +@RequiredArgsConstructor +@Service +public class ShopGoodsPublishedServiceImpl implements IShopGoodsPublishedService { + + private final IShopService shopService; + + private final ShopGoodsPublishedMapper baseMapper; + + private final ZhishuShopGoodsMapper zhishuShopGoodsMapper; + + private final BookBaseInfoMapper bookBaseInfoMapper; + + private final CnumberUtils cnumberUtils; + + private final ShopGoodsRejectionService shopGoodsRejectionService; + + private final IRunningTaskService runningTaskService; + + private final IRunningTaskByShopService runningTaskByShopService; + + private final IFilterSetService filterSetService; + + private final ITaskService taskService; + + @Autowired + private RedisTemplate redisTemplate; + + + /** + * 查询记录已发布书籍 + * + * @param id 主键 + * @return 记录已发布书籍 + */ + @Override + public ShopGoodsPublishedVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 根据shop_goods_id批量查询 + * @param shopGoodsIds 商品ID列表 + * @return 查询结果列表 + */ + @Override + public List selectByShopGoodsIds(List shopGoodsIds,Long shopId){ + return baseMapper.selectByShopGoodsIds(shopGoodsIds,shopId); + } + + @Override + public List selectListByShopsId(Long shopId) { + return baseMapper.selectListByShopsId(shopId); + } + + @Override + public List selectShopGoodsPublishedByShopIdAndArtNo(Long shopId,String artNo){ + return baseMapper.selectShopGoodsPublishedByShopIdAndArtNo(shopId,artNo); + } + + @Override + public ShopGoodsPublishedVo selectDataById(Long id) { + return baseMapper.selectDataById(id); + } + + public TableDataInfo selectDataList(ShopGoodsPublishedBo bo, PageQuery pageQuery) { + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + String con = cnumberUtils.CHINESE_TO_CODE_MAP.get(bo.getConditionCode()); + bo.setConditionCode(con); +// LambdaQueryWrapper lqw = buildQueryWrapper(bo); +// Page result = baseMapper.selectDataList(pageQuery.build(), lqw, LoginHelper.getUserId().toString()); + Page result = baseMapper.selectDataList(pageQuery.build(), bo); + result.getRecords().forEach(item -> { + if (StringUtils.isNotEmpty(item.getCreateBy())) { + String phone = StringUtils.substring(item.getCreateBy(), 0, 2) + "****" + + StringUtils.substring(item.getCreateBy(), -2); + item.setCreateBy(phone); + if (StringUtils.isNotEmpty(item.getSupplier())) { + item.setSupplier(phone + "-" + item.getSupplier()); + } + } + if (item.getBookPic().isEmpty()) { + String path = zhishuShopGoodsMapper.selectByBookPic(item.getShopGoodsId()); + if (path != null) { + String bookPic = UploadUtil.getFiles("","","",path); + item.setBookPic(bookPic); + } + } + }); + return TableDataInfo.build(result); + } + + /** + * 分页查询记录已发布书籍列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 记录已发布书籍分页列表 + */ + @Override + public TableDataInfo queryPageList(ShopGoodsPublishedBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的记录已发布书籍列表 + * + * @param bo 查询条件 + * @return 记录已发布书籍列表 + */ + @Override + public List queryList(ShopGoodsPublishedBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(ShopGoodsPublishedBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getShopGoodsId()), ShopGoodsPublished::getShopGoodsId, bo.getShopGoodsId()); + lqw.eq(StringUtils.isNotBlank(bo.getShopId()), ShopGoodsPublished::getShopId, bo.getShopId()); + return lqw; + } + + /** + * 新增记录已发布书籍 + * + * @param bo 记录已发布书籍 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ShopGoodsPublishedBo bo) { + ShopGoodsPublished add = MapstructUtils.convert(bo, ShopGoodsPublished.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改记录已发布书籍 + * + * @param bo 记录已发布书籍 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ShopGoodsPublishedBo bo) { + ShopGoodsPublished update = MapstructUtils.convert(bo, ShopGoodsPublished.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ShopGoodsPublished entity) { + // TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除记录已发布书籍信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + for(Long id : ids){ + baseMapper.delByIds(id); + } + return true; + } + + /** + * 一键删除 + * @return + */ + @Override + public String deleteAll(Long shopId){ + ShopVo shopVo = shopService.queryById(shopId); + if(!shopVo.getShopType().equals("5")){ + return "此功能目前只支持闲鱼店铺"; + } + baseMapper.delByShopId(shopId); + return "删除成功"; + } + + @Override + public String deleteByShopId(Long shopId){ + baseMapper.delByShopId(shopId); + return "删除成功"; + } + + @Override + public List selectGoodsListByShopId(Long shopId, List platformIds) { + List shopGoodsList = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ShopGoodsPublished::getShopId, shopId) + .eq(ShopGoodsPublished::getDelFlag, "0") + .eq(ShopGoodsPublished::getStatus, "0") + .in(ShopGoodsPublished::getPlatformId, platformIds) + .list().stream().map(shopGoodsPublished -> { + ShopGoodsPublishedVo shopGoodsPublishedVo = new ShopGoodsPublishedVo(); + BeanUtils.copyProperties(shopGoodsPublished, shopGoodsPublishedVo); + return shopGoodsPublishedVo; + }).toList(); + return shopGoodsList; + } + @Override + public List selectGoodsListByShopId(Long shopId) { + List shopGoodsList = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ShopGoodsPublished::getShopId, shopId) + .eq(ShopGoodsPublished::getDelFlag, "0") + .eq(ShopGoodsPublished::getStatus, "0") + .list().stream().map(shopGoodsPublished -> { + ShopGoodsPublishedVo shopGoodsPublishedVo = new ShopGoodsPublishedVo(); + BeanUtils.copyProperties(shopGoodsPublished, shopGoodsPublishedVo); + return shopGoodsPublishedVo; + }).toList(); + return shopGoodsList; + } + + /** + * 根据平台id查询 + * + * @param shopId + * @param platformId + * @return + */ + @Override + public ShopGoodsPublishedVo queryByPlatformId(String shopId, String platformId) { + List shopGoodsPublishedList = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ShopGoodsPublished::getShopId, shopId) + .eq(ShopGoodsPublished::getPlatformId, platformId) + .list(); + if (ObjectUtil.isNotEmpty(shopGoodsPublishedList)) { + ShopGoodsPublished shopGoodsPublished = shopGoodsPublishedList.get(0); + ShopGoodsPublishedVo shopGoodsPublishedVo = new ShopGoodsPublishedVo(); + BeanUtils.copyProperties(shopGoodsPublished, shopGoodsPublishedVo); + return shopGoodsPublishedVo; + } + return null; + } + + /** + * 根据商品id和店铺id查询 + * + * @param shopId 店铺id + * @param shopGoodsId 商品id + * @return + */ + @Override + public ShopGoodsPublishedVo queryByShopIdAndShopGoodsId(String shopId, String shopGoodsId) { + List shopGoodsPublishedList = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ShopGoodsPublished::getShopId, shopId) + .eq(ShopGoodsPublished::getShopGoodsId, shopGoodsId) + .list(); + if (ObjectUtil.isNotEmpty(shopGoodsPublishedList)) { + ShopGoodsPublished shopGoodsPublished = shopGoodsPublishedList.get(0); + ShopGoodsPublishedVo shopGoodsPublishedVo = new ShopGoodsPublishedVo(); + BeanUtils.copyProperties(shopGoodsPublished, shopGoodsPublishedVo); + return shopGoodsPublishedVo; + } + return null; + } + + /** + * 根据shopGoodsId查询 + * + * @param shopGoodsId + * @return + */ + @Override + public List queryByShopGoodsId(String shopGoodsId) { + List list = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ShopGoodsPublished::getShopGoodsId, shopGoodsId) + .list(); + if (ObjectUtil.isNotEmpty(list)) { + return list.stream().map(shopGoodsPublished -> { + ShopGoodsPublishedVo shopGoodsPublishedVo = new ShopGoodsPublishedVo(); + BeanUtils.copyProperties(shopGoodsPublished, shopGoodsPublishedVo); + return shopGoodsPublishedVo; + }).toList(); + } + return new ArrayList<>(); + } + + /** + * 商品发布驳回-类目修改cat_id + * + * @param shopType + * @param mallId + * @param platformId + * @return + */ + @Override + public Boolean uodateCatId(String shopType, Long mallId, String platformId) { + ShopVo shopVo = shopService.queryByMailId(mallId, Integer.parseInt(shopType)); + ShopGoodsPublished shopGoodsPublished = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ShopGoodsPublished::getShopId, shopVo.getId().toString()) + .eq(ShopGoodsPublished::getPlatformId, platformId) + .oneOpt().orElseThrow(() -> new BaseException("查询发布商品数据异常-shopId:" + shopVo.getId() + "-platformId:" + platformId)); + ZhishuShopGoods zhishuShopGoods = new LambdaQueryChainWrapper<>(zhishuShopGoodsMapper) + .eq(ZhishuShopGoods::getId, shopGoodsPublished.getShopGoodsId()) + .oneOpt().orElseThrow(() -> new BaseException("查询商品数据异常-shopGoodsId:" + shopGoodsPublished.getShopGoodsId())); + return new LambdaUpdateChainWrapper<>(bookBaseInfoMapper) + .eq(BookBaseInfo::getIsbn, zhishuShopGoods.getIsbn()) + .set(BookBaseInfo::getCatId, null) + .update(); + } + + /** + * 删除 + * + * @param mallId + * @param platformId + */ + @Override + public Boolean delShopGoodsPublished(String shopType, Long mallId, String platformId, String rejectComment) { + // 先从Redis中查询,如果不存在再查数据库 + String redisKey = "shop:" + mallId + ":" + shopType; + ShopVo shopVo = null; + try { + // 尝试从Redis获取 + String shopJson = String.valueOf(redisTemplate.opsForValue().get(redisKey)) ; + if (StringUtils.isNotBlank(shopJson)) { + shopVo = JsonUtil.transferToObj(shopJson, ShopVo.class); + } + } catch (Exception e) { + log.warn("从Redis获取店铺信息失败,降级到数据库查询"+e); + } + + // Redis中没有,从数据库查询 + if (ObjectUtil.isEmpty(shopVo)) { + shopVo = shopService.queryByMailId(mallId, Integer.parseInt(shopType)); + if (ObjectUtil.isEmpty(shopVo)) { + return false; + } + + // 将查询结果存入Redis,设置过期时间 + try { + String shopJson = JsonUtil.transferToJson(shopVo); + redisTemplate.opsForValue().set(redisKey, shopJson, Duration.ofHours(8)); // 缓存8小时 + } catch (Exception e) { + log.warn("店铺信息存入Redis失败"+ e); + } + } + try { + RunningTask runningTask = runningTaskByShopService.selectVoByTrilateralId("t_running_task_"+shopVo.getId(), platformId); + if(runningTask != null){ + SuccessDataItemDto item = JsonUtil.transferToObj(runningTask.getSuccessData(), SuccessDataItemDto.class); + // 插入驳回原因 + insertRejectionRecord(shopVo, platformId, rejectComment, item); + } + runningTaskByShopService.deleteByGoodsId("t_running_task_"+shopVo.getId(), platformId); + } catch (Exception e) { + log.error("插入商品驳回原因异常:{}", e); + } + + return baseMapper.delShopGoodsPublished(shopVo.getId().toString(), platformId); + } + + + private void insertRejectionRecord(ShopVo shopVo, String platformId, String rejectComment, SuccessDataItemDto item) { + //根据店铺与商品id获取erp商品id + String shopGoodsId = ""; + try{ + System.out.println("查询已发布商品数据:"+shopVo.getId()+"----"+platformId); + ShopGoodsPublishedVo shopGoodsPublishedVo = queryByPlatformId(shopVo.getId().toString(),platformId); + if(shopGoodsPublishedVo != null){ + System.out.println("查询已发布商品成功"); + shopGoodsId = shopGoodsPublishedVo.getShopGoodsId(); + }else{ + System.out.println("已发布商品无数据"); + } + }catch (Exception e){ + System.out.println("查询已发布商品数据异常:"+e.getMessage()); + } + + // 获取img字段(Object类型) + Object shopGoodsImgObj = item.getImg(); + String shopGoodsImg = ""; + + if (shopGoodsImgObj != null) { + if (shopGoodsImgObj instanceof String) { + // 如果是字符串类型,直接使用 + shopGoodsImg = (String) shopGoodsImgObj; + } else if (shopGoodsImgObj instanceof Map) { + // 如果是Map类型,处理复杂结构 + Map imgMap = (Map) shopGoodsImgObj; + + // 获取carousel_url_array + Object carouselArrayObj = imgMap.get("carousel_url_array"); + + if (carouselArrayObj instanceof List) { + List carouselList = (List) carouselArrayObj; + + // 获取第一张图片,如果列表不为空 + if (carouselList != null && !carouselList.isEmpty()) { + shopGoodsImg = carouselList.get(0); + } + } + } + } + + ShopGoodsRejection rejection = ShopGoodsRejection.builder() + .rejectionReason(rejectComment) + .createTime(new Date()) + .shopId(shopVo.getId()) + .shopGoodsId(shopGoodsId) + .platformId(platformId) + .isbn(item.getIsbn()) + .shopName(shopVo.getShopName()) + .tenantId("000000") + .platformType(1) + .goodsType(1) + .shopGoodsImg(shopGoodsImg) + .build(); + shopGoodsRejectionService.save(rejection); + + try{ + //如果rejectComment包含了 ”违禁“ 则插入到黑名单里 + if(rejectComment.contains("违禁") + || rejectComment.contains("违法") + || rejectComment.contains("色情") + || rejectComment.contains("情色") + || rejectComment.contains("禁止销售") + ){ + FilterSetBo bo = new FilterSetBo(); + bo.setFilterType("1"); + bo.setLimitationType("0"); + bo.setAddWay("2"); + // 0 是拼多多 + bo.setSort("0"); + bo.setReason(rejectComment); + //去掉前后空格 + bo.setAddTxt(item.getIsbn()); + //查询是否有相同的违规词,如果有,则合并 + List list = filterSetService.selectVoListByBo(bo); + + if(list.isEmpty()){ + //没有则直接新增 + filterSetService.insertByBo(bo); + }else{ + //如果存在则合并平台字段,并将多余的数据删除 + //两个数组合并 + Set sortSet = new HashSet(); + FilterSetVo vo = list.get(0); + String[] newSortArr = bo.getSort().split( ","); + for (int j=0;j> selectPublishedStatus(List goodsIds, List shopIds) { + if (goodsIds == null || goodsIds.isEmpty() || shopIds == null || shopIds.isEmpty()) { + return new ArrayList<>(); + } + return baseMapper.selectPublishedStatus(goodsIds, shopIds); + } + + @Override + public List getPlatFormIdsByShopId(Long shopId) { + return this.baseMapper.getPlatFormIdsByShopId(shopId); + } + + @Override + public void batchUpdateKfzPlatformId(List platformIdUpdateVOList) { + baseMapper.batchUpdateKfzPlatformId(platformIdUpdateVOList); + } + + @Override + public void insertLog(String shopType, Long mallId, String platformId, String offshelftime) { + ShopVo shopVo = shopService.queryByMailId(mallId, Integer.parseInt(shopType)); + if(ObjectUtil.isEmpty(shopVo)){ + return ; + } + + try { + RunningTask runningTask =runningTaskByShopService.selectVoByTrilateralId("t_running_task_"+shopVo.getId(), platformId); + if(runningTask!=null){ + SuccessDataItemDto item = JsonUtil.transferToObj(runningTask.getSuccessData(), SuccessDataItemDto.class); + insertRejectionRecord(shopVo, platformId, "平台抽查驳回下架", item); + } + + }catch (Exception e){ + log.error("插入商品驳回原因异常:{}",e); + } + } + + /** + * 根据条件查询总数 + */ + @Override + public Long selectCount(ShopGoodsPublishedBo bo){ + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectCount(lqw); + } + + /** + * 已发布商品记录校验店铺商品 + */ + @Override + public void verifyShopGoodsPublished(String shopId){ + + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 为每个店铺创建新的 TaskBo 对象 + TaskBo taskBo = new TaskBo(); + // 存储任务信息 + taskBo.setTaskType("VERIFY_SHOPGOODS_PUBLISHED"); + taskBo.setFileName("已发布商品数据校验"); + taskBo.setShopIds(shopId); + taskBo.setShopNames(shopVo.getShopName()); + taskBo.setDataNum(0L); + taskBo.setTaskStatus("0"); + taskBo.setCreateBy(shopVo.getCreateBy()); + taskBo.setUpdateBy(shopVo.getCreateBy()); + taskService.insertByBo(taskBo); + + ShopGoodsPublishedBo bo = new ShopGoodsPublishedBo(); + bo.setShopId(shopId); + Long count = selectCount(bo); + + + // 设置每页大小 + int pageSize = 1000; + // 计算总页数 + int totalPages = (int) Math.ceil((double) count / pageSize); + + List needDeleteIds = new ArrayList<>(); // 存储需要删除的id + List needDeletePlatformIds = new ArrayList<>(); // 存储需要删除的platformId(用于日志) + String tableName = "t_running_task_" + shopId; + // 从最后一页往前循环 + for (int pageNum = totalPages; pageNum >= 1; pageNum--) { + PageQuery pageQuery = new PageQuery(pageSize, pageNum); + TableDataInfo tableDataInfo = queryPageList(bo, pageQuery); + List list = tableDataInfo.getRows(); + + // 批量提取platformId并转换为Long + List goodsIds = list.stream() + .map(vo -> { + return Long.parseLong(vo.getPlatformId()); + }) + .collect(Collectors.toList()); + // 批量查询已存在的goods_id + List existingGoodsIds = runningTaskByShopService.batchSelectExistsByGoodsIds(tableName, goodsIds); + Set existingSet = new HashSet<>(existingGoodsIds); + // 找出需要删除的记录(同时保存id和platformId) + List needDeleteRecords = list.stream() + .filter(vo -> { + try { + Long goodsId = Long.parseLong(vo.getPlatformId()); + return !existingSet.contains(goodsId); + } catch (NumberFormatException e) { + return false; + } + }) + .toList(); + + if (!needDeleteRecords.isEmpty()) { + // 提取需要删除的id和platformId + List batchDeleteIds = needDeleteRecords.stream() + .map(ShopGoodsPublishedVo::getId) + .collect(Collectors.toList()); + + List batchDeletePlatformIds = needDeleteRecords.stream() + .map(ShopGoodsPublishedVo::getPlatformId) + .toList(); + + // 添加到总列表 + needDeleteIds.addAll(batchDeleteIds); + needDeletePlatformIds.addAll(batchDeletePlatformIds); + + // 执行删除语句 - 根据id删除 + if (!batchDeleteIds.isEmpty()) { + // 分批次删除,比如每批500条 + int deleteBatchSize = 500; + for (int i = 0; i < batchDeleteIds.size(); i += deleteBatchSize) { + int end = Math.min(i + deleteBatchSize, batchDeleteIds.size()); + List subDeleteIds = batchDeleteIds.subList(i, end); + // 调用根据id批量删除的方法 + baseMapper.batchDeleteByIds(subDeleteIds); + System.out.println("第" + pageNum + "页删除批次" + (i/deleteBatchSize + 1) + ",删除" + subDeleteIds.size() + "条记录"); + } + } + + // 记录日志 - 使用platformId + List taskList = batchDeletePlatformIds.stream() + .map(platformId -> { + Map goMap = new HashMap<>(); + goMap.put("trilateralId", platformId); + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(taskBo.getId()); + runningTask.setShopId(Long.valueOf(shopId)); + runningTask.setGoodsId(0L); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setTaskName(taskBo.getFileName()); + runningTask.setPriority(255L); + runningTask.setCallBackData("已发布商品记录删除成功"); + runningTask.setData(JsonUtil.transferToJson(goMap)); + runningTask.setStatus("3"); + runningTask.setTaskType(taskBo.getTaskType()); + return runningTask; + }) + .collect(Collectors.toList()); + + // 批量插入任务记录 + if (!taskList.isEmpty()) { + int logBatchSize = 100; + for (int i = 0; i < taskList.size(); i += logBatchSize) { + int end = Math.min(i + logBatchSize, taskList.size()); + List subList = taskList.subList(i, end); + runningTaskService.batchInsert(subList); + } + } + System.out.println("第" + pageNum + "页发现" + batchDeletePlatformIds.size() + "个需要删除的商品"); + } + } + + System.out.println("分析完成,总共需要删除" + needDeleteIds.size() + "个商品"); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsServiceImpl.java new file mode 100644 index 0000000..c90a4c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsServiceImpl.java @@ -0,0 +1,417 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.zhishu.domain.dto.ShopGoodsDto; +import org.dromara.zhishu.mapper.ShopGoodsMapper; +import org.dromara.zhishu.service.ShopGoodsService; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Map; + +/** + * 商品信息Service实现类 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class ShopGoodsServiceImpl implements ShopGoodsService { + + private final ShopGoodsMapper shopGoodsMapper; + + // ==================== 表管理 ==================== + @DS("slave") + @Override + public boolean checkTableExists(String tableName) { + if (!StringUtils.hasText(tableName)) { + return false; + } + try { + int count = shopGoodsMapper.checkTableExists(tableName); + return count > 0; + } catch (Exception e) { + log.error("检查表是否存在失败, tableName: {}", tableName, e); + return false; + } + } + + @DS("slave") + @Override + public void createTable(String tableName) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + shopGoodsMapper.createTable(tableName); + log.info("创建表成功, tableName: {}", tableName); + } catch (Exception e) { + log.error("创建表失败, tableName: {}", tableName, e); + throw new RuntimeException("创建表失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public void initTable(String tableName) { + if (!checkTableExists(tableName)) { + createTable(tableName); + log.info("初始化表成功, tableName: {}", tableName); + } else { + log.info("表已存在, tableName: {}", tableName); + } + } + + // ==================== 插入操作 ==================== + + @DS("slave") + @Override + public int insert(String tableName, ShopGoodsDto shopGoods) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (shopGoods == null) { + throw new IllegalArgumentException("商品信息不能为空"); + } + try { + return shopGoodsMapper.insert(tableName, shopGoods); + } catch (Exception e) { + log.error("插入商品失败, tableName: {}", tableName, e); + throw new RuntimeException("插入商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int batchInsert(String tableName, List list) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (CollectionUtils.isEmpty(list)) { + log.warn("批量插入商品列表为空"); + return 0; + } + try { + return shopGoodsMapper.batchInsert(tableName, list); + } catch (Exception e) { + log.error("批量插入商品失败, tableName: {}, size: {}", tableName, list.size(), e); + throw new RuntimeException("批量插入商品失败: " + e.getMessage(), e); + } + } + + // ==================== 删除操作 ==================== + + @DS("slave") + @Override + public int deleteById(String tableName, Long id) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (id == null) { + throw new IllegalArgumentException("ID不能为空"); + } + try { + return shopGoodsMapper.deleteById(tableName, id); + } catch (Exception e) { + log.error("根据ID删除商品失败, tableName: {}, id: {}", tableName, id, e); + throw new RuntimeException("删除商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int deleteByCondition(String tableName, String trilateralId, String isbn, String shopId, String isOnSale) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + return shopGoodsMapper.deleteByCondition(tableName, trilateralId, isbn, shopId, isOnSale); + } catch (Exception e) { + log.error("根据条件删除商品失败, tableName: {}", tableName, e); + throw new RuntimeException("删除商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int batchDeleteByIds(String tableName, List ids) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (CollectionUtils.isEmpty(ids)) { + log.warn("批量删除商品ID列表为空"); + return 0; + } + try { + return shopGoodsMapper.batchDeleteByIds(tableName, ids); + } catch (Exception e) { + log.error("批量删除商品失败, tableName: {}, ids: {}", tableName, ids, e); + throw new RuntimeException("批量删除商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int deleteAll(String tableName) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + return shopGoodsMapper.deleteAll(tableName); + } catch (Exception e) { + log.error("删除所有商品失败, tableName: {}", tableName, e); + throw new RuntimeException("删除所有商品失败: " + e.getMessage(), e); + } + } + + // ==================== 更新操作 ==================== + + @DS("slave") + @Override + public int updateById(String tableName, ShopGoodsDto shopGoods) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (shopGoods == null) { + throw new IllegalArgumentException("商品信息不能为空"); + } + if (shopGoods.getId() == null) { + throw new IllegalArgumentException("商品ID不能为空"); + } + try { + return shopGoodsMapper.updateById(tableName, shopGoods); + } catch (Exception e) { + log.error("根据ID更新商品失败, tableName: {}, id: {}", tableName, shopGoods.getId(), e); + throw new RuntimeException("更新商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int updateOnSaleStatus(String tableName, String trilateralId, String isOnSale) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (!StringUtils.hasText(trilateralId)) { + throw new IllegalArgumentException("商品ID不能为空"); + } + try { + return shopGoodsMapper.updateOnSaleStatus(tableName, trilateralId, isOnSale); + } catch (Exception e) { + log.error("更新上下架状态失败, tableName: {}, trilateralId: {}, isOnSale: {}", tableName, trilateralId, isOnSale, e); + throw new RuntimeException("更新上下架状态失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int batchUpdateOnSaleStatus(String tableName, List trilateralIds, String isOnSale) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (CollectionUtils.isEmpty(trilateralIds)) { + log.warn("批量更新上下架状态商品ID列表为空"); + return 0; + } + try { + return shopGoodsMapper.batchUpdateOnSaleStatus(tableName, trilateralIds, isOnSale); + } catch (Exception e) { + log.error("批量更新上下架状态失败, tableName: {}, size: {}, isOnSale: {}", tableName, trilateralIds.size(), isOnSale, e); + throw new RuntimeException("批量更新上下架状态失败: " + e.getMessage(), e); + } + } + + // ==================== 查询操作 ==================== + + @DS("slave") + @Override + public ShopGoodsDto selectById(String tableName, Long id) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (id == null) { + return null; + } + try { + return shopGoodsMapper.selectById(tableName, id); + } catch (Exception e) { + log.error("根据ID查询商品失败, tableName: {}, id: {}", tableName, id, e); + return null; + } + } + + @DS("slave") + @Override + public ShopGoodsDto selectByTrilateralId(String tableName, String trilateralId) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (!StringUtils.hasText(trilateralId)) { + return null; + } + try { + return shopGoodsMapper.selectByTrilateralId(tableName, trilateralId); + } catch (Exception e) { + log.error("根据商品ID查询失败, tableName: {}, trilateralId: {}", tableName, trilateralId, e); + return null; + } + } + + @DS("slave") + @Override + public List selectByIsbn(String tableName, String isbn) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (!StringUtils.hasText(isbn)) { + return List.of(); + } + try { + return shopGoodsMapper.selectByIsbn(tableName, isbn); + } catch (Exception e) { + log.error("根据ISBN查询商品失败, tableName: {}, isbn: {}", tableName, isbn, e); + return List.of(); + } + } + + @DS("slave") + @Override + public List selectByShopId(String tableName, String shopId) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (!StringUtils.hasText(shopId)) { + return List.of(); + } + try { + return shopGoodsMapper.selectByShopId(tableName, shopId); + } catch (Exception e) { + log.error("根据店铺ID查询商品失败, tableName: {}, shopId: {}", tableName, shopId, e); + return List.of(); + } + } + + @DS("slave") + @Override + public List selectByCondition(String tableName, ShopGoodsDto shopGoodsDto) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + return shopGoodsMapper.selectByCondition(tableName, shopGoodsDto); + } catch (Exception e) { + log.error("分页条件查询商品失败, tableName: {}", tableName, e); + return List.of(); + } + } + + @DS("slave") + @Override + public int selectCountByCondition(String tableName, ShopGoodsDto shopGoodsDto) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + return shopGoodsMapper.selectCountByCondition(tableName, shopGoodsDto); + } catch (Exception e) { + log.error("条件查询商品总数失败, tableName: {}", tableName, e); + return 0; + } + } + + @DS("slave") + @Override + public List selectAll(String tableName) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + return shopGoodsMapper.selectAll(tableName); + } catch (Exception e) { + log.error("查询所有商品失败, tableName: {}", tableName, e); + return List.of(); + } + } + + @DS("slave") + @Override + public int countOnSale(String tableName) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + return shopGoodsMapper.countOnSale(tableName); + } catch (Exception e) { + log.error("统计在售商品数量失败, tableName: {}", tableName, e); + return 0; + } + } + + @DS("slave") + @Override + public int countAll(String tableName) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + try { + return shopGoodsMapper.countAll(tableName); + } catch (Exception e) { + log.error("统计总记录数失败, tableName: {}", tableName, e); + return 0; + } + } + + @DS("slave") + @Override + public ShopGoodsDto selectByGoodsCode(String tableName, String goodsCode) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (!StringUtils.hasText(goodsCode)) { + return null; + } + try { + return shopGoodsMapper.selectByGoodsCode(tableName, goodsCode); + } catch (Exception e) { + log.error("根据商品编码查询失败, tableName: {}, goodsCode: {}", tableName, goodsCode, e); + return null; + } + } + + @DS("slave") + @Override + public ShopGoodsDto selectBySkuCode(String tableName, String skuCode) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (!StringUtils.hasText(skuCode)) { + return null; + } + try { + return shopGoodsMapper.selectBySkuCode(tableName, skuCode); + } catch (Exception e) { + log.error("根据SKU编码查询失败, tableName: {}, skuCode: {}", tableName, skuCode, e); + return null; + } + } + + @DS("slave") + @Override + public List> batchCheckExists(String tableName, List trilateralIds) { + if (!StringUtils.hasText(tableName)) { + throw new IllegalArgumentException("表名不能为空"); + } + if (CollectionUtils.isEmpty(trilateralIds)) { + return List.of(); + } + try { + return shopGoodsMapper.batchCheckExists(tableName, trilateralIds); + } catch (Exception e) { + log.error("批量查询商品是否存在失败, tableName: {}, size: {}", tableName, trilateralIds.size(), e); + return List.of(); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopImgServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopImgServiceImpl.java new file mode 100644 index 0000000..43fcbd7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopImgServiceImpl.java @@ -0,0 +1,156 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.ShopImgBo; +import org.dromara.zhishu.domain.vo.ShopImgVo; +import org.dromara.zhishu.domain.ShopImg; +import org.dromara.zhishu.mapper.ShopImgMapper; +import org.dromara.zhishu.service.IShopImgService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 店铺图片Service业务层处理 + * + * @author yxy + * @date 2025-03-17 + */ +@RequiredArgsConstructor +@Service +public class ShopImgServiceImpl implements IShopImgService { + + private final ShopImgMapper baseMapper; + + /** + * 查询店铺图片 + * + * @param id 主键 + * @return 店铺图片 + */ + @Override + public ShopImgVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 根据店铺id查询店铺图片 + * @param pid + * @return + */ + @Override + public List selectVoByShopId(String pid){ + return baseMapper.selectVoByShopId(pid); + } + + /** + * 分页查询店铺图片列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺图片分页列表 + */ + @Override + public TableDataInfo queryPageList(ShopImgBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的店铺图片列表 + * + * @param bo 查询条件 + * @return 店铺图片列表 + */ + @Override + public List queryList(ShopImgBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(ShopImgBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(ShopImg::getCreateTime); + lqw.eq(bo.getPid() != null, ShopImg::getPid, bo.getPid()); + lqw.eq(StringUtils.isNotBlank(bo.getRelativePath()), ShopImg::getRelativePath, bo.getRelativePath()); + lqw.eq(StringUtils.isNotBlank(bo.getAbsolutePath()), ShopImg::getAbsolutePath, bo.getAbsolutePath()); + lqw.eq(StringUtils.isNotBlank(bo.getType()), ShopImg::getType, bo.getType()); + lqw.eq(bo.getImgOrder() != null, ShopImg::getImgOrder, bo.getImgOrder()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ShopImg::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增店铺图片 + * + * @param bo 店铺图片 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ShopImgBo bo) { + + if(bo.getType().equals("1") || bo.getType().equals("2")){ + deleteByPidAndType(bo.getPid().toString(), bo.getType()); + bo.setImgOrder(Long.parseLong("1")); + } + + ShopImg add = MapstructUtils.convert(bo, ShopImg.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改店铺图片 + * + * @param bo 店铺图片 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ShopImgBo bo) { + ShopImg update = MapstructUtils.convert(bo, ShopImg.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ShopImg entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除店铺图片信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + @Override + public int deleteByPidAndType(String pid, String type) { + return baseMapper.deleteByPidAndType(pid,type); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopServiceImpl.java new file mode 100644 index 0000000..04588dd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopServiceImpl.java @@ -0,0 +1,1221 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import org.dromara.zhishu.util.*; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.pdd.pop.sdk.common.util.JsonUtil; +import jakarta.servlet.http.HttpServletRequest; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.ShopDepot; +import org.dromara.zhishu.domain.bo.*; +import org.dromara.zhishu.domain.dto.request.ErpBaseShopPageGetRequest; +import org.dromara.zhishu.domain.dto.request.UpdateTokenRequest; +import org.dromara.zhishu.domain.dto.response.ErpBaseShopPageGetResponse; +import org.dromara.zhishu.domain.dto.response.GetWlnShopListResponse; +import org.dromara.zhishu.domain.dto.response.WlnBaseResponse; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.mapper.ShopDepotMapper; +import org.dromara.zhishu.mapper.ShopDetailMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.client.WlnClient; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.mapper.ShopMapper; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; +import java.util.Date; +import java.nio.file.Paths; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; +import com.fasterxml.jackson.core.type.TypeReference; + +/** + * 店铺主表Service业务层处理 + * + * @author yxy + * @date 2025-03-10 + */ +@RequiredArgsConstructor +@Service +@Slf4j +public class ShopServiceImpl implements IShopService { + + private final ShopMapper baseMapper; + + private final ShopDetailMapper baseDetailMapper; + + private final WlnClient wlnClient; + + private final IWhiteListService whiteListService; + + private final HttpServletRequest httpServletRequest; + + private final IShopDetailService shopDetailService; + + private final ISpecService specService; + + private final PricingUrlUtil pricingUrlUtil; + + + private final ShopDepotMapper shopDepotMapper; + + private final AtomicLong lastTimestamp = new AtomicLong(0L); + private final AtomicInteger sequence = new AtomicInteger(0); + + + /** + * 查询店铺主表 + * + * @param id 主键 + * @return 店铺主表 + */ + @Override + public ShopVo queryById(Long id) { + ShopVo shopVo = baseMapper.selectVoById(id); + /** + * 咸鱼 + */ + if(shopVo != null && shopVo.getShopType().equals("5")){ + shopVo.setCode(shopVo.getMallId().toString()); + } + + return shopVo; + } + + @Override + public List queryByType(String type, Long userId) { + List list = baseMapper.getShopListByType(type, userId); + return list; + } + + @Override + public ShopVo selectByMallId(String mallId) { + return baseMapper.selectByMallId(mallId); + } + + @Override + public List selectListByMallId(Long mallId){ + return baseMapper.selectListByMallId(mallId); + } + + @Override + public List selectMallIdsById(Long id){ + return baseMapper.selectMallIdsById(id); + } + + @Override + public ShopVo selectByToken(String token) { + return baseMapper.selectByToken(token); + } + + @Override + public ShopVo selectByShopName(String shopName) { + return baseMapper.selectByShopName(shopName); + } + + @Override + public ShopVo selectByGoofishShopKey(String shopKey) { + return baseMapper.selectBygoofishShopName(shopKey); + } + + @Override + public Boolean checkIsExist(String shopKey) { + return baseMapper.checkIsExist(shopKey); + } + + @Override + public List selectByAccount(String account) { + return baseMapper.selectByAccount(account); + } + + /** + * 分页查询店铺主表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺主表分页列表 + */ + @Override + public TableDataInfo queryPageList(ShopBo bo, PageQuery pageQuery) { + // 获取当前用户id + Long userId = bo.getUserId() == null ? LoginHelper.getUserId() : bo.getUserId(); + // 获取白名单 + + if (userId != 1) { + + bo.setCreateBy(userId); + } +// else { +// String ip = httpServletRequest.getHeader("X-Forwarded-For"); +// if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { +// ip = httpServletRequest.getRemoteAddr(); +// } +// System.out.println("当前登录ip为:" + ip); +// // 获取白名单ip +// List list = whiteListService.selectByIp(ip); +// if (list.size() == 0) { +// bo.setCreateBy(userId); +// } +// } + + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage2(pageQuery.build(), lqw); + // 循环查询孔夫子店铺下是否存在待同步商品的Excel文件 + // 获取当前时间戳 + long currentTime = System.currentTimeMillis(); + for (ShopVo shopVo : result.getRecords()) { + if (shopVo.getId() != null) { + ShopDetailVo shopDetailVo = baseDetailMapper.selectVoByShopId(shopVo.getId()); + if (shopDetailVo != null) { + shopVo.setAutoAdd(shopDetailVo.getAutoAdd()); + } + } + if (shopVo.getShopType().equals("2")) { + // 指定读取需要新增的商品Excel文件路径 + String newGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "New_" + shopVo.getId() + "_0.xlsx").toString(); + // 指定读取需要修改的商品Excel文件路径 + String updateGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "Changed_" + shopVo.getId() + "_0.xlsx").toString(); + // 判断redis中是否存在未完成的任务 + String lockKey = "WriteExcelKey_" + shopVo.getId(); + String writeExcelLock = RedisUtils.getCacheObject(lockKey); + // 若获取存在说明存在读取该文件的线程,则直接返回,不进行后续操作 + shopVo.setHasSyncFile(FileUtil.isFileExists(newGoodsExcelPath) || FileUtil.isFileExists(updateGoodsExcelPath) || ObjectUtil.isNotEmpty(writeExcelLock)); + } else { + shopVo.setHasSyncFile(false); + } + + // 查询店铺是否过期,过期则修改店铺状态 + if (shopVo.getExpirationTime() != null + && currentTime > shopVo.getExpirationTime().getTime() + && shopVo.getShopType().equals("1")) { + // 如果当前时间超过到期时间则修改店铺授权状态 + shopVo.setShopAuthorize("2"); + // 修改数据库 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("2"); + updateByBo(shopBo); + } + else if(!shopVo.getShopType().equals("1")){ + if(shopVo.getExpirationTime() != null + && currentTime > shopVo.getExpirationTime().getTime()){ + // 如果当前时间超过到期时间则修改店铺授权状态 + shopVo.setShopAuthorize("2"); + // 修改数据库 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("2"); + updateByBo(shopBo); + } + //校验是否过期 + String result2 = InterfaceUtils.getInterface(UrlUtil.getServiceGoUrl(),"/api/user/getKfzUserRecbusiness?userId="+shopVo.getId()); + Map resultMap = JSONObject.parseObject(result2, Map.class); + if(resultMap.get("message").equals("success")){ + //成功 + Map data = (Map) resultMap.get("data"); +// shopVo.setExpirationTime(new Date((Long) data.get("expirationDate"))); + shopVo.setShopExpirationTime(new Date((Long) data.get("expirationDate"))); + if(!(Boolean) data.get("isVip")){ + //过期,修改店铺设置 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("2"); + updateByBo(shopBo); + } else { + //已过期,续费后修改店铺设置 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("1"); + updateByBo(shopBo); + } + }else{ + if(StringUtils.isEmpty(shopVo.getIsExpiration())){ + //为空赋值0 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("0"); + updateByBo(shopBo); + } + } + } + } + + return TableDataInfo.build(result); + } + + /** + * 分页查询店铺主表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺主表分页列表 + */ + @Override + public TableDataInfo queryPageListInvite(ShopBo bo, PageQuery pageQuery) { + // 获取当前用户id + Long userId = bo.getUserId(); + // 获取白名单 + + if (userId != 1) { + + bo.setCreateBy(userId); + } +// else { +// String ip = httpServletRequest.getHeader("X-Forwarded-For"); +// if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) { +// ip = httpServletRequest.getRemoteAddr(); +// } +// System.out.println("当前登录ip为:" + ip); +// // 获取白名单ip +// List list = whiteListService.selectByIp(ip); +// if (list.size() == 0) { +// bo.setCreateBy(userId); +// } +// } + + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + // 循环查询孔夫子店铺下是否存在待同步商品的Excel文件 + // 获取当前时间戳 + long currentTime = System.currentTimeMillis(); + for (ShopVo shopVo : result.getRecords()) { + if (shopVo.getId() != null) { + ShopDetailVo shopDetailVo = baseDetailMapper.selectVoByShopId(shopVo.getId()); + if (shopDetailVo != null) { + shopVo.setAutoAdd(shopDetailVo.getAutoAdd()); + } + } + if (shopVo.getShopType().equals("2")) { + // 指定读取需要新增的商品Excel文件路径 + String newGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "New_" + shopVo.getId() + "_0.xlsx").toString(); + // 指定读取需要修改的商品Excel文件路径 + String updateGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "Changed_" + shopVo.getId() + "_0.xlsx").toString(); + // 判断redis中是否存在未完成的任务 + String lockKey = "WriteExcelKey_" + shopVo.getId(); + String writeExcelLock = RedisUtils.getCacheObject(lockKey); + // 若获取存在说明存在读取该文件的线程,则直接返回,不进行后续操作 + shopVo.setHasSyncFile(FileUtil.isFileExists(newGoodsExcelPath) || FileUtil.isFileExists(updateGoodsExcelPath) || ObjectUtil.isNotEmpty(writeExcelLock)); + } else { + shopVo.setHasSyncFile(false); + } + + // 查询店铺是否过期,过期则修改店铺状态 + if (shopVo.getExpirationTime() != null + && currentTime > shopVo.getExpirationTime().getTime() + && !shopVo.getShopAuthorize().equals("2") && shopVo.getShopType().equals("1")) { + // 如果当前时间超过到期时间则修改店铺授权状态 + shopVo.setShopAuthorize("2"); + // 修改数据库 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setShopAuthorize("2"); + updateByBo(shopBo); + } + else if(!shopVo.getShopType().equals("1")){ + if(shopVo.getExpirationTime() != null + && currentTime > shopVo.getExpirationTime().getTime() + &&shopVo.getShopType().equals("5")){ + // 如果当前时间超过到期时间则修改店铺授权状态 + shopVo.setShopAuthorize("2"); + // 修改数据库 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setShopAuthorize("2"); + updateByBo(shopBo); + } + //校验是否过期 + String result2 = InterfaceUtils.getInterface(UrlUtil.getServiceGoUrl(),"/api/user/getKfzUserRecbusiness?userId="+shopVo.getId()); + Map resultMap = JSONObject.parseObject(result2, Map.class); + if(resultMap.get("message").equals("success")){ + //成功 + Map data = (Map) resultMap.get("data"); +// shopVo.setExpirationTime(new Date((Long) data.get("expirationDate"))); + shopVo.setShopExpirationTime(new Date((Long) data.get("expirationDate"))); + if(!(Boolean) data.get("isVip")){ + //过期,修改店铺设置 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("2"); + updateByBo(shopBo); + } + }else{ + if(StringUtils.isEmpty(shopVo.getIsExpiration())){ + //为空赋值0 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("0"); + updateByBo(shopBo); + } + } + } + } + + return TableDataInfo.build(result); + } + + + /** + * 查询符合条件的店铺主表列表 + * + * @param bo 查询条件 + * @return 店铺主表列表 + */ + @Override + public List queryList(ShopBo bo) { + Long userId = LoginHelper.getUserId(); + if(userId != 1){ + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List shopVos = baseMapper.selectVoList(lqw); + List shopList = new ArrayList<>(); + for (ShopVo shopVo : shopVos){ + if(shopVo.getShopType().equals("1")){ + shopList.add(shopVo); + }else { + if( StringUtils.isNotEmpty(shopVo.getIsExpiration()) && shopVo.getIsExpiration().equals("1")){ + //校验是否过期 + String result = InterfaceUtils.getInterface(UrlUtil.getServiceGoUrl(),"/api/user/getKfzUserRecbusiness?userId="+shopVo.getId()); + Map resultMap = JSONObject.parseObject(result, Map.class); + if(resultMap.get("message").equals("success")){ + //成功 + Map data = (Map) resultMap.get("data"); + if((Boolean) data.get("isVip")){ + shopVo.setExpirationTime(new Date((Long) data.get("expirationDate"))); + shopVo.setShopExpirationTime(new Date((Long) data.get("expirationDate"))); + shopList.add(shopVo); + }else{ + //过期,修改店铺设置 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setIsExpiration("2"); + updateByBo(shopBo); + } + } + } + } + } + return shopList; + } + + private LambdaQueryWrapper buildQueryWrapper(ShopBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByDesc(Shop::getUpdateTime); + lqw.eq(bo.getCreateBy() != null, Shop::getCreateBy, bo.getCreateBy()); + lqw.eq(StringUtils.isNotBlank(bo.getShopType()), Shop::getShopType, bo.getShopType()); + lqw.like(StringUtils.isNotBlank(bo.getShopGroup()), Shop::getShopGroup, bo.getShopGroup()); + lqw.like(StringUtils.isNotBlank(bo.getShopName()), Shop::getShopName, bo.getShopName()); + lqw.like(StringUtils.isNotBlank(bo.getShopAliasName()), Shop::getShopAliasName, bo.getShopAliasName()); + lqw.eq(StringUtils.isNotBlank(bo.getShopAuthorize()), Shop::getShopAuthorize, bo.getShopAuthorize()); + lqw.eq(bo.getExpirationTime() != null, Shop::getExpirationTime, bo.getExpirationTime()); + lqw.eq(bo.getAddTime() != null, Shop::getAddTime, bo.getAddTime()); + lqw.eq(StringUtils.isNotBlank(bo.getShopKey()), Shop::getShopKey, bo.getShopKey()); + lqw.eq(StringUtils.isNotBlank(bo.getToken()), Shop::getToken, bo.getToken()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Shop::getStatus, bo.getStatus()); + if (!StringUtils.equals(bo.getShopType(), "1") || + (StringUtils.equals(bo.getShopType(), "1") && !StringUtils.equals(bo.getIsExpiration(),"1"))) { + lqw.eq(StringUtils.isNotBlank(bo.getIsExpiration()), Shop::getIsExpiration, bo.getIsExpiration()); + } + return lqw; + } + + /** + * 新增店铺主表 + * + * @param bo 店铺主表 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ShopBo bo) { + //2025-9-19 店铺默认同步订单 + bo.setIsSynOrder(1); + bo.setUpdateTime(DateUtils.getNowDate()); + bo.setUpdateBy(LoginHelper.getUserId()); + if(StringUtils.isEmpty(bo.getShopAuthorize())){ + bo.setShopAuthorize("0"); + } + bo.setAddTime(DateUtils.getNowDate()); + if (StringUtils.isEmpty(bo.getShopGroup())) { + bo.setShopGroup("默认分组"); + } + Shop add = MapstructUtils.convert(bo, Shop.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + + //更新Redis +// String url = "http://localhost:30200/api/updateSourceTable"; + String url = "http://localhost:9099/api/updateSourceTable"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ShopID", bo.getId().toString()); + + // 设置请求头 + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + try { + // 将请求对象转换为JSON字符串 + String jsonBody = HttpUtils.convertObjectToJson(requestBody); + + // 发送POST请求 + String response = HttpUtils.sendPost(url, headers, jsonBody); + System.out.println("调用updateShopHandler接口成功,响应: " + response); + } catch (Exception e) { + System.err.println("调用updateShopHandler接口失败: " + e.getMessage()); + e.printStackTrace(); + } + +// insertShopIntoRedis(bo); + + ShopDetailBo shopDetailBo = new ShopDetailBo(); + shopDetailBo.setShopId(bo.getId()); + if (bo.getShopType().equals("1") || bo.getShopType().equals("5")) { + shopDetailBo.setSystemSetUp(",0,1,2,3,4,5,6,7,8"); + } + shopDetailBo.setHighPrice(999999L); + shopDetailBo.setLowPrice(0L); + shopDetailBo.setDeliveryTime("1"); + shopDetailBo.setConditionDef(85L); + shopDetailBo.setBookTemplate("17"); + shopDetailBo.setTitleConsistOf("1:true,0:true,2:true,3:false,4:false,5:false,6:false"); + shopDetailService.insertByBo(shopDetailBo); + SpecBo specBo = new SpecBo(); + specBo.setShopId(bo.getId()); + specService.insertByBo(specBo); + + + //更新Redis +// String specUrl = "http://localhost:30200/api/updateSpec"; + String specUrl = "http://localhost:9099/api/updateSpec"; + + // 创建请求体,包含ID参数 + Map specRequestBody = new HashMap<>(); + specRequestBody.put("ShopID", bo.getId().toString()); + + // 设置请求头 + Map specHeaders = new HashMap<>(); + specHeaders.put("Content-Type", "application/json"); + + try { + // 将请求对象转换为JSON字符串 + String jsonBody = HttpUtils.convertObjectToJson(specRequestBody); + + // 发送POST请求 + String response = HttpUtils.sendPost(specUrl, specHeaders, jsonBody); + System.out.println("调用updateShopHandler接口成功,响应: " + specRequestBody); + } catch (Exception e) { + System.err.println("调用updateShopHandler接口失败: " + e.getMessage()); + e.printStackTrace(); + } + +// insertSpecIntoRedis(specBo.get); + + return flag; + } + + /** + * 修改店铺主表 + * + * @param bo 店铺主表 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ShopBo bo) { + Shop update = MapstructUtils.convert(bo, Shop.class); + validEntityBeforeSave(update); + boolean flag = baseMapper.updateById(update) > 0; + if (flag) { + // 更新成功后更新Redis中的shop数据 + + //更新Redis +// String url = "http://localhost:30200/api/updateSourceTable"; + String url = "http://localhost:9099/api/updateSourceTable"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ShopID", bo.getId().toString()); + + // 设置请求头 + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + try { + // 将请求对象转换为JSON字符串 + String jsonBody = HttpUtils.convertObjectToJson(requestBody); + + // 发送POST请求 + String response = HttpUtils.sendPost(url, headers, jsonBody); + System.out.println("调用updateShopHandler接口成功,响应: " + response); + } catch (Exception e) { + System.err.println("调用updateShopHandler接口失败: " + e.getMessage()); + e.printStackTrace(); + } + +// insertShopIntoRedis(bo); + } + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(Shop entity) { + // TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除店铺主表信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + @Override + public int selectShopAssociationMall(ShopBo shopBo) { + int mark = 0; + ShopVo shopVo = baseMapper.selectByMallId(shopBo.getMallId().toString()); + if (shopVo == null) { + Shop update = MapstructUtils.convert(shopBo, Shop.class); + mark = baseMapper.updateById(update); + } else if (shopVo.getId().equals(shopBo.getId())) { + Shop update = MapstructUtils.convert(shopBo, Shop.class); + mark = baseMapper.updateById(update); + } + return mark; + } + + @Override + public Boolean updateTime(Long shopId, Long startUpdatedAt) { + return new LambdaUpdateChainWrapper<>(baseMapper) + .eq(Shop::getId, shopId) + .eq(Shop::getDelFlag, "0") + .eq(Shop::getStatus, "0") + .set(Shop::getStartUpdatedAt, startUpdatedAt) + .update(); + } + + @Override + public ShopVo queryByMailId(Long mailId, Integer shopType) { + List list = new LambdaQueryChainWrapper<>(baseMapper) + .eq(Shop::getMallId, mailId) + .eq(Shop::getShopType, shopType.toString()) + .list(); + if(ObjectUtil.isEmpty(list)){ + return null; + } + return MapstructUtils.convert(list.get(0), ShopVo.class); + } + + @Override + public ShopVo queryByMailIdbyUseing(Long mailId, Integer shopType) { + List list = new LambdaQueryChainWrapper<>(baseMapper) + .eq(Shop::getMallId, mailId) + .eq(Shop::getDelFlag, "0") + .eq(Shop::getShopType, shopType.toString()) + .list(); + if(ObjectUtil.isEmpty(list)){ + return null; + } + return MapstructUtils.convert(list.get(0), ShopVo.class); + } + + @Override + public Boolean updateToken(UpdateTokenRequest request) { + return new LambdaUpdateChainWrapper<>(baseMapper) + .eq(Shop::getId, request.getShopId()) + .eq(Shop::getShopType, request.getShopType()) + .set(Shop::getToken, request.getAccessToken()) + .set(Shop::getRefreshToken, request.getRefreshToken()) + .set(Shop::getExpirationTime, request.getExpirationTime()) + .update(); + } + + @Override + public List getShopId(Long userId) { + return baseMapper.getShopIdByUserId(userId); + } + + @Override + public List getShopIdByUserIdAndExpirationTime(Long userId) { + return baseMapper.getShopIdByUserIdAndExpirationTime(userId); + } + + @Override + public List selectCorrelationByUserId(Long userId){ + return baseMapper.selectCorrelationByUserId(userId); + } + + @Override + public Boolean updateShopIsSynOrder(Long shopId, int status) { + return new LambdaUpdateChainWrapper<>(baseMapper) + .eq(Shop::getId, shopId) + .eq(Shop::getDelFlag, "0") + .eq(Shop::getStatus, "0") + .set(Shop::getIsSynOrder, status) + .update(); + } + + @Override + public List getWlnShopList(Integer page, Integer limit, Long shopId, String shopNick) { + ShopVo shopVo = queryById(shopId); + if (!shopVo.getShopType().equals("3")) throw new ServiceException("非万里牛店铺类型"); + ErpBaseShopPageGetRequest request = new ErpBaseShopPageGetRequest(); + request.setPage(page); + request.setLimit(limit); + if (ObjectUtil.isNotEmpty(shopNick)) request.setShopNick(shopNick); + WlnBaseResponse> resp = wlnClient.erpBaseShopPageGet(UrlUtil.getWlnServiceUrl(), shopVo.getAccount(), shopVo.getPassword(), request); + if (resp.getCode() != 0) throw new ServiceException("获取万里牛店铺列表失败:" + resp.getMessage()); + if (ObjectUtil.isNotEmpty(resp.getData())) { + return resp.getData().stream().map(item -> { + GetWlnShopListResponse response = new GetWlnShopListResponse(); + response.shopName = item.getShopName(); + response.shopNick = item.getShopNick(); + return response; + }).collect(Collectors.toList()); + } else { + return new ArrayList<>(); + } + } + + @Override + public Boolean authorizationWln(Long shopId, String shopName, String shopNick) { + ShopVo shopVo = queryById(shopId); + if (!shopVo.getShopType().equals("3")) throw new ServiceException("店铺类型错误"); + new LambdaUpdateChainWrapper<>(baseMapper) + .eq(Shop::getShopNike, shopNick) + .eq(Shop::getDelFlag, "0") + .set(Shop::getShopAuthorize, "0") + .set(Shop::getShopNike, "") + .set(Shop::getShopAliasName, "") + .update(); + return new LambdaUpdateChainWrapper<>(baseMapper) + .eq(Shop::getId, shopId) + .eq(Shop::getDelFlag, "0") + .set(Shop::getShopAuthorize, "1") + .set(Shop::getShopNike, shopNick) + .set(Shop::getShopAliasName, shopName) + .update(); + + } + + /** + * 加密 + * + * @param bo + * @return + */ + @Override + public Map encryptionData(EncryptionDataBo bo) throws JsonProcessingException { + Map map = new HashMap<>(); + // 通过店铺id查询店铺信息 + ShopVo shopVo = new ShopVo(); + List encryptionUrlList= new ArrayList<>(); + for (Long shopId : bo.getShopId()){ + + if (shopId != null) { + shopVo = queryById(shopId); + if (shopVo != null) { + try{ + PriceTemplateVo priceTemplateVo = baseMapper.selectByName(shopId); + map.put("name", priceTemplateVo.getTemplateName()); + bo.setShopType(shopVo.getShopType()); + bo.setShopToken(shopVo.getToken()); + bo.setMallId(shopVo.getMallId()); + bo.setShopKey(shopVo.getShopKey()); + }catch (Exception e){ + throw new RuntimeException("店铺未设置价格模板"); + } + } + } + String encryptionUrl = getUrlList1(bo,shopId); + if (bo.getShopType().equals("1") || bo.getShopType().equals("5")) { + encryptionUrlList.add(encryptionUrl); + } + + } + String pricUrl = pricingUrlUtil.getPricingUrlList(encryptionUrlList); + System.out.println(pricUrl); + map.put("url", pricUrl); + + return map; + } + + /** + * · + * 解密 + * + * @param data + * @return + */ + @Override + public DecryptDataVo decryptionData(String data) { + DecryptDataVo decryptDataVo = new DecryptDataVo(); + try { + String decrypt = pricingUrlUtil.decrypt(data); + return JSONObject.parseObject(decrypt, DecryptDataVo.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public JSONObject decryptDataVoList(String data) { + JSONObject result = new JSONObject(); + try { + String dec = pricingUrlUtil.decrypt(data); + ObjectMapper mapper = new ObjectMapper(); + + // 先判断是数组还是对象 + // JsonNode rootNode = mapper.readTree(dec); + + // if (rootNode.isArray()) { + // 先解析为字符串列表 + List jsonStringList = mapper.readValue(dec, new TypeReference>() {}); + List list = new ArrayList<>(); + for (String jsonString : jsonStringList) { + // 将每个字符串解析为DecryptDataVo对象 + DecryptDataVo item = mapper.readValue(jsonString, DecryptDataVo.class); + list.add(item); + } + JSONArray jsonArray = new JSONArray(); + for (DecryptDataVo item : list) { + JSONObject jsonObject = JsonUtil.transferToObj(JsonUtil.transferToJson(item), JSONObject.class); + jsonArray.add(jsonObject); + } + result.put("data", jsonArray); + result.put("code", 200); + result.put("msg", "成功获取解密"); + // } else { + // // 原有逻辑处理对象情况 + // // 单个对象 + // DecryptDataVo vo = mapper.readValue(dec, DecryptDataVo.class); + // JSONObject voJson = JsonUtil.transferToObj(JsonUtil.transferToJson(vo), JSONObject.class); + // result.put("code", 200); + // result.put("msg", "成功获取解密"); + // result.put("data", voJson); + // + // } + } catch (Exception e) { + result.put("code", 500); + result.put("msg", e.getMessage()); + throw new RuntimeException("数据解析失败: " + e.getMessage(), e); + } + return result; + } + + @Override + public Object getDecryptedUrlList(String data) { + try { + JSONObject result = new JSONObject(); + String dec = pricingUrlUtil.decrypt(data); + ObjectMapper mapper = new ObjectMapper(); + + // 先判断是数组还是对象 + JsonNode rootNode = mapper.readTree(dec); + + if (rootNode.isArray()) { + + // 先解析为字符串列表 + List jsonStringList = mapper.readValue(dec, new TypeReference>() {}); + + List list = new ArrayList<>(); + for (String jsonString : jsonStringList) { + // 将每个字符串解析为DecryptDataVo对象 + DecryptDataVo item = mapper.readValue(jsonString, DecryptDataVo.class); + list.add(item); + } + JSONArray jsonArray = new JSONArray(); + for (DecryptDataVo item : list) { + JSONObject jsonObject = JsonUtil.transferToObj(JsonUtil.transferToJson(item), JSONObject.class); + jsonArray.add(jsonObject); + } + + return jsonArray; + } else { + // 原有逻辑处理对象情况 + // 单个对象 + DecryptDataVo vo = mapper.readValue(dec, DecryptDataVo.class); + JSONObject voJson = JsonUtil.transferToObj(JsonUtil.transferToJson(vo), JSONObject.class); + return voJson; + } + } catch (Exception e) { + throw new RuntimeException("数据解析失败: " + e.getMessage(), e); + } + } + + @Override + public void updateTokenByPddMallId(String pddMallId, String accessToken) { + Shop shop = baseMapper.selectShopByPddMallId(pddMallId); + shop.setToken(accessToken); + new LambdaUpdateChainWrapper<>(baseMapper) + .eq(Shop::getId, shop.getId()) + .eq(Shop::getDelFlag, "0") + .set(Shop::getToken, accessToken) + .update(); + } + + @Override + public int updateShopSkuSpec(String id, String skuSpec) { + return baseMapper.updateShopSkuSpec(id, skuSpec); + } + + /** + * 加密拼接数据 + * + * @param bo + * @return + */ + private String getUrl(EncryptionDataBo bo) { + DecryptDataVo decryptDataVo = new DecryptDataVo(); + + decryptDataVo.setUrl(bo.getShopId().get(0)); + decryptDataVo.setShopId(bo.getShopId().get(0)); + decryptDataVo.setPrePrice(bo.getShopPrice()); + decryptDataVo.setMaxPerice(bo.getMaxPrice()); + decryptDataVo.setMinPerice(bo.getMinPrice()); + decryptDataVo.setType(Integer.valueOf(bo.getShopType())); + decryptDataVo.setTotalCount( bo.getTotalCount().get( bo.getShopId().get(0).toString() ).longValue() ); + decryptDataVo.setShopToken(bo.getShopToken()); + decryptDataVo.setIsOnSale(bo.getIsOnSale()); + decryptDataVo.setIsbn(bo.getIsbn()); + decryptDataVo.setPriceDown(bo.getPriceDown()); + decryptDataVo.setPriceUp(bo.getPriceUp()); + decryptDataVo.setStartDate(bo.getStartDate()); + decryptDataVo.setEndDate(bo.getEndDate()); + return JSONObject.toJSONString(decryptDataVo); + } + + /** + * 加密拼接数据 + * + * @param bo + * @return + */ + private String getUrl1(EncryptionDataBo bo) throws JsonProcessingException { + // Map 转 JSON 字符串 + ObjectMapper objectMapper = new ObjectMapper(); + Map dataMap = new HashMap<>(); + dataMap.put("url", bo.getShopId().get(0)); + dataMap.put("shopId", bo.getShopId().get(0)); + dataMap.put("prePrice", bo.getShopPrice()); + dataMap.put("maxPerice",bo.getMaxPrice()); + dataMap.put("minPerice", bo.getMinPrice()); + dataMap.put("type",Integer.valueOf(bo.getShopType())); + dataMap.put("totalCount", bo.getTotalCount().get( bo.getShopId().get(0).toString() ).longValue() ); + dataMap.put("shopToken", bo.getShopToken()); + + dataMap.put("isOnSale", bo.getIsOnSale()); + dataMap.put("isbn", bo.getIsbn()); + dataMap.put("priceDown", bo.getPriceDown()); + dataMap.put("priceUp", bo.getPriceUp()); + dataMap.put("startDate", bo.getStartDate()); + dataMap.put("endDate", bo.getEndDate()); + // Map 转 JSON 字符串 + String jsonString = objectMapper.writeValueAsString(dataMap); + return jsonString; + } + + + + /** + * 加密拼接数据 + * + * @param bo + * @return + */ + private String getUrlList(EncryptionDataBo bo,Long dataUrl) { + DecryptDataVo decryptDataVo = new DecryptDataVo(); + decryptDataVo.setUrl(dataUrl); + decryptDataVo.setShopId(dataUrl); + decryptDataVo.setPrePrice(bo.getShopPrice()); + decryptDataVo.setMaxPerice(bo.getMaxPrice()); + decryptDataVo.setMinPerice(bo.getMinPrice()); + decryptDataVo.setType(Integer.valueOf(bo.getShopType())); + + // decryptDataVo.setTotalCount(Long.parseLong(bo.getTotalCount().get(dataUrl).toString())); +// 方案2:使用Optional更安全的写法 + decryptDataVo.setTotalCount( + Optional.ofNullable(bo.getTotalCount().get(dataUrl.toString())) + .map(Integer::longValue) + .orElse(0L) + ); + + + decryptDataVo.setShopToken(bo.getShopToken()); + decryptDataVo.setIsOnSale(bo.getIsOnSale()); + decryptDataVo.setIsbn(bo.getIsbn()); + decryptDataVo.setPriceDown(bo.getPriceDown()); + decryptDataVo.setPriceUp(bo.getPriceUp()); + decryptDataVo.setStartDate(bo.getStartDate()); + decryptDataVo.setEndDate(bo.getEndDate()); + return JSONObject.toJSONString(decryptDataVo); + } + + private String getUrlList1(EncryptionDataBo bo,Long dataUrl) throws JsonProcessingException { + + // Map 转 JSON 字符串 + ObjectMapper objectMapper = new ObjectMapper(); + Map dataMap = new HashMap<>(); + + dataMap.put("url", dataUrl); + dataMap.put("shopId",dataUrl); + dataMap.put("mallId",bo.getMallId()); + dataMap.put("shopKey",StringUtils.isEmpty(bo.getShopKey()) ? "" : bo.getShopKey()); + dataMap.put("prePrice", bo.getShopPrice()); + dataMap.put("maxPerice",bo.getMaxPrice()); + dataMap.put("minPerice", bo.getMinPrice()); + dataMap.put("type",Integer.valueOf(bo.getShopType())); + dataMap.put("totalCount", Optional.ofNullable(bo.getTotalCount().get(dataUrl.toString())) + .map(Integer::longValue) + .orElse(0L)); + dataMap.put("shopToken", bo.getShopToken()); + + dataMap.put("isOnSale", bo.getIsOnSale()); + dataMap.put("isbn", bo.getIsbn()); + dataMap.put("priceDown", bo.getPriceDown()); + dataMap.put("priceUp", bo.getPriceUp()); + dataMap.put("startDate", bo.getStartDate()); + dataMap.put("endDate", bo.getEndDate()); + + dataMap.put("goodsName",bo.getGoodsName()); ; + dataMap.put("stockDown",bo.getStockDown()); ; + dataMap.put("stockUp",bo.getStockUp()); ; + dataMap.put("trilateralId",bo.getTrilateralId()); ; + dataMap.put("goodsCode",bo.getGoodsCode()); ; + dataMap.put("skuCode",bo.getSkuCode()); ; + + + + + // Map 转 JSON 字符串 + String jsonString = objectMapper.writeValueAsString(dataMap); + return jsonString; + } + + + + + + @Override + public List getShopDepotByShopId(Long shopId) { + return shopDepotMapper.selectByShopId(shopId); + } + + @Override + public boolean bindDepotToShop(Long shopId, List depotIds) { + try { + Long userId = LoginHelper.getUserId(); + + // 先删除该店铺所有原有的绑定关系 + shopDepotMapper.deleteByShopId(shopId); + + // 批量插入新的绑定关系 + List shopDepots = new ArrayList<>(); + Date now = new Date(); + + for (Long depotId : depotIds) { + ShopDepot shopDepot = new ShopDepot(); + + shopDepot.setId(Long.parseLong(generate19DigitTimestampSafe())); + shopDepot.setShopId(shopId); + shopDepot.setDepotId(depotId); + shopDepot.setCreateBy(userId); + shopDepot.setCreateTime(now); + shopDepot.setUpdateBy(userId); + shopDepot.setUpdateTime(now); + shopDepots.add(shopDepot); + } + + // 批量插入 + int result = shopDepotMapper.insertBatch(shopDepots); + + return result > 0; + } catch (Exception e) { + log.error("绑定仓库失败", e); + return false; + } + } + + private String generate19DigitTimestampSafe() { + long currentTimestamp = System.currentTimeMillis(); + long lastTs = lastTimestamp.get(); + + // 如果当前时间戳与上次相同,则递增序列号 + if (currentTimestamp == lastTs) { + int seq = sequence.incrementAndGet(); + if (seq > 999999) { + // 序列号溢出,等待到下一毫秒 + while (currentTimestamp <= lastTs) { + currentTimestamp = System.currentTimeMillis(); + } + sequence.set(0); + seq = 0; + } + lastTimestamp.set(currentTimestamp); + return currentTimestamp + String.format("%06d", seq); + } else { + // 时间戳变化,重置序列号 + sequence.set(0); + lastTimestamp.set(currentTimestamp); + return currentTimestamp + "000000"; + } + } + + /** + * 向redis,db7中添加t_spec数据 + * @param bo + */ +// public void insertSpecIntoRedis(SpecBo bo){ +// if (ObjectUtil.isEmpty(bo) || bo.getShopId() == null) { +// return; +// } +// +// try { +// String redisKey = bo.getShopId().toString(); +// // 构建t_spec数据结构 +// Map specData = new LinkedHashMap<>(); +// specData.put("source_table", "t_spec"); +// specData.put("data", bo); +// String specJson = JsonObjUtil.objectToJsonWithSnakeKeys(specData); +// +// // 获取Redis中的List +// org.redisson.api.RList redisList = RedisUtils.getThirdClient().getList(redisKey); +// boolean updated = false; +// +// // 遍历List,更新对应source_table的数据 +// for (int i = 0; i < redisList.size(); i++) { +// String item = redisList.get(i); +// Map itemMap = JSONUtil.toBean(item, Map.class); +// if ("t_spec".equals(itemMap.get("source_table"))) { +// redisList.set(i, specJson); +// updated = true; +// break; +// } +// } +// +// // 如果没有找到对应数据,则添加新元素 +// if (!updated) { +// redisList.add(specJson); +// } +// +// } catch (Exception e) { +// System.out.println(e.getMessage()); +// } +// } + + /** + * 向redis,db7中添加t_shop数据 + * @param bo + */ +// public void insertShopIntoRedis(ShopBo bo){ +// if (ObjectUtil.isEmpty(bo) || bo.getId() == null) { +// return; +// } +// +// try { +// String redisKey = bo.getId().toString(); +// // 构建t_shop数据结构 +// Map shopData = new LinkedHashMap<>(); +// shopData.put("source_table", "t_shop"); +// shopData.put("data", bo); +// String shopJson = JsonObjUtil.objectToJsonWithSnakeKeys(shopData); +// +// // 获取Redis中的List +// org.redisson.api.RList redisList = RedisUtils.getThirdClient().getList(redisKey); +// boolean updated = false; +// +// // 遍历List,更新对应source_table的数据 +// for (int i = 0; i < redisList.size(); i++) { +// String item = redisList.get(i); +// Map itemMap = JSONUtil.toBean(item, Map.class); +// if ("t_shop".equals(itemMap.get("source_table"))) { +// redisList.set(i, shopJson); +// updated = true; +// break; +// } +// } +// +// // 如果没有找到对应数据,则添加新元素 +// if (!updated) { +// redisList.add(shopJson); +// } +// +// } catch (Exception e) { +// System.out.println(e.getMessage()); +// } +// } + + + /** + * 查看调用次数 + * @param shopVo 店铺 + * @return + */ + @Override + public Long checkUsageCount(ShopVo shopVo){ + if (shopVo.getShopType().equals("1") && shopVo.getSkuSpec().contains("7天") && shopVo.getDeregulation().equals("1")){ + // 如果是7天 未开启限免,则返回500 - 已使用次数 + Long usageCount = shopVo.getUsageCount() == null ? 0 : shopVo.getUsageCount(); + return new BigDecimal(500).subtract(new BigDecimal(usageCount)).longValue(); + }else{ + return 9999999L; + } + } + + /** + * 修改调用次数 + * @param shopVo + * @param usageCount + */ + @Override + public void updateUsageCount(ShopVo shopVo ,Long usageCount){ + if (shopVo.getShopType().equals("1") && shopVo.getSkuSpec().contains("7天") && shopVo.getDeregulation().equals("1")){ + // 更新使用次数 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + Long newUsageCount = 500 - usageCount; + shopBo.setUsageCount(newUsageCount); + updateByBo(shopBo); + } + } + + + @Override + public List selectByIds(List ids){ + return baseMapper.selectByIds(ids); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopWarehouseAutoServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopWarehouseAutoServiceImpl.java new file mode 100644 index 0000000..d41b331 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopWarehouseAutoServiceImpl.java @@ -0,0 +1,103 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.zhishu.domain.ShopWarehouse; +import org.dromara.zhishu.domain.ShopWarehouseAuto; +import org.dromara.zhishu.domain.bo.ShopWarehouseBo; +import org.dromara.zhishu.domain.vo.ShopWarehouseVo; +import org.dromara.zhishu.mapper.ShopWarehouseAutoMapper; +import org.dromara.zhishu.mapper.ShopWarehouseMapper; +import org.dromara.zhishu.service.IShopWarehouseAutoService; +import org.dromara.zhishu.service.IShopWarehouseService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 店铺与仓库自动发布关联Service业务层处理 + * + * @author yxy + * @date 2025-12-28 + */ +@RequiredArgsConstructor +@Service +public class ShopWarehouseAutoServiceImpl implements IShopWarehouseAutoService { + + private final ShopWarehouseAutoMapper baseMapper; + + /** + * 查询店铺与仓库自动发布关联 + * + * @param id 主键 + * @return 店铺与仓库自动发布关联 + */ + @Override + @DS("psi") + public ShopWarehouseAuto queryById(Long id) { + return baseMapper.selectById(id); + } + + + /** + * 查询列表 + * @param bo + * @return + */ + @Override + @DS("psi") + public List queryList(ShopWarehouseAuto bo){ + return baseMapper.selectList(bo); + } + + /** + * 根据店铺ID查询关联列表 + * + * @param shopId 店铺ID + * @return 关联列表 + */ + @Override + @DS("psi") + public List queryListByShopId(Long shopId) { + return baseMapper.selectByShopId(shopId); + } + + /** + * 新增店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否新增成功 + */ + @Override + @DS("psi") + public Boolean insertByBo(ShopWarehouseAuto bo) { + return baseMapper.insert(bo) > 0; + } + + /** + * 修改店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否修改成功 + */ + @Override + @DS("psi") + public Boolean updateByBo(ShopWarehouseAuto bo) { + return baseMapper.update(bo) > 0; + } + + /** + * 根据店铺删除关联信息 + * @param shopId 店铺ID + * @return 是否删除成功 + */ + @Override + @DS("psi") + public Boolean deleteByShopId(Long shopId) { + return baseMapper.deleteByShopId(shopId) > 0; + } + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SinglePrintServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SinglePrintServiceImpl.java new file mode 100644 index 0000000..409e6e6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SinglePrintServiceImpl.java @@ -0,0 +1,206 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.SinglePrint; +import org.dromara.zhishu.domain.bo.SinglePrintBo; +import org.dromara.zhishu.service.ISinglePrintService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Collection; +import java.util.Map; + +/** + * 单票打印Service业务层处理 + * + * @author yxy + * @date 2026-03-27 + */ +@RequiredArgsConstructor +@Service +public class SinglePrintServiceImpl implements ISinglePrintService { + + /** + * 查询单票打印 + * + * @param id 主键 + * @return 单票打印 + */ + @Override + public SinglePrint queryById(Long id) { + String singlePrintStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getOrderServiceUrl(), + "/api/singlePrint/" + id, + new HashMap<>() + ); + return JsonUtil.transferToObj(singlePrintStr, SinglePrint.class); + } + + /** + * 根据快递单号查询 + * + * @param mailNo 快递单号 + * @return 单票打印 + */ + @Override + public SinglePrint queryByMailNo(String mailNo) { + String singlePrintStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getOrderServiceUrl(), + "/api/singlePrint/getByMailNo/" + mailNo, + new HashMap<>() + ); + return JsonUtil.transferToObj(singlePrintStr, SinglePrint.class); + } + + /** + * 分页查询单票打印列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 单票打印分页列表 + */ + @Override + public TableDataInfo queryPageList(SinglePrintBo bo, PageQuery pageQuery) { + Map params = new HashMap<>(); + params.put("pageNum", pageQuery.getPageNum()); + params.put("pageSize", pageQuery.getPageSize()); + + // 添加查询条件 + if (bo.getId() != null) { + params.put("id", bo.getId()); + } + if (bo.getMailNo() != null && !bo.getMailNo().isEmpty()) { + params.put("mailNo", bo.getMailNo()); + } + if (bo.getSenderName() != null && !bo.getSenderName().isEmpty()) { + params.put("senderName", bo.getSenderName()); + } + if (bo.getSenderPhone() != null && !bo.getSenderPhone().isEmpty()) { + params.put("senderPhone", bo.getSenderPhone()); + } + if (bo.getReceiverName() != null && !bo.getReceiverName().isEmpty()) { + params.put("receiverName", bo.getReceiverName()); + } + if (bo.getReceiverPhone() != null && !bo.getReceiverPhone().isEmpty()) { + params.put("receiverPhone", bo.getReceiverPhone()); + } + if (bo.getItemName() != null && !bo.getItemName().isEmpty()) { + params.put("itemName", bo.getItemName()); + } + if (bo.getFastMailId() != null) { + params.put("fastMailId", bo.getFastMailId()); + } + + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + params.put("createBy",userId); + } + + + String singlePrintListStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getOrderServiceUrl(), + "/api/singlePrint/getList", + params + ); + Map dataMap = JsonUtil.transferToObj(singlePrintListStr, Map.class); + List singlePrintList = (List) dataMap.get("data"); + int total = (int) dataMap.get("total"); + + Page result = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize(), total); + result.setRecords(singlePrintList); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的单票打印列表 + * + * @param bo 查询条件 + * @return 单票打印列表 + */ + @Override + public List queryList(SinglePrintBo bo) { + Map params = new HashMap<>(); + + // 添加查询条件 + if (bo.getId() != null) { + params.put("id", bo.getId()); + } + if (bo.getMailNo() != null && !bo.getMailNo().isEmpty()) { + params.put("mailNo", bo.getMailNo()); + } + if (bo.getSenderName() != null && !bo.getSenderName().isEmpty()) { + params.put("senderName", bo.getSenderName()); + } + if (bo.getSenderPhone() != null && !bo.getSenderPhone().isEmpty()) { + params.put("senderPhone", bo.getSenderPhone()); + } + if (bo.getReceiverName() != null && !bo.getReceiverName().isEmpty()) { + params.put("receiverName", bo.getReceiverName()); + } + if (bo.getReceiverPhone() != null && !bo.getReceiverPhone().isEmpty()) { + params.put("receiverPhone", bo.getReceiverPhone()); + } + if (bo.getItemName() != null && !bo.getItemName().isEmpty()) { + params.put("itemName", bo.getItemName()); + } + if (bo.getFastMailId() != null) { + params.put("fastMailId", bo.getFastMailId()); + } + if (bo.getCreateBy() != null) { + params.put("createBy", bo.getCreateBy()); + } + + String singlePrintListStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getOrderServiceUrl(), + "/api/singlePrint/getList", + params + ); + Map dataMap = JsonUtil.transferToObj(singlePrintListStr, Map.class); + return (List) dataMap.get("data"); + } + + + + /** + * 校验并批量删除单票打印信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + for (Long id : ids) { + InterfaceUtils.postForm( + UrlUtil.getOrderServiceUrl(), + "/api/singlePrint/deleteById/" + id, + new HashMap<>() + ); + } + return true; + } + + /** + * 根据快递单号删除 + * + * @param mailNo 快递单号 + * @return 是否删除成功 + */ + @Override + public Boolean deleteByMailNo(String mailNo) { + InterfaceUtils.postForm( + UrlUtil.getOrderServiceUrl(), + "/api/singlePrint/deleteByMailNo/" + mailNo, + new HashMap<>() + ); + return true; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SyncLogServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SyncLogServiceImpl.java new file mode 100644 index 0000000..3bc4795 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SyncLogServiceImpl.java @@ -0,0 +1,83 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.domain.SyncLog; +import org.dromara.zhishu.mapper.SyncLogMapper; +import org.dromara.zhishu.service.ISyncLogService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 迁移日志Service业务层处理 + * + * @author yxy + * @date 2026-06-06 + */ +@RequiredArgsConstructor +@Service +public class SyncLogServiceImpl implements ISyncLogService { + + private final SyncLogMapper baseMapper; + + /** + * 根据ID查询迁移日志 + * + * @param id 主键 + * @return 迁移日志 + */ + @Override + @DS("psi") + public SyncLog queryById(Long id) { + return baseMapper.selectById(id); + } + + /** + * 查询迁移日志列表 + * + * @param bo 查询条件 + * @return 迁移日志列表 + */ + @Override + @DS("psi") + public List queryList(SyncLog bo) { + return baseMapper.selectList(bo); + } + + /** + * 新增迁移日志 + * + * @param bo 迁移日志 + * @return 是否新增成功 + */ + @Override + @DS("psi") + public Boolean insertByBo(SyncLog bo) { + return baseMapper.insert(bo) > 0; + } + + /** + * 修改迁移日志 + * + * @param bo 迁移日志 + * @return 是否修改成功 + */ + @Override + @DS("psi") + public Boolean updateByBo(SyncLog bo) { + return baseMapper.update(bo) > 0; + } + + /** + * 根据ID删除迁移日志 + * + * @param id 主键 + * @return 是否删除成功 + */ + @Override + @DS("psi") + public Boolean deleteById(Long id) { + return baseMapper.deleteById(id) > 0; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SynchronizationShopLogServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SynchronizationShopLogServiceImpl.java new file mode 100644 index 0000000..cb6a3f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SynchronizationShopLogServiceImpl.java @@ -0,0 +1,204 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.bo.SynchronizationShopLogBo; +import org.dromara.zhishu.domain.vo.SynchronizationShopLogVo; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; +import org.dromara.zhishu.service.ISynchronizationShopLogService; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 同步店铺商品库存日志Service业务层处理 + * + * @author yxy + * @date 2026-04-14 + */ +@RequiredArgsConstructor +@Service +public class SynchronizationShopLogServiceImpl implements ISynchronizationShopLogService { + + private final IZhishuShopGoodsService zhishuShopGoodsService; + + /** + * 查询同步店铺商品库存日志 + * + * @param id 主键 + * @return 同步店铺商品库存日志 + */ + @Override + public SynchronizationShopLogVo queryById(Long id) { + String logStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getOrderServiceUrl(), + "/api/synchronizationShopLog/" + id, + new HashMap<>() + ); + return JsonUtil.transferToObj(logStr, SynchronizationShopLogVo.class); + } + + /** + * 分页查询同步店铺商品库存日志列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 同步店铺商品库存日志分页列表 + */ + @Override + public TableDataInfo> queryPageList(SynchronizationShopLogBo bo, PageQuery pageQuery) { + Map params = new HashMap<>(); + params.put("pageNum", pageQuery.getPageNum()); + params.put("pageSize", pageQuery.getPageSize()); + + // 添加查询条件 + if (bo.getGoodsId() != null) { + params.put("goodsId", bo.getGoodsId()); + } + if (bo.getGoodsCreateBy() != null) { + params.put("goodsCreateBy", bo.getGoodsCreateBy()); + } + if (bo.getErpOrderId() != null) { + params.put("erpOrderId", bo.getErpOrderId()); + } + if (bo.getOrderSn() != null && !bo.getOrderSn().isEmpty()) { + params.put("orderSn", bo.getOrderSn()); + } + if (bo.getShopId() != null) { + params.put("shopId", bo.getShopId()); + } + if (bo.getShopName() != null && !bo.getShopName().isEmpty()) { + params.put("shopName", bo.getShopName()); + } + if (bo.getShopCreateBy() != null) { + params.put("shopCreateBy", bo.getShopCreateBy()); + } + if (bo.getPlatformId() != null) { + params.put("platformId", bo.getPlatformId()); + } + if (bo.getCode() != null && !bo.getCode().isEmpty()) { + params.put("code", bo.getCode()); + } + + + Long userId = LoginHelper.getUserId(); + if (userId != 1){ + params.put("userId",userId); + } + + String logListStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getOrderServiceUrl(), + "/api/synchronizationShopLog/getList", + params + ); + + // 解析返回的数据 + Map dataMap = JsonUtil.transferToObj(logListStr, Map.class); + + // 获取 data 列表(直接作为 Map 列表) + List> logList = (List>) dataMap.get("data"); + int total = (int) dataMap.get("total"); + + // 提取所有的 goodsId(从 Map 中获取) + if (logList != null && !logList.isEmpty()) { + List goodsIds = logList.stream() + .map(item -> item.get("goodsId")) + .filter(Objects::nonNull) + .map(Object::toString) + .map(String::valueOf) + .distinct() + .collect(Collectors.toList()); + + // 批量查询商品信息 + if (!goodsIds.isEmpty()) { + List goodsList = zhishuShopGoodsService.selectByIds(goodsIds); + + // 将商品信息转换为 Map,key 为 String 类型的 ID + Map goodsMap = goodsList.stream() + .filter(goods -> goods.getId() != null) + .collect(Collectors.toMap( + goods -> String.valueOf(goods.getId()), + Function.identity(), + (existing, replacement) -> existing + )); + + // 回填信息到 logList 的每个 Map 中 + for (Map logItem : logList) { + Object goodsIdObj = logItem.get("goodsId"); + if (goodsIdObj != null) { + String goodsIdStr = String.valueOf(goodsIdObj); + ZhishuShopGoodsVo goods = goodsMap.get(goodsIdStr); + if (goods != null) { + logItem.put("zhishuShopGoodsVo",goods); + } + } + } + } + } + + Page> result = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize(), total); + result.setRecords(logList); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的同步店铺商品库存日志列表 + * + * @param bo 查询条件 + * @return 同步店铺商品库存日志列表 + */ + @Override + public List queryList(SynchronizationShopLogBo bo) { + + + Map params = new HashMap<>(); + + if (bo.getGoodsId() != null) { + params.put("goodsId", bo.getGoodsId()); + } + if (bo.getGoodsCreateBy() != null) { + params.put("goodsCreateBy", bo.getGoodsCreateBy()); + } + if (bo.getErpOrderId() != null) { + params.put("erpOrderId", bo.getErpOrderId()); + } + if (bo.getOrderSn() != null && !bo.getOrderSn().isEmpty()) { + params.put("orderSn", bo.getOrderSn()); + } + if (bo.getShopId() != null) { + params.put("shopId", bo.getShopId()); + } + if (bo.getShopName() != null && !bo.getShopName().isEmpty()) { + params.put("shopName", bo.getShopName()); + } + if (bo.getShopCreateBy() != null) { + params.put("shopCreateBy", bo.getShopCreateBy()); + } + if (bo.getPlatformId() != null) { + params.put("platformId", bo.getPlatformId()); + } + if (bo.getCode() != null && !bo.getCode().isEmpty()) { + params.put("code", bo.getCode()); + } + + + String logListStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getOrderServiceUrl(), + "/api/synchronizationShopLog/getListLog", + params + ); + Map dataMap = JsonUtil.transferToObj(logListStr, Map.class); + List logList = (List) dataMap.get("data"); + return logList; + } + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShelvesServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShelvesServiceImpl.java new file mode 100644 index 0000000..f010c87 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShelvesServiceImpl.java @@ -0,0 +1,269 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.apache.poi.ss.formula.functions.T; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.TDepot; +import org.dromara.zhishu.domain.TShelves; +import org.dromara.zhishu.domain.bo.TShelvesBo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TShelvesVo; +import org.dromara.zhishu.mapper.TDepotMapper; +import org.dromara.zhishu.mapper.TShelvesMapper; +import org.dromara.zhishu.service.ITShelvesService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 货架信息Service业务层处理 + * + * @author Lion Li + * @date 2025-03-26 + */ +@RequiredArgsConstructor +@Service +public class TShelvesServiceImpl implements ITShelvesService { + +// @Autowired + private final TShelvesMapper baseMapper; + + private final TDepotMapper tDepotMapper; + + /** + * 查询货架信息 + * + * @param id 主键 + * @return 货架信息 + */ + @Override + public TShelvesVo queryById(Long id) { + TShelvesVo vo=baseMapper.selectVoById(id); + Long userId = LoginHelper.getUserId(); + String depotName=baseMapper.selectDepotName(vo.getDepotId()); + vo.setDepotName(depotName); + return vo; + } + + @Override + public TShelvesVo queryFoundId(Long depotId, String code){ + TShelvesVo vo=baseMapper.selectForLocal(depotId, code); + Long userId = LoginHelper.getUserId(); + String depotName=baseMapper.selectDepotName(vo.getDepotId()); + vo.setDepotName(depotName); + return vo; + } + + /** + * 分页查询货架信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 货架信息分页列表 + */ + @Override + public TableDataInfo queryPageList(TShelvesBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Long userId = LoginHelper.getUserId(); + List depotids=baseMapper.selectV(userId); + Page result = new Page<>(); + + if(!depotids.isEmpty()){ + result =baseMapper.selectVo(pageQuery.build(), bo,depotids); + for (int i = 0; i < result.getRecords().size(); i++) { + String name = result.getRecords().get(i).getName(); + String unit = result.getRecords().get(i).getUnit(); + result.getRecords().get(i).setName(name+unit); + Long id = result.getRecords().get(i).getId(); + TDepotVo depotName = baseMapper.selectByName1(id,userId); + result.getRecords().get(i).setDepotName(depotName.getName()+depotName.getUnit()); + } + } + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的货架信息列表 + * + * @param bo 查询条件 + * @return 货架信息列表 + */ + @Override + public List queryList(TShelvesBo bo) { + Long userId = LoginHelper.getUserId(); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List list=baseMapper.selectVoList(lqw); + //通过list中的id去查询仓库名称,并将仓库名称赋值到depotName字段中 + for (TShelvesVo record : list) { + record.setDepotName(baseMapper.selectByName(record.getId(),userId)); + } + return list; + } + + private LambdaQueryWrapper buildQueryWrapper(TShelvesBo bo) { + Map params = bo.getParams(); + Long userId = LoginHelper.getUserId(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(TShelves::getId); + lqw.like(StringUtils.isNotBlank(bo.getName()), TShelves::getName, bo.getName()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TShelves::getStatus, bo.getStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getCode()), TShelves::getCode, bo.getCode()); + return lqw; + } + + /** + * 新增货架信息 + * + * @param bo 货架信息 + * @return 是否新增成功 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public Boolean insertByBo(TShelvesBo bo) { + TShelves add = MapstructUtils.convert(bo, TShelves.class); + validEntityBeforeSave(add); +// Long userId = LoginHelper.getUserId(); + Long userId = bo.getUserId() != null ? bo.getUserId() : LoginHelper.getUserId(); + String depotName = baseMapper.selectDName(add.getDepotId(),userId); +// 将货架编码转换为大写 + String sheCode=add.getCode().toUpperCase(); + add.setCode(sheCode); + add.setTenantId("000000"); + + if(StringUtils.isEmpty(add.getName())){ + throw new RuntimeException("请稍后重试"); + } + +// 查询当前仓库下的货架 + Integer message1 = baseMapper.selectByCode(null, add.getDepotId(), add.getName()); + if (message1 != 0) { + throw new RuntimeException("货区名称重复"); + } +// 查询当前仓库下的货架编码是否重复 + Integer message2 = baseMapper.selectByCode(add.getCode(),add.getDepotId(),null); + if (message2 != 0) { + throw new RuntimeException("货区编码重复"); + } +// 查询当前仓库下的货架数量是否达到最大值 + Integer countMax= baseMapper.selectNumber(bo.getDepotId()); +// 查询当前仓库下的货架总数量 + Integer count=baseMapper.selectcount(bo.getDepotId()); +// 判断货架编码或货架数量是否超过最大值 + if (countMax <= count) { + throw new RuntimeException("货区数量已达到货区最大的数量"); + } else { + boolean flag = baseMapper.insertBo(add) > 0; + bo.setId(add.getId()); + Integer message3 = baseMapper.updateByShe(bo.getId(), bo.getDepotId()); + if (flag) { + } + return flag; + } + } + + /** + * 修改货架信息 + * + * @param bo 货架信息 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TShelvesBo bo) { + TShelves update = MapstructUtils.convert(bo, TShelves.class); + validEntityBeforeSave(update); + + Integer message = baseMapper.selectByExcludeCurrent(update.getName(), update.getDepotId(), update.getId()); + if (message != 0) { + throw new RuntimeException("仓库名称重复"); + } + + return baseMapper.updateShe(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TShelves entity){ + //TODO 做一些数据校验,如唯一约束 + if (StringUtils.isEmpty(entity.getName())) { + throw new RuntimeException("请稍后重试"); + } + } + + /** + * 校验并批量删除货架信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid,Long LocalUserId) { + // 2. 业务校验逻辑 + Long userId = LocalUserId != null ? LocalUserId : LoginHelper.getUserId(); + List shelvesList = baseMapper.selectListVo(ids,userId); + if(!shelvesList.isEmpty()){ + for (TShelvesVo shelvesVo : shelvesList) { + Integer message=0; + if(shelvesVo.getTwosCode().length()==3){ + //查询货号前三位 + message = baseMapper.selectCounts(userId,shelvesVo.getTwosCode()); + }else if(shelvesVo.getTwosCode().length()==4){ + //查询货号前4位 + message = baseMapper.selectCounts1(userId,shelvesVo.getTwosCode()); + } + if(message>0){ + throw new RuntimeException("货区下有书品,请先删除书品"); + }else{ + baseMapper.deleteByIdShe(ids); // 关联表删除 + baseMapper.deleteByIds(ids); // 主表删除 + return true; + } + } + } + return false; + } + + @Override + public List queryList1() { + //获取当前用户id + Long userId = LoginHelper.getUserId(); + //查询当前用户下的货区 + List vo=baseMapper.selectList1(userId); + //循环遍历货区名称和货区编码 + for (TShelvesVo v:vo){ + v.setName(v.getName()+v.getUnit()); + TDepotVo depotVo = baseMapper.selectDepot(v.getDepotId()); + v.setDepotName(depotVo.getName()+depotVo.getUnit()); + } + return vo; + } + + @Override + public List selectShelvesIdByDepotIdAndCode(String depotId, String code) { + return baseMapper.selectShelvesIdByDepotIdAndCode(depotId,code); + } + + @Override + public List selectShelvesByDepotId(String depotId){ + return baseMapper.selectShelvesByDepotId(depotId); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopOrderServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopOrderServiceImpl.java new file mode 100644 index 0000000..238b58f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopOrderServiceImpl.java @@ -0,0 +1,880 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import com.pdd.pop.sdk.http.PopClient; +import com.pdd.pop.sdk.http.PopHttpClient; +import com.pdd.pop.sdk.http.api.pop.request.PddOrderListGetRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddOrderListGetResponse; +import lombok.extern.log4j.Log4j2; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.domain.dto.request.UpdateIsSynOrderRequest; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryRequest; +import org.dromara.zhishu.domain.dto.request.OrderListByShopIdRequest; +import org.dromara.zhishu.domain.dto.PddOrderQueryDto; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.enums.PddResCodeEnum; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.service.ITShopOrderDetailService; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.service.client.PddClient; +import org.dromara.zhishu.service.factory.ItemListJsonStringParseStrategyFactory; +import org.dromara.zhishu.service.factory.OrderStrategyFactory; +import org.dromara.zhishu.service.strategy.*; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisOperations; +import org.springframework.data.redis.core.RedisTemplate; + +import org.springframework.data.redis.core.SessionCallback; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.TShopOrderBo; +import org.dromara.zhishu.domain.TShopOrder; +import org.dromara.zhishu.mapper.TShopOrderMapper; +import org.dromara.zhishu.service.ITShopOrderService; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Duration; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + + + +/** + * 订单Service业务层处理 + * + * @author Lion Li + * @date 2025-03-13 + */ +@RequiredArgsConstructor +@Service +@Log4j2 +public class TShopOrderServiceImpl implements ITShopOrderService { + + private final TShopOrderMapper baseMapper; + + + private final IZhishuShopGoodsService zhishuShopGoodsService; + private final ShopMapper shopMapper; + + private final ITShopOrderDetailService tShopOrderDetailService; + + private final ScheduledExecutorService scheduledExecutorService; + + private final KfzClient kfzClient; + private final PddClient pddClient; + + @Value("${pdd.app.clientId}") + private String clientId; + + @Value("${pdd.app.clientSecret}") + private String clientSecret; + + + @Autowired + private RedisTemplate redisTemplates; + + private static final String ORDER_COUNT_KEY = "order_count_"; + private static final String ORDER_AMOUNT_KEY = "order_amount_"; + + + /** + * 查询订单 + * + * @param id 主键 + * @return 订单 + */ + @Override + public TShopOrderVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询订单列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 订单分页列表 + */ + @Override + public TableDataInfo queryPageList(TShopOrderBo bo, PageQuery pageQuery) { + // 若没传userId筛选条件,默认取当前登录用户userId + if (ObjectUtil.isNull(bo.getUserId())) { + LoginUser user = LoginHelper.getLoginUser(); + if (user != null) { + bo.setUserId(user.getUserId()); + } + } + if (ObjectUtil.isEmpty(bo.getShopIdList())) { + // 根据userId获取当前用户下所有店铺Id + List shopIdList = new LambdaQueryChainWrapper<>(shopMapper) + .eq(Shop::getCreateBy, bo.getUserId()) + .eq(Shop::getDelFlag, "0") + .list().stream().map(Shop::getId).distinct().toList(); + bo.setShopIdList(shopIdList); + if (ObjectUtil.isEmpty(shopIdList)) return TableDataInfo.build(new Page<>()); + } + Page result = baseMapper.queryOrderList(pageQuery.build(), bo); + if (ObjectUtil.isNotEmpty(result.getRecords())) { + for (TShopOrderVo record : result.getRecords()) { + record.setOrderExceptionTypeList(Arrays.asList(record.getOrderExceptionType().split(","))); + List orderItemList = buildOrderItemVo(record.getItemList(), record.getOrderSourceType()); + //查看商品是否是发布商品 如果不是标红不能发布 + if(!orderItemList.isEmpty()){ + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.selectShopGoodsByArtNo(orderItemList.get(0).getArtNo()); + if (zhishuShopGoodsVo != null) { + record.setLabel(true); + }else { + record.setLabel(false); + } + } + record.setOrderItemList(orderItemList); + } + } + return TableDataInfo.build(result); + } + + private List buildOrderItemVo(String itemListStr, Integer orderSourceType) { + List orderItemList = new ArrayList<>(); + ItemListJsonStringParseStrategy strategy = ItemListJsonStringParseStrategyFactory.getStrategy(orderSourceType); + if (strategy instanceof ItemListJsonStringParsePddStrategy) { + ItemListVo pddVo = ((ItemListJsonStringParsePddStrategy) strategy).itemListJsonStringParse(itemListStr); + if (ObjectUtil.isNotEmpty(pddVo.getOrderItems())) { + for (GoodsItemPddVo orderItem : pddVo.getOrderItems()) { + OrderItemVo orderItemVo = new OrderItemVo(); + orderItemVo.setGoodsName(orderItem.getGoodsName()); + orderItemVo.setGoodsImg(orderItem.getGoodsImg()); + orderItemVo.setGoodsPrice(orderItem.getGoodsPrice().toString()); + orderItemVo.setGoodsCount(orderItem.getGoodsCount().toString()); + orderItemVo.setArtNo(orderItem.getOuterId()); + orderItemList.add(orderItemVo); + } + } + } + if (strategy instanceof ItemListJsonStringParseKWStrategy) { + ItemListVo kfzVo = ((ItemListJsonStringParseKWStrategy) strategy).itemListJsonStringParse(itemListStr); + if (ObjectUtil.isNotEmpty(kfzVo.getOrderItems())) { + for (GoodsItemKfzVo orderItem : kfzVo.getOrderItems()) { + OrderItemVo orderItemVo = new OrderItemVo(); + orderItemVo.setGoodsName(orderItem.getItemName()); + orderItemVo.setGoodsImg(orderItem.getImg()); + orderItemVo.setGoodsPrice(orderItem.getPrice()); + orderItemVo.setGoodsCount(orderItem.getNumber().toString()); + orderItemVo.setArtNo(orderItem.getItemSn()); + orderItemList.add(orderItemVo); + } + } + } + return orderItemList; + } + + /** + * 查询符合条件的订单列表 + * + * @param bo 查询条件 + * @return 订单列表 + */ + @Override + public List queryList(TShopOrderBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TShopOrderBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(TShopOrder::getId); + lqw.in(ObjectUtil.isNotEmpty(bo.getShopIdList()), TShopOrder::getShopId, bo.getShopIdList()); + lqw.like(StringUtils.isNotBlank(bo.getShopName()), TShopOrder::getShopName, bo.getShopName()); + return lqw; + } + + /** + * 新增订单 + * + * @param bo 订单 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(TShopOrderBo bo) { + TShopOrder add = MapstructUtils.convert(bo, TShopOrder.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改订单 + * + * @param bo 订单 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TShopOrderBo bo) { + TShopOrder update = MapstructUtils.convert(bo, TShopOrder.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + @Override + public Boolean updateBy(TShopOrder bo) { + return baseMapper.updateById(bo) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TShopOrder entity) { + // TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除订单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + + @Override + public R getInterShopOrder(PddOrderQueryDto queryDto) { + + String accessToken = "2f5ddb784f9a4913af7a5f93b2970b1c12ccad4e"; + + PopClient client = new PopHttpClient(clientId, clientSecret); + SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss"); + Date startTime; + Date endTime; + try { + startTime = sdf.parse(queryDto.getStartTime()); + endTime = sdf.parse(queryDto.getEndTime()); + } catch (ParseException e) { + throw new RuntimeException(e); + } + + long start_confirm_at = startTime.getTime(); + long end_confirm_at = endTime.getTime(); + PddOrderListGetRequest request = new PddOrderListGetRequest(); + request.setEndConfirmAt(end_confirm_at); + request.setOrderStatus(queryDto.getOrder_status()); + request.setPage(1); + request.setPageSize(100); + request.setRefundStatus(queryDto.getRefund_status()); + request.setStartConfirmAt(start_confirm_at); + request.setTradeType(queryDto.getTrade_type()); + request.setUseHasNext(true); + PddOrderListGetResponse response = null; + try { + response = client.syncInvoke(request, accessToken); + } catch (Exception e) { + throw new RuntimeException(e); + } + String res = JsonUtil.transferToJson(response); + + + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); + + // 字符串转换成对象 + JsonObject obj = gson.fromJson(res, JsonObject.class); + ; + + if (ObjectUtils.isNotEmpty(obj.get(PddResCodeEnum.ERR.getCode()))) { + // 报错信息 + JsonObject error_response = obj.get(PddResCodeEnum.ERR.getCode()).getAsJsonObject(); + log.error("调取拼多多接口失败{}", error_response); + } + + + return R.ok(); + } + + @Override + public void insertPddIncrementOrder(JsonArray jsonArray) { +// Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); +// +// for (Object o : jsonArray) { +// +// JsonObject orderObject = gson.fromJson(o.toString(), JsonObject.class); +// +// +// String orderSn = JsonObjUtil.getString(orderObject, PddOrderEnum.ORDER_SN.getCode()); +// +// +// QueryWrapper queryWrapper = new QueryWrapper(); +// +// queryWrapper.lambda().eq(TShopOrder::getOrderSn,orderSn); +// +// +// TShopOrder tShopOrder = baseMapper.selectOne(queryWrapper); +// +// if(ObjectUtils.isEmpty(tShopOrder)){ +// tShopOrder = new TShopOrder(); +// } +// +// String address = JsonObjUtil.getString(orderObject, PddOrderEnum.ADDRESS.getCode()); +// tShopOrder.setAddress(address); +// +// String addressMask = JsonObjUtil.getString(orderObject, PddOrderEnum.ADDRESS_MASK.getCode()); +// tShopOrder.setAddressMask(addressMask); +// +// Long afterSalesStatus = JsonObjUtil.getLong(orderObject, PddOrderEnum.AFTER_SALES_STATUS.getCode()); +// tShopOrder.setAfterSalesStatus(afterSalesStatus); +// +// String buyerMemo = JsonObjUtil.getString(orderObject, PddOrderEnum.BUYER_MEMO.getCode()); +// tShopOrder.setBuyerMemo(buyerMemo); +// +// String confirmTime = JsonObjUtil.getString(orderObject, PddOrderEnum.CONFIRM_TIME.getCode()); +// tShopOrder.setConfirmTime(confirmTime); +// +// Long confirmStatus = JsonObjUtil.getLong(orderObject, PddOrderEnum.CONFIRM_STATUS.getCode()); +// tShopOrder.setConfirmStatus(confirmStatus); +// +// String createdTime = JsonObjUtil.getString(orderObject, PddOrderEnum.CREATED_TIME.getCode()); +// tShopOrder.setCreatedTime(createdTime); +// +// String deliveryOneDay = JsonObjUtil.getString(orderObject, PddOrderEnum.DELIVERY_ONE_DAY.getCode()); +// tShopOrder.setDeliveryOneDay(deliveryOneDay); +// +// BigDecimal discountAmount = JsonObjUtil.getDecimal(orderObject, PddOrderEnum.DISCOUNT_AMOUNT.getCode()); +// tShopOrder.setDiscountAmount(discountAmount); +// +// BigDecimal duoDuoPayReduction = JsonObjUtil.getDecimal(orderObject, PddOrderEnum.DISCOUNT_AMOUNT.getCode()); +// tShopOrder.setDuoDuoPayReduction(duoDuoPayReduction); +// +// Long duoduoWholesale = JsonObjUtil.getLong(orderObject, PddOrderEnum.DUODUO_WHOLESALE.getCode()); +// tShopOrder.setDuoduoWholesale(duoduoWholesale); +// +// BigDecimal goodsAmount = JsonObjUtil.getDecimal(orderObject, PddOrderEnum.GOODS_AMOUNT.getCode()); +// tShopOrder.setGoodsAmount(goodsAmount); +// +// String orderDepotInfo = JsonObjUtil.getString(orderObject, PddOrderEnum.ORDER_DEPOT_INFO.getCode()); +// tShopOrder.setOrderDepotInfo(orderDepotInfo); +//// +//// String depotId = JsonObjUtil.getString(orderObject,PddOrderEnum.DEPOT_ID.getCode()); +//// tShopOrder.setDepotId(depotId ); +//// +//// String depotName =JsonObjUtil.getString(orderObject,PddOrderEnum.DEPOT_NAME.getCode()); +//// tShopOrder.setDepotName( depotName ); +//// +//// Long depotType = JsonObjUtil.getLong(orderObject,PddOrderEnum.DEPOT_TYPE.getCode()); +//// tShopOrder.setDepotType(depotType); +//// +//// Long wareId = JsonObjUtil.getLong(orderObject,PddOrderEnum.WARE_ID.getCode()); +//// tShopOrder.setWareId(wareId); +//// +//// String wareName = JsonObjUtil.getString(orderObject,PddOrderEnum.WARE_NAME.getCode()); +//// tShopOrder.setWareName(wareName); +//// +//// String wareSn = JsonObjUtil.getString(orderObject,PddOrderEnum.WARE_SN.getCode()); +//// tShopOrder.setWareName(wareSn); +//// +//// Long wareType = JsonObjUtil.getLong(orderObject,PddOrderEnum.WARE_TYPE.getCode()); +//// tShopOrder.setWareType(wareType); +// +// +// BigDecimal payAmount = JsonObjUtil.getDecimal(orderObject, PddOrderEnum.PAY_AMOUNT.getCode()); +// tShopOrder.setPayAmount(payAmount); +// +//// String orderSn = JsonObjUtil.getString(orderObject, PddOrderEnum.ORDER_SN.getCode()); +//// tShopOrder.setOrderSn(orderSn); +// +// Long orderStatus = JsonObjUtil.getLong(orderObject, PddOrderEnum.ORDER_STATUS.getCode()); +// tShopOrder.setOrderStatus(orderStatus); +// +// String payNo = JsonObjUtil.getString(orderObject, PddOrderEnum.PAY_NO.getCode()); +// tShopOrder.setPayNo(payNo); +// +// String payTime = JsonObjUtil.getString(orderObject, PddOrderEnum.PAY_TIME.getCode()); +// tShopOrder.setPayTime(payTime); +// +// String payType = JsonObjUtil.getString(orderObject, PddOrderEnum.PAY_TYPE.getCode()); +// tShopOrder.setPayType(payType); +// +// BigDecimal platformDiscount = JsonObjUtil.getDecimal(orderObject, PddOrderEnum.PLATFORM_DISCOUNT.getCode()); +// tShopOrder.setPlatformDiscount(platformDiscount); +// +// BigDecimal postage = JsonObjUtil.getDecimal(orderObject, PddOrderEnum.POSTAGE.getCode()); +// tShopOrder.setPostage(postage); +// +// String preSaleTime = JsonObjUtil.getString(orderObject, PddOrderEnum.PRE_SALE_TIME.getCode()); +// tShopOrder.setPreSaleTime(preSaleTime); +// +// String promiseDeliveryTime = JsonObjUtil.getString(orderObject, PddOrderEnum.PROMISE_DELIVERY_TIME.getCode()); +// tShopOrder.setPromiseDeliveryTime(promiseDeliveryTime); +// +// String province = JsonObjUtil.getString(orderObject, PddOrderEnum.PROVINCE.getCode()); +// tShopOrder.setProvince(province); +// +// String provinceId = JsonObjUtil.getString(orderObject, PddOrderEnum.PROVINCE_ID.getCode()); +// tShopOrder.setProvinceId(provinceId); +// +// String receiveTime = JsonObjUtil.getString(orderObject, PddOrderEnum.RECEIVE_TIME.getCode()); +// tShopOrder.setReceiveTime(receiveTime); +// +// String receiverAddress = JsonObjUtil.getString(orderObject, PddOrderEnum.RECEIVER_ADDRESS.getCode()); +// tShopOrder.setReceiverAddress(receiverAddress); +// +// String receiverAddressMask = JsonObjUtil.getString(orderObject, PddOrderEnum.RECEIVER_ADDRESS_MASK.getCode()); +// tShopOrder.setReceiverAddressMask(receiverAddressMask); +// +// String receiverName = JsonObjUtil.getString(orderObject, PddOrderEnum.RECEIVER_NAME.getCode()); +// tShopOrder.setReceiverName(receiverName); +// +// String receiverNameMask = JsonObjUtil.getString(orderObject, PddOrderEnum.RECEIVER_NAME_MASK.getCode()); +// tShopOrder.setReceiverName(receiverNameMask); +// +// String receiverPhone = JsonObjUtil.getString(orderObject, PddOrderEnum.RECEIVER_PHONE.getCode()); +// tShopOrder.setReceiverPhone(receiverPhone); +// +// String receiverPhoneMask = JsonObjUtil.getString(orderObject, PddOrderEnum.RECEIVER_PHONE_MASK.getCode()); +// tShopOrder.setReceiverPhoneMask(receiverPhoneMask); +// +// Long refundStatus = JsonObjUtil.getLong(orderObject, PddOrderEnum.REFUND_STATUS.getCode()); +// tShopOrder.setRefundStatus(refundStatus); +// +// String remark = JsonObjUtil.getString(orderObject, PddOrderEnum.REMARK.getCode()); +// tShopOrder.setRemark(remark); +// +// String remarkTag = JsonObjUtil.getString(orderObject, PddOrderEnum.REMARK_TAG.getCode()); +// tShopOrder.setRemarkTag(remarkTag); +// +// String remarkTagName = JsonObjUtil.getString(orderObject, PddOrderEnum.REMARK_TAG_NAME.getCode()); +// tShopOrder.setRemarkTagName(remarkTagName); +// +// Long returnFreightPayer = JsonObjUtil.getLong(orderObject, PddOrderEnum.RETURN_FREIGHT_PAYER.getCode()); +// tShopOrder.setReturnFreightPayer(returnFreightPayer); +// +// Long riskControlStatus = JsonObjUtil.getLong(orderObject, PddOrderEnum.RISK_CONTROL_STATUS.getCode()); +// tShopOrder.setRiskControlStatus(riskControlStatus); +// +// BigDecimal sellerDiscount = JsonObjUtil.getDecimal(orderObject, PddOrderEnum.SELLER_DISCOUNT.getCode()); +// tShopOrder.setSellerDiscount(sellerDiscount); +// +// Long stockOutHandleStatus = JsonObjUtil.getLong(orderObject, PddOrderEnum.STOCK_OUT_HANDLE_STATUS.getCode()); +// tShopOrder.setStockOutHandleStatus(stockOutHandleStatus); +// +// Long supportNationwideWarranty = JsonObjUtil.getLong(orderObject, PddOrderEnum.SUPPORT_NATIONWIDE_WARRANTY.getCode()); +// tShopOrder.setSupportNationwideWarranty(supportNationwideWarranty); +// +// String town = JsonObjUtil.getString(orderObject, PddOrderEnum.TOWN.getCode()); +// tShopOrder.setTown(town); +// +// String townId = JsonObjUtil.getString(orderObject, PddOrderEnum.TOWN_ID.getCode()); +// tShopOrder.setTownId(townId); +// +// String trackingNumber = JsonObjUtil.getString(orderObject, PddOrderEnum.TRACKING_NUMBER.getCode()); +// tShopOrder.setTrackingNumber(trackingNumber); +// +// +// Long tradeType = JsonObjUtil.getLong(orderObject, PddOrderEnum.TRADE_TYPE.getCode()); +// tShopOrder.setTradeType(tradeType); +// +// String updatedAt = JsonObjUtil.getString(orderObject, PddOrderEnum.UPDATED_AT.getCode()); +// tShopOrder.setUpdatedAt(updatedAt); +// +// +// String urgeShippingTime = JsonObjUtil.getString(orderObject, PddOrderEnum.URGE_SHIPPING_TIME.getCode()); +// tShopOrder.setUrgeShippingTime(urgeShippingTime); +// +// String yypsDate = JsonObjUtil.getString(orderObject, PddOrderEnum.YYPS_DATE.getCode()); +// tShopOrder.setYypsDate(yypsDate); +// +// +// String yypsTime = JsonObjUtil.getString(orderObject, PddOrderEnum.YYPS_TIME.getCode()); +// tShopOrder.setYypsTime(yypsTime); +// +// +// String itemList = JsonObjUtil.getString(orderObject, PddOrderEnum.ITEM_LIST.getCode()); +// tShopOrder.setItemList(itemList); +// +// +//// // todo 循环插入商品列表 +//// String itemList = orderObject.get(PddOrderEnum.ITEM_LIST.getCode()).getAsString(); +//// String orderSn = orderObject.get(PddOrderEnum.ORDER_SN.getCode()).getAsString(); +// +// +// if(ObjectUtils.isNotEmpty(tShopOrder.getId())){ +// baseMapper.updateById(tShopOrder); +// }else{ +// baseMapper.insert(tShopOrder); +// } +// tShopOrderDetailService.insertBatchOrderDetail(itemList, orderSn, tShopOrder.getId()); +// +// } + } + + @Override + public TableDataInfo customPageList(TShopOrderBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + if (ObjectUtils.isNotEmpty(bo.getShopName())) { + lqw.eq(TShopOrder::getShopName, bo.getShopName()); + } + Page result = baseMapper.customPageList(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @Override + public List listByShopId(OrderListByShopIdRequest request) { + List list = new LambdaQueryChainWrapper<>(baseMapper) + .eq(TShopOrder::getShopId, request.getShopId().toString()) + .eq(TShopOrder::getDelFlag, "0") + .eq(TShopOrder::getStatus, "0") + .in(ObjectUtil.isNotEmpty(request.getOrderSnList()), TShopOrder::getOrderSn, request.getOrderSnList()) + .list().stream().map(order -> { + TShopOrderVo tShopOrderVo = new TShopOrderVo(); + BeanUtils.copyProperties(order, tShopOrderVo); + return tShopOrderVo; + }).toList(); + return list; + } + + @Override + @Async + public void insertOrUpdateOrderBatch(List orderList) { + System.out.println("订单传入参数:"+JsonUtil.transferToJson(orderList)); + List tShopOrderList = orderList.stream().map(order -> { + TShopOrder tShopOrder = new TShopOrder(); + BeanUtils.copyProperties(order, tShopOrder); + return tShopOrder; + }).toList(); + System.out.println("tShopOrderList:"+ JSONObject.toJSONString(tShopOrderList)); + //存储到redis中 + try { + //确保新增的时候删除标记为0 + for (TShopOrder tShopOrder : tShopOrderList){ + if(StringUtils.isEmpty(tShopOrder.getDelFlag())){ + tShopOrder.setDelFlag("0"); + } + if (StringUtils.isEmpty(tShopOrder.getStatus())){ + tShopOrder.setStatus("0"); + } + } + processOrderStatistics(orderList); + } catch (Exception e) { + log.error("订单统计异常", e); + } + baseMapper.insertOrUpdateBatch(tShopOrderList); + } + + @Override + public TShopOrderVo listByOrderSn(String orderSn) { + List tShopOrderVoList = new LambdaQueryChainWrapper<>(baseMapper) + .eq(TShopOrder::getOrderSn, orderSn) + .eq(TShopOrder::getDelFlag, "0") + .eq(TShopOrder::getStatus, "0") + .list().stream().map(order -> { + TShopOrderVo tShopOrderVo = new TShopOrderVo(); + BeanUtils.copyProperties(order, tShopOrderVo); + return tShopOrderVo; + }).toList(); + if (ObjectUtil.isEmpty(tShopOrderVoList)) return null; + return tShopOrderVoList.get(0); + } + + @Async + @Override + public void syncKfzOrderTask() { + List kfzListIds = new LambdaQueryChainWrapper<>(shopMapper) + .eq(Shop::getShopType, "2") + .eq(Shop::getShopAuthorize, "1") + .eq(Shop::getIsSynOrder, 1) + .eq(Shop::getStatus, "0") + .eq(Shop::getDelFlag, "0") + .list().stream().map(Shop::getId).toList(); + kfzClient.fullSynchronizationOrder(UrlUtil.getKfzServiceUrl(), 30, "auto", kfzListIds); + } + + @Override + public List deliveryMethodList(Long shopId, Integer orderSourceType) { + OrderStrategy strategy = OrderStrategyFactory.getStrategy(orderSourceType); + if (strategy == null) throw new ServiceException("未知订单类型获取不到对应策略"); + try { + return strategy.deliveryMethodList(shopId); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + + @Override + public Boolean orderDelivery(OrderDeliveryRequest request) { + try { + OrderStrategy strategy = OrderStrategyFactory.getStrategy(request.getOrderSourceType()); + if (strategy == null) throw new ServiceException("未知订单类型获取不到对应策略"); + return strategy.orderDelivery(request); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + + @Async + @Override + public void syncKfzHistoryOrder(Integer days, List shopIdList) { + for (Long shopId : shopIdList) { + // 查询当前店铺信息 + Shop shop = new LambdaQueryChainWrapper<>(shopMapper) + .eq(Shop::getDelFlag, 0) + .eq(Shop::getStatus, 0) + .eq(Shop::getId, shopId) + .oneOpt().orElseThrow(() -> new ServiceException("未查询到店铺信息shopId:" + shopId)); + // 校验店铺授权信息,若有店铺未授权,打印日志,并跳过当前店铺 + if (!shop.getShopAuthorize().equals("1") || ObjectUtil.isNull(shop.getMallId())) { + log.error("店铺授权异常,不能同步授权异常店铺-shopId:{}", shopId); + continue; + } + + // 暂时设置店铺是否开启同步订单为否,防止定时同步订单写入订单数据 + // 重置店铺上次同步订单时间 + /*boolean updateShop = new LambdaUpdateChainWrapper<>(shopMapper) + .eq(Shop::getId, shopId) + .set(Shop::getStartUpdatedAt, null) + .set(Shop::getIsSynOrder, 0) + .update(); + if (!updateShop) { + log.error("店铺同步订单状态修改失败,请检查店铺信息-shopId:{}", shopId); + continue; + }*/ + // 删除店铺历史订单 + new LambdaUpdateChainWrapper<>(baseMapper) + .eq(TShopOrder::getDelFlag, 0) + .eq(TShopOrder::getShopId, shopId) + .set(TShopOrder::getDelFlag, 1) + .update(); + // 根据店铺类型同步订单 + Objects.requireNonNull(OrderStrategyFactory.getStrategy(Integer.valueOf(shop.getShopType()))) + .syncKfzHistoryOrder(shopId, days); + } + } + + @Async + @Override + public void syncKfzHistoryOrderCallBack(Long shopId) { + Shop shop = new LambdaQueryChainWrapper<>(shopMapper) + .eq(Shop::getId, shopId) + .oneOpt().orElseThrow(() -> new ServiceException("未查询到店铺信息shopId:" + shopId)); + // 发送消息给前端告知拉取下来的数据已比对完毕 + scheduledExecutorService.schedule(() -> + + { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage("店铺:" + shop.getShopName() + ",订单已重新同步完成"); + dto.setUserIds(List.of(shop.getCreateBy())); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); + } + + /** + * 修改店铺是否开启同步订单 + * @param request + */ + @Override + public void updateIsSynOrder(UpdateIsSynOrderRequest request) { + new LambdaUpdateChainWrapper<>(shopMapper) + .eq(Shop::getId, Long.valueOf(request.getShopId())) + .set(Shop::getIsSynOrder, request.getIsSynOrder()) + .update(); + } + + @Override + public TShopOrderBo findSHopOrderByid(String id) { + TShopOrder shopOrder = baseMapper.selectById(id); + if (shopOrder == null) { + // 提示用户暂无数据 + throw new ServiceException("暂无数据"); + } + TShopOrderBo tShopOrder = new TShopOrderBo(); + BeanUtils.copyProperties(shopOrder, tShopOrder); + + return tShopOrder; + + } + + + + + private void processOrderStatistics(List orderList) { + for (TShopOrderVo order : orderList) { + System.out.println("订单插入前数据:"+JsonUtil.transferToJson(order)); + if (order.getPayAmount()== null) { + order.setPayAmount(BigDecimal.ZERO); + } + // 新订单(没有ID) + if (order.getId() == null) { + // 新订单直接增加 + incrementOrderStats(order.getPayAmount(), Long.parseLong(order.getShopId())); + } + // 更新订单且是退款状态 + if (order.getAfterSalesStatus()==10) { + // 退款情况,减少销售额 + decrementOrderStats(order.getPayAmount(), Long.parseLong(order.getShopId())); + } + if (order.getOrderSourceType()==5 && order.getConfirmStatus()==2) { + decrementOrderStats(order.getPayAmount(), Long.parseLong(order.getShopId())); + } + } + } + + /** + * 增加订单量和销售额(原子操作) + */ + public void incrementOrderStats(BigDecimal amount, Long shopId) { + String today = getTodayDate(); + String countKey = ORDER_COUNT_KEY + today + "_" + shopId; + String amountKey = ORDER_AMOUNT_KEY + today + "_" + shopId; + + // 临时设置序列化器 + redisTemplates.setKeySerializer(new StringRedisSerializer()); + redisTemplates.setValueSerializer(new StringRedisSerializer()); + + // 在事务外读取当前金额 + Object currentAmountObj = redisTemplates.opsForValue().get(amountKey); + BigDecimal currentAmount = currentAmountObj != null ? + new BigDecimal(currentAmountObj.toString()) : BigDecimal.ZERO; + + redisTemplates.execute(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + operations.watch(Arrays.asList(amountKey, countKey)); + + // 验证数据在读取后没有被修改 + Object currentCheck = operations.opsForValue().get(amountKey); + BigDecimal currentCheckAmount = currentCheck != null ? + new BigDecimal(currentCheck.toString()) : BigDecimal.ZERO; + + if (!currentAmount.equals(currentCheckAmount)) { + // 数据已被其他客户端修改,放弃事务 + operations.unwatch(); + return Collections.emptyList(); + } + + operations.multi(); + + // 计算新金额 + BigDecimal newAmount = currentAmount.add(amount).setScale(2, RoundingMode.HALF_UP); + + // 设置金额 + operations.opsForValue().set(amountKey, newAmount.toString(), Duration.ofDays(1)); + + // 处理订单数量 + operations.opsForValue().increment(countKey, 1); + operations.expire(countKey, Duration.ofDays(1)); + + return operations.exec(); + } + }); + } + /** + * 获取今日日期字符串 + */ + private String getTodayDate() { + return LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + } + + /** + * 减少订单统计(退款情况) + */ + public void decrementOrderStats(BigDecimal amount, Long shopId) { + String today = getTodayDate(); + String countKey = ORDER_COUNT_KEY + today + "_" + shopId; + String amountKey = ORDER_AMOUNT_KEY + today + "_" + shopId; + + // 临时设置序列化器 + redisTemplates.setKeySerializer(new StringRedisSerializer()); + redisTemplates.setValueSerializer(new StringRedisSerializer()); + + // 在事务外读取当前值 + Object currentAmountObj = redisTemplates.opsForValue().get(amountKey); + Object currentCountObj = redisTemplates.opsForValue().get(countKey); + + BigDecimal currentAmount = currentAmountObj != null ? + new BigDecimal(currentAmountObj.toString()) : BigDecimal.ZERO; + Long currentCount = currentCountObj != null ? + Long.parseLong(currentCountObj.toString()) : 0L; + + redisTemplates.execute(new SessionCallback() { + @Override + public Object execute(RedisOperations operations) throws DataAccessException { + operations.watch(Arrays.asList(amountKey, countKey)); + + // 验证数据在读取后没有被修改 + Object currentAmountCheck = operations.opsForValue().get(amountKey); + Object currentCountCheck = operations.opsForValue().get(countKey); + + BigDecimal currentAmountCheckVal = currentAmountCheck != null ? + new BigDecimal(currentAmountCheck.toString()) : BigDecimal.ZERO; + Long currentCountCheckVal = currentCountCheck != null ? + Long.parseLong(currentCountCheck.toString()) : 0L; + + if (!currentAmount.equals(currentAmountCheckVal) || !currentCount.equals(currentCountCheckVal)) { + // 数据已被其他客户端修改,放弃事务 + operations.unwatch(); + return Collections.emptyList(); + } + + operations.multi(); + + // 计算新金额(确保不会出现负数) + BigDecimal newAmount = currentAmount.subtract(amount).max(BigDecimal.ZERO) + .setScale(2, RoundingMode.HALF_UP); + + // 计算新订单数量(确保不会出现负数) + Long newCount = Math.max(currentCount - 1, 0); + + // 设置金额和数量 + operations.opsForValue().set(amountKey, newAmount.toString(), Duration.ofDays(1)); + operations.opsForValue().set(countKey, newCount.toString(), Duration.ofDays(1)); + + return operations.exec(); + } + }); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TaskPauseServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TaskPauseServiceImpl.java new file mode 100644 index 0000000..57f16be --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TaskPauseServiceImpl.java @@ -0,0 +1,28 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.domain.TaskPause; +import org.dromara.zhishu.mapper.TaskPauseMapper; +import org.dromara.zhishu.service.ITaskPauseService; +import org.springframework.stereotype.Service; + + +@RequiredArgsConstructor +@Service +public class TaskPauseServiceImpl implements ITaskPauseService { + + private final TaskPauseMapper baseMapper; + + @DS("slave") + @Override + public Boolean insert(TaskPause taskPause) { + return baseMapper.insert(taskPause) > 0; + } + + @DS("slave") + @Override + public Boolean deleteByTaskId(Long taskId){ + return baseMapper.deleteByTaskId(taskId) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ViolationServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ViolationServiceImpl.java new file mode 100644 index 0000000..98c0301 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ViolationServiceImpl.java @@ -0,0 +1,142 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.ViolationBo; +import org.dromara.zhishu.domain.vo.ViolationVo; +import org.dromara.zhishu.domain.Violation; +import org.dromara.zhishu.mapper.ViolationMapper; +import org.dromara.zhishu.service.IViolationService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 违规Service业务层处理 + * + * @author yxy + * @date 2025-06-23 + */ +@RequiredArgsConstructor +@Service +public class ViolationServiceImpl implements IViolationService { + + private final ViolationMapper baseMapper; + + /** + * 查询违规 + * + * @param id 主键 + * @return 违规 + */ + @Override + public ViolationVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询违规列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 违规分页列表 + */ + @Override + public TableDataInfo queryPageList(ViolationBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的违规列表 + * + * @param bo 查询条件 + * @return 违规列表 + */ + @Override + public List queryList(ViolationBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(ViolationBo bo) { + + Long userId = LoginHelper.getUserId(); + if(userId != null && userId != 1 ){ + bo.setUserid(userId); + } + + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(Violation::getId); + lqw.eq(StringUtils.isNotBlank(bo.getType()), Violation::getType, bo.getType()); + lqw.eq(StringUtils.isNotBlank(bo.getContent()), Violation::getContent, bo.getContent()); + lqw.eq(bo.getUserid() != null, Violation::getUserid, bo.getUserid()); + lqw.eq(StringUtils.isNotBlank(bo.getReview()), Violation::getReview, bo.getReview()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Violation::getStatus, bo.getStatus()); + lqw.like(StringUtils.isNotBlank(bo.getName()), Violation::getName, bo.getName()); + return lqw; + } + + /** + * 新增违规 + * + * @param bo 违规 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ViolationBo bo) { + Violation add = MapstructUtils.convert(bo, Violation.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改违规 + * + * @param bo 违规 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ViolationBo bo) { + Violation update = MapstructUtils.convert(bo, Violation.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(Violation entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除违规信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WaveServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WaveServiceImpl.java new file mode 100644 index 0000000..710990f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WaveServiceImpl.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.zhishu.domain.vo.WaveVo; +import org.dromara.zhishu.mapper.WaveMapper; +import org.dromara.zhishu.service.IWaveService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@RequiredArgsConstructor +@Service +@Slf4j +public class WaveServiceImpl implements IWaveService { + + private final WaveMapper waveMapper; + + @Override + public String getStaffName(String staffId) { + return waveMapper.getStaffName(staffId); + } + + @Override + public List getStaffId() { + return waveMapper.getStaffId(); + } + + @Override + public List getStaffList(String userId){return waveMapper.getStaffList(userId);} +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WhiteListServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WhiteListServiceImpl.java new file mode 100644 index 0000000..5703df0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WhiteListServiceImpl.java @@ -0,0 +1,146 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.WhiteListBo; +import org.dromara.zhishu.domain.vo.WhiteListVo; +import org.dromara.zhishu.domain.WhiteList; +import org.dromara.zhishu.mapper.WhiteListMapper; +import org.dromara.zhishu.service.IWhiteListService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 白名单Service业务层处理 + * + * @author yxy + * @date 2025-06-25 + */ +@RequiredArgsConstructor +@Service +public class WhiteListServiceImpl implements IWhiteListService { + + private final WhiteListMapper baseMapper; + + /** + * 查询白名单 + * + * @param id 主键 + * @return 白名单 + */ + @Override + public WhiteListVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询白名单列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 白名单分页列表 + */ + @Override + public TableDataInfo queryPageList(WhiteListBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @Override + public List selectAll(){ + return baseMapper.selectAll(); + } + + @Override + public List selectByIp(String ip){ + return baseMapper.selectByIp(ip); + } + + /** + * 查询符合条件的白名单列表 + * + * @param bo 查询条件 + * @return 白名单列表 + */ + @Override + public List queryList(WhiteListBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(WhiteListBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(WhiteList::getId); + lqw.eq(StringUtils.isNotBlank(bo.getIp()), WhiteList::getIp, bo.getIp()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), WhiteList::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增白名单 + * + * @param bo 白名单 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(WhiteListBo bo) { + WhiteList add = MapstructUtils.convert(bo, WhiteList.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改白名单 + * + * @param bo 白名单 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(WhiteListBo bo) { + WhiteList update = MapstructUtils.convert(bo, WhiteList.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(WhiteList entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除白名单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + @Override + public void deleteAll(){ + baseMapper.deleteAll(); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedPddStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedPddStrategy.java new file mode 100644 index 0000000..b496b38 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedPddStrategy.java @@ -0,0 +1,56 @@ +package org.dromara.zhishu.service.strategy; + +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import org.dromara.common.core.exception.base.BaseException; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.mapper.RunningTaskByShopMapper; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.dromara.zhishu.service.IRunningTaskByShopService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class InventorySynchronizedPddStrategy implements InventorySynchronizedStrategy { + + @Autowired + private ISysConfigService configService; + + @Autowired + private ZhishuShopGoodsMapper zhishuShopGoodsMapper; + + @Autowired + private IRunningTaskByShopService iRunningTaskByShopService; + + @Override + public void inventorySynchronized(ShopVo shop, ShopGoodsPublishedVo goodsPublishedVo, Integer type) { + String shopGoodsId = goodsPublishedVo.getShopGoodsId(); + ZhishuShopGoods zhishuShopGoods = new LambdaQueryChainWrapper<>(zhishuShopGoodsMapper) + .eq(ZhishuShopGoods::getId, shopGoodsId) + .oneOpt().orElseThrow(() -> new BaseException("数据异常")); + // 再去从库查询skuId 根据店铺Id和商品id + List successDataItemDtos = iRunningTaskByShopService.selectByGoodsId("t_running_task_" + shop.getId(), goodsPublishedVo.getPlatformId()); + Map allData = new HashMap(); + allData.put("shopId", shop.getId()); + allData.put("mallId", successDataItemDtos.get(0).getSkuId()); + allData.put("token", shop.getToken()); + allData.put("goodsId", goodsPublishedVo.getPlatformId()); + allData.put("quantity", zhishuShopGoods.getInventory()); + + String pddIp = configService.selectConfigByKey("pdd.ip"); + InterfaceUtils.getInterfacePost(pddIp, "/api/pdd/inventory/inventorySync", allData); + } + + @Override + public void operatingGoodsSoldOut(ShopVo shop, ShopGoodsPublishedVo goodsPublishedVo, Integer platformType, Integer logType, Integer operationType, String orderSn) { + + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedStrategy.java new file mode 100644 index 0000000..7d754aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedStrategy.java @@ -0,0 +1,12 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.domain.vo.ShopVo; + +public interface InventorySynchronizedStrategy { + + void inventorySynchronized(ShopVo shop, ShopGoodsPublishedVo goodsPublishedVo, Integer type); + + void operatingGoodsSoldOut(ShopVo shop, ShopGoodsPublishedVo goodsPublishedVo, Integer platformType, Integer logType, Integer operationType, String orderSn); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParsePddStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParsePddStrategy.java new file mode 100644 index 0000000..6a91620 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParsePddStrategy.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.service.strategy; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import org.dromara.zhishu.domain.vo.GoodsItemPddVo; +import org.dromara.zhishu.domain.vo.ItemListVo; +import org.springframework.stereotype.Service; + +@Service +public class ItemListJsonStringParsePddStrategy implements ItemListJsonStringParseStrategy{ + @Override + public ItemListVo itemListJsonStringParse(String itemListStr) { + return JSON.parseObject(itemListStr, new TypeReference>() {}); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsKWStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsKWStrategy.java new file mode 100644 index 0000000..6c2a262 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsKWStrategy.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.zhishu.domain.dto.request.UpdateShopGoodsPriceRequest; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ShopGoodsKWStrategy implements ShopGoodsStrategy { + + @Autowired + private KfzClient kfzClient; + + @Override + public void synchronizationGoods(Long shopId) { + kfzClient.synchronizationGoods(UrlUtil.getKfzServiceUrl(), shopId, null, 1); + } + + @Override + public Boolean setShopGoodsOnSaleStatus(Long mallId, String token, Integer isOnSale, List ItemList) { + return false; + } + + @Override + public Boolean updateShopGoodsPrice(Long mallId, String token, List ItemList) { + return false; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsPddStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsPddStrategy.java new file mode 100644 index 0000000..69f4e04 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsPddStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.zhishu.service.strategy; + +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.zhishu.controller.PddController; +import org.dromara.zhishu.domain.dto.request.*; +import org.dromara.zhishu.domain.dto.response.CalculatePriceByTemplateResponse; +import org.dromara.zhishu.domain.dto.response.GoodsSaleStatusSetResponse; +import org.dromara.zhishu.domain.dto.response.UpdateSkuPriceResponse; +import org.dromara.zhishu.service.IPriceTemplateService; +import org.dromara.zhishu.service.client.PddClient; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class ShopGoodsPddStrategy implements ShopGoodsStrategy { + + private final PddClient pddClient; + + private final PddController pddController; + + private final IPriceTemplateService priceTemplateService; + + @Override + public void synchronizationGoods(Long shopId) { + + } + + @Override + public Boolean setShopGoodsOnSaleStatus(Long mallId, String token, Integer isOnSale, List ItemList) { + // 批量操作拼多多店铺商品上/下架 + GoodsSaleStatusSetBatchRequest updateOnLineRequest = new GoodsSaleStatusSetBatchRequest(); + updateOnLineRequest.setToken(token); + updateOnLineRequest.setIsOnSale(isOnSale); + updateOnLineRequest.setGoodsPlatformIds(ItemList.stream().map(UpdateShopGoodsPriceRequest.Item::getPlatformId).toList()); + R listR = pddClient.goodsSaleStatusSet(UrlUtil.getPddServiceUrl(), updateOnLineRequest); + // CSV文件中商品上/下架状态 + UpdateShopGoodsDataPriceCSVRequest updateCsvRequest = new UpdateShopGoodsDataPriceCSVRequest(); + updateCsvRequest.setMallId(mallId); + updateCsvRequest.setIsOnSale(isOnSale); + updateCsvRequest.setSkuItemList(ItemList.stream().map(item -> new UpdateShopGoodsDataPriceCSVRequest.SkuItem(item.getPlatformId(), null, null, null)).toList()); + R booleanR = pddController.updateShopGoodsDataPriceCSV(updateCsvRequest); + return true; + } + + @Override + public Boolean updateShopGoodsPrice(Long mallId, String token, List ItemList) { + // 根据价格模板计算商品价格 + List requestList = ItemList.stream().map(item -> { + // 转换为分(乘以100,并四舍五入) + BigDecimal cents = new BigDecimal(item.getPrice()); + Long priceInCents = cents.longValue(); + return new CalculatePriceByTemplateRequest(item.getPlatformId().toString(), priceInCents); + }).toList(); + + List priceList = priceTemplateService.getPriceByPlatformId(requestList); + if (ObjectUtil.isEmpty(priceList)) { + throw new ServiceException("根据价格模板计算商品价格失败"); + } + HashMap priceMap = new HashMap<>(); + for (CalculatePriceByTemplateResponse response : priceList) { + priceMap.put(Long.valueOf(response.getPlatformId()), response); + } + // 批量修改店铺商品价格 + UpdateSkuPriceRequest updateSkuPriceRequest = new UpdateSkuPriceRequest(); + updateSkuPriceRequest.setToken(token); + List goodsSkus = ItemList.stream().filter(item -> ObjectUtil.isNotNull(priceMap.get(item.getPlatformId()))) + .map(item -> { + UpdateSkuPriceRequest.GoodsSku goodsSku = new UpdateSkuPriceRequest.GoodsSku(); + goodsSku.setGoodsPlatformId(item.getPlatformId()); + goodsSku.setGroupPrice(priceMap.get(item.getPlatformId()).getGroupPrice()); + goodsSku.setSinglePrice(priceMap.get(item.getPlatformId()).getSinglePrice()); + goodsSku.setSkuId(item.getSkuId()); + return goodsSku; + }).toList(); + updateSkuPriceRequest.setGoodsSkus(goodsSkus); + if (goodsSkus.isEmpty()) return false; + R listR = pddClient.updateSkuPrice(UrlUtil.getPddServiceUrl(), updateSkuPriceRequest); + + // CSV文件中商品的价格 + UpdateShopGoodsDataPriceCSVRequest updateCsvRequest = new UpdateShopGoodsDataPriceCSVRequest(); + updateCsvRequest.setMallId(mallId); + List list = ItemList.stream().map(item -> { + CalculatePriceByTemplateResponse response = priceMap.get(item.getPlatformId()); + Long groupPrice = null; + if (ObjectUtil.isNotEmpty(response)) { + groupPrice = response.getGroupPrice(); + } + return new UpdateShopGoodsDataPriceCSVRequest.SkuItem(item.getPlatformId(), item.getSkuId(), null, groupPrice); + }).toList(); + updateCsvRequest.setSkuItemList(list); + R booleanR = pddController.updateShopGoodsDataPriceCSV(updateCsvRequest); + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsStrategy.java new file mode 100644 index 0000000..bddf093 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsStrategy.java @@ -0,0 +1,14 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.zhishu.domain.dto.request.UpdateShopGoodsPriceRequest; + +import java.util.List; + +public interface ShopGoodsStrategy { + + void synchronizationGoods(Long shopId); + + Boolean setShopGoodsOnSaleStatus(Long mallId, String token, Integer isOnSale, List ItemList); + + Boolean updateShopGoodsPrice(Long mallId, String token, List ItemList); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/ExcelTaskRunnable.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/ExcelTaskRunnable.java new file mode 100644 index 0000000..13d9a54 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/ExcelTaskRunnable.java @@ -0,0 +1,32 @@ +package org.dromara.zhishu.threads; + +import java.util.List; +import java.util.Map; +import org.dromara.zhishu.domain.bo.ExcelTaskBo; + +public class ExcelTaskRunnable implements Runnable{ + +// private final IPddService pddService; + + + private final Map map; + private final ExcelTaskBo excelTaskBo; +// private final List list; + + +// public PddTaskRunnable(IPddService pddService,Map map, TaskBo taskBo, List list) { +// this.pddService = pddService; +// this.map = map; +// this.taskBo = taskBo; +// this.list = list; +// } + public ExcelTaskRunnable(Map map, ExcelTaskBo excelTaskBo){ + this.map = map; + this.excelTaskBo = excelTaskBo; + } + + @Override + public void run() { + + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/KfzAutoAddRunnable.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/KfzAutoAddRunnable.java new file mode 100644 index 0000000..a395c6c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/KfzAutoAddRunnable.java @@ -0,0 +1,137 @@ +package org.dromara.zhishu.threads; + +import org.anyline.annotation.Autowired; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsDetailBo; +import org.dromara.zhishu.domain.dto.request.SoldOutRequest; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.TShopDepotAotuVo; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.mapper.TShopDepotAotuMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.impl.KongfzServiceImpl; +import org.springframework.context.ApplicationContext; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.util.*; + +public class KfzAutoAddRunnable implements Runnable { + + private ApplicationContext applicationContext; + + private final IShopDetailService shopDetailService; + private final IShopGoodsPublishedService shopGoodsPublishedService; + private final IShopService shopService; + private final KongfzServiceImpl kongfzService; + private final IZhishuShopGoodsService zhishuShopService; + private final IZhishuShopGoodsDetailService zhishuShopGoodsDetailService; + private final TShopDepotAotuMapper tShopDepotAotuMapper; // 添加Mapper + + private final Long userId; + private final ZhishuShopGoods shopGoods; + + public KfzAutoAddRunnable(Long userId, + IShopService shopService, + IShopDetailService shopDetailService, + IShopGoodsPublishedService shopGoodsPublishedService, + KongfzServiceImpl kongfzService, + IZhishuShopGoodsService zhishuShopService, + ApplicationContext applicationContext, + IZhishuShopGoodsDetailService zhishuShopGoodsDetailService, + ZhishuShopGoods shopGoods, + TShopDepotAotuMapper tShopDepotAotuMapper) { // 添加Mapper参数 + this.shopService = shopService; + this.shopDetailService = shopDetailService; + this.shopGoodsPublishedService = shopGoodsPublishedService; + this.kongfzService = kongfzService; + this.zhishuShopService=zhishuShopService; + this.applicationContext = applicationContext; + this.zhishuShopGoodsDetailService = zhishuShopGoodsDetailService; + this.userId = userId; + this.shopGoods = shopGoods; + this.tShopDepotAotuMapper = tShopDepotAotuMapper; // 初始化Mapper + } + + @Override + public void run() { + List result = shopService.selectCorrelationByUserId(userId); + List myShopIds = shopService.getShopIdByUserIdAndExpirationTime(userId); + + // 安全处理null值 + List tempList = new ArrayList<>(); + if (result != null && !result.isEmpty()) { + tempList.addAll(result); + } + if (myShopIds != null && !myShopIds.isEmpty()) { + tempList.addAll(myShopIds); + } + + // 去重,最终结果赋值给shopIds + Set uniqueSet = new LinkedHashSet<>(tempList); + List shopIds = new ArrayList<>(uniqueSet); + + + + String templateType = shopGoods.getTemplateType() == null ? "" : shopGoods.getTemplateType(); + if(templateType.equals("2")){ + /** + * 添加商品信息补全表 + */ + ZhishuShopGoodsDetailBo zhishuShopGoodsDetailBo = new ZhishuShopGoodsDetailBo(); + zhishuShopGoodsDetailBo.setPid(Long.parseLong(shopGoods.getId())); + zhishuShopGoodsDetailBo.setPublisher(shopGoods.getPublisher()); + zhishuShopGoodsDetailBo.setPublishertime(shopGoods.getPrintTime()); + zhishuShopGoodsDetailBo.setAuthor(shopGoods.getAuthor()); + zhishuShopGoodsDetailBo.setFormat(shopGoods.getFormat()); + zhishuShopGoodsDetailBo.setWordage(shopGoods.getWordage()); + zhishuShopGoodsDetailBo.setUnifiedisbn(shopGoods.getGoodUnifyIsbn()); + zhishuShopGoodsDetailService.insertByBo(zhishuShopGoodsDetailBo); + } + for (int i = 0; i < shopIds.size(); i++) { + String shopId = shopIds.get(i); + ShopDetailVo vo = shopDetailService.queryByShopId(Long.valueOf(shopId)); + if(vo == null || vo.getAutoAdd() == null){ + continue; + } + // 如果autoAdd为1,调用商品发布方法 + if ("1".equals(vo.getAutoAdd())) { + // 获取店铺信息 + ShopVo shopVo = shopService.queryById(Long.valueOf(shopId)); + //如果不是拼多多商品,则需要校验是否订阅了服务 + if(!shopVo.getShopType().equals("1") && (shopVo.getIsExpiration() == null || !shopVo.getIsExpiration().equals("1"))){ + continue; + } + // 查询是否已发布商品 + ShopGoodsPublishedVo shopGoodsPublishedVo = shopGoodsPublishedService.queryByShopIdAndShopGoodsId(shopId, shopGoods.getId()); + if (shopGoodsPublishedVo != null) { + // 若是已发布数据,则修改孔夫子店铺商品库存 + kongfzService.goodUpdateStock(shopVo.getToken(), shopGoodsPublishedVo.getPlatformId(), shopGoods.getInventory().toString()); + } else { + // 若不是已发布数据,则新发布商品 + List shopList = new ArrayList<>(); + shopList.add(shopId); + //封装数据 + List> goodsList = new ArrayList<>(); + List goodsDataList = new ArrayList<>(); + // 0 id 1 isbn 2 bookName 3 price 4 stock 5 conditionCode品相 6 artNo 货号 7 运费 + goodsDataList.add(shopGoods.getId().toString()); + goodsDataList.add(shopGoods.getIsbn()); + goodsDataList.add(shopGoods.getGoodsName()); + goodsDataList.add(shopGoods.getPrice().toString()); + goodsDataList.add(shopGoods.getInventory().toString()); + goodsDataList.add(shopGoods.getConditionCode()); + goodsDataList.add(shopGoods.getArtNo()); + goodsDataList.add(shopGoods.getTemplateMinPrice()); + goodsList.add(goodsDataList); + //存储 + Map detailData = new HashMap(); + Map map = Map.of("shopIds", shopList, "bookList", goodsList,"userId",userId,"mark","autoGoodsAdd","X-PDD-Pati","","detailData",detailData,"categoryId",shopGoods.getCategoryId() == null ? "" : shopGoods.getCategoryId()); + IZhishuShopGoodsService zhishuShopGoodsService = applicationContext.getBean(IZhishuShopGoodsService.class); + zhishuShopGoodsService.goodsAutoAdd(map); + } + } + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/ShopGoodsTaskRunnable.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/ShopGoodsTaskRunnable.java new file mode 100644 index 0000000..bd01d2f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/threads/ShopGoodsTaskRunnable.java @@ -0,0 +1,45 @@ +package org.dromara.zhishu.threads; + + +import com.alibaba.fastjson.JSON; +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.bo.FilterSetBo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.vo.BookBaseInfoVo; +import org.dromara.zhishu.domain.vo.FilterSetVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.ZhishuShopImagesVo; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.util.CnumberUtils; +import org.dromara.zhishu.util.EasyExcelUtil; +import org.dromara.zhishu.util.InterfaceUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ShopGoodsTaskRunnable implements Runnable { + + + private final IZhishuShopGoodsService zhishuShopGoodsService; + private final Map map; + private final Long userId; + private final ShopVo shopVo; + + public ShopGoodsTaskRunnable(IZhishuShopGoodsService zhishuShopGoodsService,Map map,Long userId,ShopVo shopVo) { + this.zhishuShopGoodsService = zhishuShopGoodsService; + this.map = map; + this.userId = userId; + this.shopVo = shopVo; + } + @Override + public void run() { + zhishuShopGoodsService.goodsAdd(map,userId, shopVo); + } +} + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/AliOssUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/AliOssUtils.java new file mode 100644 index 0000000..eb416f8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/AliOssUtils.java @@ -0,0 +1,318 @@ +package org.dromara.zhishu.util; + +import java.io.*; +import java.net.HttpURLConnection; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; + +import com.aliyun.oss.*; +import com.aliyun.oss.common.comm.SignVersion; + + + + +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.zhishu.domain.BookBaseInfoPhp; +import org.dromara.zhishu.domain.LocalMultipartFile; +import org.dromara.zhishu.domain.vo.BookBaseInfoVo; +import org.dromara.zhishu.domain.vo.ZhishuShopImagesVo; +import org.springframework.web.multipart.MultipartFile; + +import java.net.URL; +import java.util.Date; + +import java.io.File; +import java.util.UUID; + +import static org.dromara.zhishu.util.InterfaceUtils.getInterface; + +public class AliOssUtils { + + public static void main(String[] args){ + + String path = "http://localhost:8080/system/shopImages/listByPage"; + getInterface(path,""); + + } + +// public static void main(String[] args) { +// +// String staticUrl = "http://111.229.25.150:8001/"; +// +// String minioUrl = "https://book.goods.img.buzhiyushu.cn/"; +// +// //最新跑数据 7 +// int page = 3669; +// String per_page = "1000"; +// int markNum = (page-1)*1000; +// +// String phpUrl = "https://test.kongfz.buzhiyushu.cn/api"; +// +// List batch; +// do{ +// String path = "/bookBase/getBookBaseInfoAll"; +// path = path + "?page=" + page + "&per_page=" + per_page; +// String BookBaseInfoVoStr = getInterface(phpUrl, path); +// BookBaseInfoVoStr = JsonObjUtil.jsonToMapWithCamelKeys(BookBaseInfoVoStr); +// BookBaseInfoPhp bookBaseInfoPhp = JsonUtil.transferToObj(BookBaseInfoVoStr, BookBaseInfoPhp.class); +// batch = bookBaseInfoPhp.getData(); +// for(BookBaseInfoVo vo : batch){ +// String id = vo.getId(); +// String isbn = vo.getIsbn(); +// String bookName = vo.getBookName(); +// String bookPic = vo.getBookPic(); +// if(StringUtils.isEmpty(bookPic)){ +// markNum++; +// System.out.println("第"+markNum+"条:没有图片:"+bookName+";id:"+id); +// continue; +// } +// +// String result = UploadUtil.getMd5FirstChart(bookName); +// //首先校验静态路径 +// if(isImageExists(staticUrl+bookPic)){ +// //存在 +// markNum++; +// System.out.println("第"+markNum+"条:存在静态路径:"+staticUrl+bookPic+";"+bookName+";id:"+id); +// +// MultipartFile multipartFile = getMultipartFileFromPathUrl(staticUrl+bookPic); +// +// try { +// setIamge("bookInfoImages/"+result+"/"+bookPic,multipartFile.getBytes()); +// } catch (IOException e) { +// e.printStackTrace(); +// System.out.println("第"+markNum+"条:上传异常:"+staticUrl+bookPic+";"+bookName+";id:"+id); +// } +// }else if(isImageExists(minioUrl+result+"/"+bookPic)){ +// //不存在静态路径,获取minio存放位置 +// //MD5加密获取大写首字母 +// markNum++; +// String minioPath = minioUrl+result+"/"+bookPic; +// System.out.println("第"+markNum+"条:存在minio路径:"+minioPath+";"+bookName+";id:"+id); +// +// +// MultipartFile multipartFile = getMultipartFileFromPathUrl(minioPath); +// +// try { +// setIamge("bookInfoImages/"+result+"/"+bookPic,multipartFile.getBytes()); +// } catch (IOException e) { +// e.printStackTrace(); +// System.out.println("第"+markNum+"条:上传异常:"+staticUrl+bookPic+";"+bookName+";id:"+id); +// } +// }else{ +// markNum++; +// System.out.println("第"+markNum+"条:数据库有数据,但是没有图片:"+bookName+";id:"+id); +// processTxtFile("D:/zhishu/noImage.txt",isbn); +// } +// } +// page++; +// processTxtFile("D:/zhishu/pageNum1.txt",page+":"+new Date()); +// }while(batch != null); +// +////// setIamge("exampleobject.txt"); +//// +//// getImagePath("exampleobject.txt"); +// } + + public static void setIamge(String objectName,byte[] data){ + // Endpoint以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com,其它Region请按实际情况填写。 + String endpoint = "https://oss-cn-beijing.aliyuncs.com"; + String bucketName = "buzhiyushu"; + // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。 + // 关于OSS支持的Region与Endpoint的对应关系,请参见https://www.alibabacloud.com/help/zh/oss/user-guide/regions-and-endpoints。 + String region = "cn-beijing"; + + // 从环境变量中获取访问凭证。运行本代码示例之前,请先配置环境变量 + EnvironmentVariableCredentialsProvider2 credentialsProvider = new EnvironmentVariableCredentialsProvider2(); + + // 创建OSSClient实例。 + // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。 + ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); + // 显式声明使用 V4 签名算法 + clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); + OSS ossClient = OSSClientBuilder.create() + .endpoint(endpoint) + .credentialsProvider(credentialsProvider) + .region(region) + .build(); + try { +// // 1. 创建存储空间(Bucket) +// ossClient.createBucket(bucketName); +// System.out.println("1. Bucket " + bucketName + " 创建成功。"); + // 2. 上传文件 +// String content = "Hello OSS"; + ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(data)); + System.out.println("文件 " + objectName + " 上传成功。"); + +// System.out.println("文件访问地址:"+getImagePath(objectName)); + +// // 3. 下载文件 +// OSSObject ossObject = ossClient.getObject(bucketName, objectName); +// InputStream contentStream = ossObject.getObjectContent(); +// BufferedReader reader = new BufferedReader(new InputStreamReader(contentStream)); +// String line; +// System.out.println("3. 下载的文件内容:"); +// while ((line = reader.readLine()) != null) { +// System.out.println(line); +// } +// contentStream.close(); +// // 4. 列出文件 +// System.out.println("4. 列出 Bucket 中的文件:"); +// ObjectListing objectListing = ossClient.listObjects(bucketName); +// for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) { +// System.out.println(" - " + objectSummary.getKey() + " (大小 = " + objectSummary.getSize() + ")"); +// } +// // 5. 删除文件 +// ossClient.deleteObject(bucketName, objectName); +// System.out.println("5. 文件 " + objectName + " 删除成功。"); +// // 6. 删除存储空间(Bucket) +// ossClient.deleteBucket(bucketName); +// System.out.println("6. Bucket " + bucketName + " 删除成功。"); + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } +// catch (ClientException | IOException ce) { +// System.out.println("Caught an ClientException, which means the client encountered " +// + "a serious internal problem while trying to communicate with OSS, " +// + "such as not being able to access the network."); +// System.out.println("Error Message:" + ce.getMessage()); +// } + finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + } + + public static String getImagePath(String objectName){ + // 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。 + String endpoint = "https://oss-cn-beijing.aliyuncs.com"; + // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 + EnvironmentVariableCredentialsProvider2 credentialsProvider = new EnvironmentVariableCredentialsProvider2(); + // 填写Bucket名称,例如examplebucket。 + String bucketName = "buzhiyushu";; + // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。 + String region = "cn-beijing"; + + // 创建OSSClient实例。 + // 当OSSClient实例不再使用时,调用shutdown方法以释放资源。 + ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration(); + clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); + OSS ossClient = OSSClientBuilder.create() + .endpoint(endpoint) + .credentialsProvider(credentialsProvider) + .clientConfiguration(clientBuilderConfiguration) + .region(region) + .build(); + + try { + // 设置预签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。 + Date expiration = new Date(new Date().getTime() + 3600 * 1000L); + // 生成以GET方法访问的预签名URL。本示例没有额外请求头,其他人可以直接通过浏览器访问相关内容。 + URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration); + System.out.println("文件访问地址:"+url); + return url.toString(); + } catch (OSSException oe) { + System.out.println("Caught an OSSException, which means your request made it to OSS, " + + "but was rejected with an error response for some reason."); + System.out.println("Error Message:" + oe.getErrorMessage()); + System.out.println("Error Code:" + oe.getErrorCode()); + System.out.println("Request ID:" + oe.getRequestId()); + System.out.println("Host ID:" + oe.getHostId()); + } catch (ClientException ce) { + System.out.println("Caught an ClientException, which means the client encountered " + + "a serious internal problem while trying to communicate with OSS, " + + "such as not being able to access the network."); + System.out.println("Error Message:" + ce.getMessage()); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + return null; + } + + + /** + * 根据路径获取TXT文件内容,如果文件不存在则创建。 + * + * @param filePath 文件的路径 + * @param contentToAppend 要追加的内容 + * @return 文件的完整内容 + */ + public static String processTxtFile(String filePath, String contentToAppend) { + try { + File file = new File(filePath); + + // 如果文件不存在,则创建 + if (!file.exists()) { + file.createNewFile(); + } + + // 读取文件内容 + String fileContent = new String(Files.readAllBytes(Paths.get(filePath))); + + // 追加内容并换行 + try (FileWriter writer = new FileWriter(file, true)) { + writer.write(System.lineSeparator() + contentToAppend); + } + + return fileContent; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * 校验文件是否存在 + */ + public static boolean isImageExists(String imageUrl) { + try { + URL url = new URL(imageUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("HEAD"); + int responseCode = connection.getResponseCode(); + return responseCode == HttpURLConnection.HTTP_OK; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + public static MultipartFile getMultipartFileFromPathUrl(String filePath) { + try { + URL url = new URL(filePath); + // 提取文件后缀 + String fileSuffix = ""; + String path = url.getPath(); + int lastDotIndex = path.lastIndexOf("."); + if (lastDotIndex > 0 && lastDotIndex < path.length()) { + fileSuffix = path.substring(lastDotIndex); // 如 ".jpg" + } + + // 创建带后缀的临时文件 + Path tempFile = Files.createTempFile("upload-"+ UUID.randomUUID(), fileSuffix); + + // 下载远程文件到本地临时文件 + try (InputStream in = url.openStream()) { + Files.copy(in, tempFile, StandardCopyOption.REPLACE_EXISTING); + } + + // 构建 MultipartFile + return new LocalMultipartFile(tempFile.toFile()); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DaDanUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DaDanUtil.java new file mode 100644 index 0000000..e167bc8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DaDanUtil.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.util; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.util.FileCopyUtils; +import java.nio.charset.StandardCharsets; +import java.io.InputStreamReader; +import java.io.IOException; + +/** + * 快递打单工具类 + */ +public class DaDanUtil { + + + /** + * 获取韵达快递预览单的Base64字符串 + * @return Base64编码的PDF内容 + */ + public static String getYunDaPreview(){ + try { + // 从resources目录读取文件 + ClassPathResource resource = new ClassPathResource("preview/韵达快递单pdf_base64.txt"); + InputStreamReader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8); + + // 读取文件内容 + String base64String = FileCopyUtils.copyToString(reader); + + // 去除可能存在的换行符和空白字符 + return base64String.replaceAll("\\s", ""); + + } catch (IOException e) { + e.printStackTrace(); + // 如果读取失败,返回空字符串或抛出运行时异常 + throw new RuntimeException("读取韵达快递预览单Base64文件失败", e); + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EncryptionUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EncryptionUtil.java new file mode 100644 index 0000000..4ce5ba6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EncryptionUtil.java @@ -0,0 +1,143 @@ +package org.dromara.zhishu.util; + +import cn.hutool.core.util.ObjectUtil; +import org.dromara.common.core.exception.ServiceException; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; + +/** + * 加密工具类 + */ +public class EncryptionUtil { + + // 默认中间替换部分的字符串 + private static final String MASK = "****"; + + // 加密使用的密钥(16字节 = 128位) + private static final String SECRET_KEY = "BZYSErpSecretKey"; // 必须是16位字符 + + // 偏移量(IV),也必须是16字节 + private static final String INIT_VECTOR = "ZSErpOffsetValue"; + + /** + * 对字符串类型(String)的参数进行打码处理 + * + * @param input 输入字符串 + * @return 打码后的字符串 + */ + public static String maskString(String input) { + if (input == null || ObjectUtil.isEmpty(input)) { + return input; + } else if (input.length() < 4) { + return input.charAt(0) + MASK; // 如果长度不足4,直接返回原值 + } + return input.substring(0, 2) + MASK + input.substring(input.length() - 2); + } + + /** + * 对长整型(Long)参数进行打码处理 + * + * @param input 输入长整型数值 + * @return 打码后的字符串 + */ + public static String maskLong(Long input) { + if (input == null) { + return null; + } + String str = input.toString(); + return maskString(str); + } + + /** + * 使用 AES 加密字符串 + * + * @param value 待加密的明文字符串 + * @return 加密后的 Base64 字符串 + */ + public static String encrypt(String value) { + try { + IvParameterSpec iv = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8")); + SecretKeySpec skeySpec = new SecretKeySpec(SECRET_KEY.getBytes("UTF-8"), "AES"); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); + + byte[] encrypted = cipher.doFinal(value.getBytes()); + return Base64.getEncoder().encodeToString(encrypted); + } catch (Exception ex) { + throw new RuntimeException("加密失败", ex); + } + } + + /** + * 使用 AES 加密长整型(Long) + * + * @param value 待加密的明文字符串 + * @return 加密后的 Base64 字符串 + */ + public static String encrypt(Long value) { + if (value == null) { + return null; + } + return encrypt(value.toString()); + } + + /** + * 使用 AES 解密字符串 + * + * @param encrypted 加密后的 Base64 字符串 + * @return 解密后的明文字符串 + */ + public static String decrypt(String encrypted) { + try { + IvParameterSpec iv = new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8")); + SecretKeySpec skeySpec = new SecretKeySpec(SECRET_KEY.getBytes("UTF-8"), "AES"); + + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); + + byte[] decoded = Base64.getDecoder().decode(encrypted); + byte[] original = cipher.doFinal(decoded); + return new String(original); + } catch (Exception ex) { + throw new RuntimeException("解密失败", ex); + } + } + + /** + * 使用 AES 解密字符串返回长整型(Long) + * + * @param encrypted 加密后的 Base64 字符串 + * @return 解密后的明文字符串 + */ + public static Long decryptToLong(String encrypted) { + String decrypt = decrypt(encrypted); + try { + return Long.valueOf(decrypt); + } catch (NumberFormatException e) { + throw new ServiceException("该字符串不能解析成长整型"); + } + } + + /** + * 对电话号进行打码处理 + * + * @param phoneNumber 输入长整型数值 + * @return 打码后的字符串 + */ + public static String maskPhoneNumber(Long phoneNumber) { + if (phoneNumber == null) { + return null; + } + String str = phoneNumber.toString(); + if (str == null || ObjectUtil.isEmpty(str)) { + return str; + } + return str.substring(0, 3) + MASK + str.substring(str.length() - 4); + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/HttpUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/HttpUtils.java new file mode 100644 index 0000000..f93181e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/HttpUtils.java @@ -0,0 +1,158 @@ +package org.dromara.zhishu.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.dromara.common.core.utils.StringUtils; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class HttpUtils { + + private static final HttpClient httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) // 设置连接超时 + .build(); + + private static final ObjectMapper objectMapper = new ObjectMapper(); // 用于处理JSON + + /** + * 发送GET请求 + * @param url 请求的URL地址 + * @param headers 请求头的Map集合 + * @return 返回响应的结果,JSON格式 + * @throws Exception 请求失败时抛出异常 + */ + public static String sendGet(String url, Map headers) throws Exception { + // 创建GET请求 + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(url)) + .timeout(Duration.ofSeconds(10)) // 请求超时时间 + .GET(); + + // 设置请求头 + if (headers != null) { + headers.forEach(requestBuilder::header); + } + + HttpRequest request = requestBuilder.build(); + + // 发送请求并获取响应 + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + // 判断响应状态码 + if (response.statusCode() == 200) { + return response.body(); // 返回响应体 + } else { + throw new RuntimeException("GET请求失败,状态码: " + response.statusCode()); + } + } + + /** + * 发送POST请求 + * @param url 请求的URL地址 + * @param headers 请求头的Map集合 + * @param requestBody 请求体,可以是JSON格式的字符串 + * @return 返回响应的结果,JSON格式 + * @throws Exception 请求失败时抛出异常 + */ + public static String sendPost(String url, Map headers, String requestBody) throws Exception { + // 创建POST请求 + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(url)) + .timeout(Duration.ofSeconds(10)) // 请求超时时间 + .POST(HttpRequest.BodyPublishers.ofString(requestBody)); // 设置请求体 + + // 设置请求头 + if (headers != null) { + headers.forEach(requestBuilder::header); + } + + HttpRequest request = requestBuilder.build(); + + // 发送请求并获取响应 + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + // 判断响应状态码 + if (response.statusCode() == 200) { + return response.body(); // 返回响应体 + } else { + throw new RuntimeException("POST请求失败,状态码: " + response.statusCode()); + } + } + + /** + * 将对象转换为JSON字符串 + * @param obj 需要转换的对象 + * @return 对象的JSON格式字符串 + * @throws Exception 转换失败时抛出异常 + */ + public static String convertObjectToJson(Object obj) throws Exception { + return objectMapper.writeValueAsString(obj); + } + + /** + * 将JSON字符串转换为指定类型的对象 + * @param json JSON字符串 + * @param clazz 转换后的对象类型 + * @param 泛型 + * @return 转换后的对象 + * @throws Exception 转换失败时抛出异常 + */ + public static T convertJsonToObject(String json, Class clazz) throws Exception { + return objectMapper.readValue(json, clazz); + } + + public static String getResponseCookie(String loginResponse) { + if (StringUtils.isEmpty(loginResponse)) { + return null; + } + + try { + // 首先尝试解析为JSON格式 + if (loginResponse.trim().startsWith("{")) { + Map responseMap = objectMapper.readValue(loginResponse, Map.class); + + // 检查响应头中是否包含Set-Cookie字段 + if (responseMap.containsKey("headers")) { + Map headers = (Map) responseMap.get("headers"); + if (headers.containsKey("Set-Cookie")) { + Object setCookieObj = headers.get("Set-Cookie"); + if (setCookieObj instanceof String) { + String setCookie = (String) setCookieObj; + // 提取PHPSESSID + String[] cookies = setCookie.split(";"); + for (String cookie : cookies) { + if (cookie.trim().startsWith("PHPSESSID=")) { + return cookie.trim(); + } + } + } else if (setCookieObj instanceof java.util.List) { + // 如果Set-Cookie是一个列表,遍历查找PHPSESSID + List cookieList = (List) setCookieObj; + for (String cookie : cookieList) { + if (cookie.contains("PHPSESSID=")) { + String[] parts = cookie.split(";"); + return parts[0].trim(); + } + } + } + } + } + } else { + // 如果不是JSON格式,可能是HTML响应,直接返回null + // 这种情况通常意味着需要重新登录 + return null; + } + return null; + } catch (Exception e) { + // 记录异常但不抛出,返回null表示需要重新登录 + e.printStackTrace(); + return null; + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/InterfaceUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/InterfaceUtils.java new file mode 100644 index 0000000..a52f819 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/InterfaceUtils.java @@ -0,0 +1,1002 @@ +package org.dromara.zhishu.util; + +import com.alibaba.fastjson.JSON; +import okhttp3.*; +import okhttp3.MultipartBody; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.concurrent.TimeUnit; + + +public class InterfaceUtils { + + private static RestTemplate createRestTemplate() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(5000); // 连接超时时间 + factory.setReadTimeout(30000); // 读取超时时间 + return new RestTemplate(factory); + } + + private static RestTemplate createRestTemplateShort() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(1000); // 连接超时时间 + factory.setReadTimeout(1000); // 读取超时时间 + return new RestTemplate(factory); + } + + public static String getInterface(String ip, String url) { + int maxRetries = 3; + int retryDelayMillis = 1000; // 初始重试延迟时间,单位毫秒 + RestTemplate restTemplate = createRestTemplateWithUtf8(); + + for (int attempt = 1; attempt <= maxRetries; attempt++) { + try { + String fullUrl = ip + url; + ResponseEntity response = restTemplate.getForEntity(fullUrl, String.class); + if (response.getStatusCode().is2xxSuccessful()) { + return response.getBody(); // 成功返回结果 + } + } catch (Exception e) { + System.err.println("Attempt " + attempt + " failed for getInterface(" + ip + ", " + url + "): " + e.getMessage()); + } + + // 如果不是最后一次重试,等待一段时间再重试 + if (attempt < maxRetries) { + try { + Thread.sleep(retryDelayMillis); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Thread interrupted during retry", ie); + } + } + } + + throw new RuntimeException("Failed to get interface after " + maxRetries + " attempts"); + } + + public static String getInterfaceSync(String ip, String url) { + int maxRetries = 1; + int retryDelayMillis = 100000; // 初始重试延迟时间,单位毫秒 + RestTemplate restTemplate = createRestTemplateWithUtf8(); + + for (int attempt = 1; attempt <= maxRetries; attempt++) { + try { + String fullUrl = ip + url; + ResponseEntity response = restTemplate.getForEntity(fullUrl, String.class); + if (response.getStatusCode().is2xxSuccessful()) { + return response.getBody(); // 成功返回结果 + } + } catch (Exception e) { + System.err.println("Attempt " + attempt + " failed for getInterface(" + ip + ", " + url + "): " + e.getMessage()); + } + + // 如果不是最后一次重试,等待一段时间再重试 + if (attempt < maxRetries) { + try { + Thread.sleep(retryDelayMillis); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Thread interrupted during retry", ie); + } + } + } + + throw new RuntimeException("Failed to get interface after " + maxRetries + " attempts"); + } + + public static String getInterfaceForBaseInfo(String ip, String url) { + int maxRetries = 3; + int retryDelayMillis = 1000; // 初始重试延迟时间,单位毫秒 + RestTemplate restTemplate = createRestTemplateWithUtf8(); + + for (int attempt = 1; attempt <= maxRetries; attempt++) { + try { + String fullUrl = ip + url; + ResponseEntity response = restTemplate.getForEntity(fullUrl, String.class); + if (response.getStatusCode().is2xxSuccessful()) { + return response.getBody(); // 成功返回结果 + } + } catch (Exception e) { + System.err.println("Attempt " + attempt + " failed for getInterface(" + ip + ", " + url + "): " + e.getMessage()); + } + + // 如果不是最后一次重试,等待一段时间再重试 + if (attempt < maxRetries) { + try { + Thread.sleep(retryDelayMillis); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Thread interrupted during retry", ie); + } + } + } + + throw new RuntimeException("本系统目前仅支持展示100万条数据,超出部分暂时不支持展示,正在抓紧优化中..."); + } + + + // 创建支持 UTF-8 的 RestTemplate + private static RestTemplate createRestTemplateWithUtf8() { + RestTemplate restTemplate = new RestTemplate(); + + // 获取原有的消息转换器 + List> converters = restTemplate.getMessageConverters(); + + // 移除原有的 StringHttpMessageConverter + converters.removeIf(converter -> converter instanceof StringHttpMessageConverter); + + // 添加支持 UTF-8 的 StringHttpMessageConverter + StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8); + stringConverter.setWriteAcceptCharset(false); // 重要:防止在请求头中添加 charset + + // 将 UTF-8 转换器添加到列表开头,优先使用 + converters.add(0, stringConverter); + + restTemplate.setMessageConverters(converters); + return restTemplate; + } + + public static String getInterfaceGetShort(String ip, String url){ + // 目标接口 URL + url = ip + url; + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplateShort(); + // 发起 GET 请求 + ResponseEntity response = restTemplate.getForEntity(url, String.class); + + return response.getBody(); + } + + public static String getInterfaceGet(String ip, String url, Map params) { + // 目标接口 URL + url = ip + url; + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplate(); + // 发起 GET 请求 + ResponseEntity response = restTemplate.getForEntity(url, String.class, params); + String responseBody = response.getBody(); + + return responseBody; + } + + /** + * params方式的get请求 + * @param ip + * @param url + * @param params + * @return + */ + public static String getInterfaceGetWithParams(String ip, String url, Map params) { + // 构建基础URL + String baseUrl = ip + url; + + // 使用UriComponentsBuilder构建带参数的URL + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl); + + if (params != null && !params.isEmpty()) { + for (Map.Entry entry : params.entrySet()) { + if (entry.getKey() != null && entry.getValue() != null) { + builder.queryParam(entry.getKey(), entry.getValue().toString()); + } + } + } + + String fullUrl = builder.toUriString(); + + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplate(); + // 发起 GET 请求 + ResponseEntity response = restTemplate.getForEntity(fullUrl, String.class); + String responseBody = response.getBody(); + + return responseBody; + } + + + + public static String getInterfacePost(String ip, String url, Map params) { + // 目标接口 URL + url = ip + url; + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplate(); + // 发起 Post 请求 + ResponseEntity response = restTemplate.postForEntity(url, params, String.class); + String responseBody = response.getBody(); + + return responseBody; + } + + public static String postForm(String ip, String url, Map formData) { + // 拼接完整 URL + url = ip + url; + + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplate(); + + // 构建表单数据 + MultiValueMap body = new LinkedMultiValueMap<>(); + formData.forEach(body::add); + + // 设置请求头为 multipart/form-data + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + + // 发送 POST 请求 + ResponseEntity response = restTemplate.postForEntity(url, requestEntity, String.class); + return response.getBody(); + } + + /** + * 通用POST JSON请求方法(直接传JSON字符串) + * + * @param ip 服务器IP地址 + * @param url 请求路径 + * @param jsonBody JSON格式的字符串 + * @return 响应内容 + */ + public static String postJson(String ip, String url, String jsonBody) { + // 拼接完整 URL + url = ip + url; + + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplate(); + + // 设置请求头为 application/json + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON); + + // 创建请求实体 + HttpEntity requestEntity = new HttpEntity<>(jsonBody, headers); + + // 发送 POST 请求 + ResponseEntity response = restTemplate.postForEntity(url, requestEntity, String.class); + + return response.getBody(); + } + + public static Map postFormObject(String ip, String url, Map formData) { + // 拼接完整 URL + url = ip + url; + + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplate(); + + // 构建表单数据 + MultiValueMap body = new LinkedMultiValueMap<>(); + formData.forEach(body::add); + + // 设置请求头为 multipart/form-data + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + + // 发送 POST 请求 + ResponseEntity response = restTemplate.postForEntity(url, requestEntity, Map.class); + return response.getBody(); + } + + //拼多多传递header参数 + public static String getInterface(String ip, String url, Map headers) { + // 目标接口 URL + url = ip + url; + + // 创建 RestTemplate 实例 + RestTemplate restTemplate = createRestTemplate(); + + // 设置请求头 + HttpHeaders httpHeaders = new HttpHeaders(); + if (headers != null) { + headers.forEach(httpHeaders::add); + } + + // 封装请求头和请求体(GET 请求无 body,传 null) + HttpEntity requestEntity = new HttpEntity<>(null, httpHeaders); + + // 发起 GET 请求 + ResponseEntity response = restTemplate.exchange( + url, + HttpMethod.GET, + requestEntity, + String.class + ); + + return response.getBody(); + } + + public static String processImageAndExtractPddUrl(Map params) { + int maxRetries = 3; + int retryDelayMillis = 1000; // 初始重试延迟时间,单位毫秒 +// String url = "http://103.236.81.185:9000/processImage"; + String url = "http://36.212.20.113:9000/processImage"; + + for (int attempt = 1; attempt <= maxRetries; attempt++) { + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(5, TimeUnit.SECONDS) // 连接超时 + .readTimeout(10, TimeUnit.SECONDS) // 读取超时 + .build(); + + try { + // 构建multipart/form-data请求体 + MultipartBody.Builder builder = new MultipartBody.Builder() + .setType(MultipartBody.FORM); + + // 添加各个参数 + if (params.get("goodsName") != null) { + builder.addFormDataPart("goodsName", params.get("goodsName").toString()); + } + if (params.get("isbn") != null) { + builder.addFormDataPart("isbn", params.get("isbn").toString()); + } + if (params.get("isKW") != null) { + builder.addFormDataPart("isKW", params.get("isKW").toString()); + } + if (params.get("autoUpload") != null) { + builder.addFormDataPart("autoUpload", params.get("autoUpload").toString()); + } + + // 处理文件数据 + if (params.get("imageData") != null && params.get("fileName") != null) { + String base64Data = params.get("imageData").toString(); + String fileName = params.get("fileName").toString(); + + // 将Base64解码为字节数组 + byte[] fileBytes = java.util.Base64.getDecoder().decode(base64Data); + + // 根据文件扩展名确定MIME类型 + String mimeType = "application/octet-stream"; + if (fileName.toLowerCase().endsWith(".jpg") || fileName.toLowerCase().endsWith(".jpeg")) { + mimeType = "image/jpeg"; + } else if (fileName.toLowerCase().endsWith(".png")) { + mimeType = "image/png"; + } else if (fileName.toLowerCase().endsWith(".gif")) { + mimeType = "image/gif"; + } + + MediaType mediaType = MediaType.parse(mimeType); + RequestBody fileBody = RequestBody.create(fileBytes, mediaType); + builder.addFormDataPart("filepath", fileName, fileBody); + } else if (params.get("imageUrl") != null) { + // 如果没有文件数据但有图片URL + builder.addFormDataPart("imageUrl", params.get("imageUrl").toString()); + } + + RequestBody body = builder.build(); + Request request = new Request.Builder() + .url(url) + .method("POST", body) + .build(); + + Response response = client.newCall(request).execute(); + if (response.isSuccessful()) { + String responseBody = response.body().string(); + + // 解析JSON响应 + com.fasterxml.jackson.databind.JsonNode jsonNode = new com.fasterxml.jackson.databind.ObjectMapper().readTree(responseBody); + + if (jsonNode.has("success") && jsonNode.get("success").asBoolean()) { + com.fasterxml.jackson.databind.JsonNode data = jsonNode.get("data"); + if (data.has("pddUpload")) { + com.fasterxml.jackson.databind.JsonNode pddUpload = data.get("pddUpload"); + if (pddUpload.has("success") && pddUpload.get("success").asBoolean()) { + String result = pddUpload.get("result").asText(); + // 解析result中的JSON获取url + com.fasterxml.jackson.databind.JsonNode resultJson = new com.fasterxml.jackson.databind.ObjectMapper().readTree(result); + if (resultJson.has("url")) { + return resultJson.get("url").asText(); + } + } + } + } + } + response.close(); + } catch (Exception e) { + System.err.println("Attempt " + attempt + " failed for processImageAndExtractPddUrl: " + e.getMessage()); + } + + // 如果不是最后一次重试,等待一段时间再重试 + if (attempt < maxRetries) { + try { + Thread.sleep(retryDelayMillis); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Thread interrupted during retry", ie); + } + } + } + + throw new RuntimeException("Failed to process image and extract PDD URL after " + maxRetries + " attempts"); + } + + public static void processImage(String formData) { + int maxRetries = 3; + int retryDelayMillis = 1000; // 初始重试延迟时间,单位毫秒 + String url = "http://175.27.224.66:8090/processImage"; + + for (int attempt = 1; attempt <= maxRetries; attempt++) { + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(5, TimeUnit.SECONDS) // 连接超时 + .readTimeout(10, TimeUnit.SECONDS) // 读取超时 + .build(); + + MediaType mediaType = MediaType.parse("application/json"); + RequestBody body = RequestBody.create(mediaType, formData); + Request request = new Request.Builder() + .url(url) + .method("POST", body) + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + try { + response = client.newCall(request).execute(); + if (response.isSuccessful()) { + return; // 成功则直接返回 + } + } catch (IOException e) { + System.err.println("Attempt " + attempt + " failed for processImage: " + e.getMessage()); + }finally { + // 确保响应被关闭 + if (response != null) { + response.close(); + } + } + + // 如果不是最后一次重试,等待一段时间再重试 + if (attempt < maxRetries) { + try { + Thread.sleep(retryDelayMillis); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Thread interrupted during retry", ie); + } + } + } + + throw new RuntimeException("Failed to process image after " + maxRetries + " attempts"); + } + + // ===================== 新增的签名相关方法 ===================== + + /** + * 带签名的表单提交方法 + * 将formData中的所有参数参与签名计算,然后将签名添加到参数中一起提交 + * + * @param ip 服务器IP地址 + * @param url 请求路径 + * @param formData 表单数据(所有业务参数,会自动计算签名并添加sign字段) + * @return 响应内容 + */ + public static String postFormWithSign(String ip, String url, Map formData) { + // 复制一份参数,避免修改原Map + Map paramsWithSign = new HashMap<>(formData); + + // 计算签名(使用原始参数,不包含sign) + String sign = signParams(formData); + System.out.println("签名: " + sign); + + // 将签名添加到参数中 + paramsWithSign.put("sign", sign); + + // 调用原始方法发送请求 + return postForm(ip, url, paramsWithSign); + } + + /** + * 对请求参数进行MD5签名(与Go代码逻辑完全一致) + * + * @param params 待签名的原始参数键值对(不包含sign字段) + * @return 计算出的签名字符串(大写MD5) + */ + public static String signParams(Map params) { + // 定义签名密钥 + String secretKey = "jRQdCh52Z55Kzh1hADaA2ZtdTKetj2PXk60Tz5Yc0iz9aD8Wafbk7CwAZ8cz69A9zb9caZ3k9dnR3Ys06J5nYFPrZ0xE9p6TY8DCD538ryiRjW81YTPmk41tCEnXizPh"; + + // 创建过滤后的参数映射表 + Map filteredParams = new HashMap<>(); + + // 遍历原始参数,过滤掉空值、sign字段和sign_type字段 + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (value != null && !value.isEmpty() + && !"sign".equals(key) + && !"sign_type".equals(key)) { + filteredParams.put(key, value); + } + } + + // 提取所有键名并排序 + List keys = new ArrayList<>(filteredParams.keySet()); + Collections.sort(keys); + + // 拼接字符串 + StringBuilder signStrBuilder = new StringBuilder(); + for (int i = 0; i < keys.size(); i++) { + String key = keys.get(i); + if (i > 0) { + signStrBuilder.append("&"); + } + signStrBuilder.append(key) + .append("=") + .append(filteredParams.get(key)); + } + + // 追加密钥 + signStrBuilder.append("&key=").append(secretKey); + String signStr = signStrBuilder.toString(); + + System.out.println("待签名字符串: " + signStr); + + // 计算MD5并转为大写 + return md5(signStr).toUpperCase(); + } + + /** + * MD5加密 + * + * @param input 输入字符串 + * @return MD5哈希值(小写) + */ + private static String md5(String input) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 algorithm not found", e); + } + } + + // ===================== 第二个接口的调用工具方法 ===================== + + /** + * 提交任务体(带签名)- 支持多个body字段 + * 对应Go中的setTaskBody方法 + * + * @param ip 服务器IP地址 + * @param url 请求路径 + * @param taskId 任务ID + * @param bodyList body对象列表(Map格式,会自动转为JSON字符串) + * @return 响应内容 + */ + public static String postTaskBodyWithSign(String ip, String url, String taskId, List> bodyList) { + return postTaskBodyWithSign(ip, url, taskId, bodyList, null); + } + + /** + * 提交任务体(带签名)- 支持多个body字段和重试机制 + * + * @param ip 服务器IP地址 + * @param url 请求路径 + * @param taskId 任务ID + * @param bodyList body对象列表(Map格式,会自动转为JSON字符串) + * @param maxRetries 最大重试次数(为null时使用默认3次) + * @return 响应内容 + */ + public static String postTaskBodyWithSign(String ip, String url, String taskId, + List> bodyList, Integer maxRetries) { + int retries = maxRetries != null ? maxRetries : 3; + int retryDelayMillis = 1000; + + for (int attempt = 1; attempt <= retries; attempt++) { + try { + // 将所有body无缝拼接用于签名(将Map转为JSON字符串) + StringBuilder allBodyBuilder = new StringBuilder(); + for (Map bodyObj : bodyList) { + allBodyBuilder.append(JSON.toJSONString(bodyObj)); + } + String allBody = allBodyBuilder.toString(); + + // 构建签名参数(用于计算签名) + Map signParams = new HashMap<>(); + signParams.put("task_id", taskId); + signParams.put("body", allBody); + + // 计算签名 + String sign = signParams(signParams); + System.out.println("第" + attempt + "次尝试 - 签名: " + sign); + + // 拼接完整URL + String fullUrl = ip + url; + + // 创建RestTemplate + RestTemplate restTemplate = createRestTemplate(); + + // 构建multipart/form-data请求体 + MultiValueMap body = new LinkedMultiValueMap<>(); + + // 添加task_id和sign + body.add("task_id", taskId); + body.add("sign", sign); + + // 关键:为每个body对象单独添加表单字段(同名) + for (Map bodyObj : bodyList) { + body.add("body", JSON.toJSONString(bodyObj)); + } + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + + // 发送请求 + ResponseEntity response = restTemplate.postForEntity(fullUrl, requestEntity, String.class); + + if (response.getStatusCode().is2xxSuccessful()) { + System.out.println("成功提交任务体,共" + bodyList.size() + "条数据"); + return response.getBody(); + } else { + System.err.println("请求失败,状态码: " + response.getStatusCode()); + } + } catch (Exception e) { + System.err.println("第" + attempt + "次尝试失败: " + e.getMessage()); + if (attempt == retries) { + throw new RuntimeException("提交任务体失败,已重试" + retries + "次", e); + } + } + + // 如果不是最后一次重试,等待一段时间再重试 + if (attempt < retries) { + try { + Thread.sleep(retryDelayMillis); + retryDelayMillis *= 2; // 指数退避 + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + throw new RuntimeException("线程被中断", ie); + } + } + } + + throw new RuntimeException("提交任务体失败,已重试" + retries + "次"); + } + + /** + * 批量提交任务体(自动分批提交) + * + * @param ip 服务器IP地址 + * @param url 请求路径 + * @param taskId 任务ID + * @param bodyList body对象列表 + * @param batchSize 每批提交的数量 + * @return 提交结果列表 + */ + public static List batchPostTaskBodyWithSign(String ip, String url, String taskId, + List> bodyList, int batchSize) { + List results = new ArrayList<>(); + List> batch = new ArrayList<>(); + + for (int i = 0; i < bodyList.size(); i++) { + batch.add(bodyList.get(i)); + + if (batch.size() >= batchSize || i == bodyList.size() - 1) { + try { + String result = postTaskBodyWithSign(ip, url, taskId, batch); + results.add(result); + System.out.println("已提交第" + (results.size()) + "批,共" + batch.size() + "条数据"); + batch.clear(); + } catch (Exception e) { + System.err.println("批次提交失败: " + e.getMessage()); + // 可以选择继续或抛出异常 + throw new RuntimeException("批次提交失败", e); + } + } + } + + return results; + } + + /** + * 提交任务体(使用Object参数,自动转换) + * + * @param ip 服务器IP地址 + * @param url 请求路径 + * @param taskId 任务ID + * @param bodyJsonList body JSON字符串列表 + * @return 响应内容 + */ + public static String postTaskBodyWithSignFromJson(String ip, String url, String taskId, List bodyJsonList) { + // 将所有body无缝拼接用于签名 + String allBody = String.join("", bodyJsonList); + + // 构建签名参数 + Map signParams = new HashMap<>(); + signParams.put("task_id", taskId); + signParams.put("body", allBody); + + // 计算签名 + String sign = signParams(signParams); + System.out.println("签名: " + sign); + + // 拼接完整URL + String fullUrl = ip + url; + + // 创建RestTemplate + RestTemplate restTemplate = createRestTemplate(); + + // 构建multipart/form-data请求体 + MultiValueMap body = new LinkedMultiValueMap<>(); + + // 添加task_id和sign + body.add("task_id", taskId); + body.add("sign", sign); + + // 添加多个body字段 + for (String bodyJson : bodyJsonList) { + body.add("body", bodyJson); + } + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.MULTIPART_FORM_DATA); + + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + + // 发送请求 + try { + ResponseEntity response = restTemplate.postForEntity(fullUrl, requestEntity, String.class); + return response.getBody(); + } catch (Exception e) { + throw new RuntimeException("请求失败: " + e.getMessage(), e); + } + } + + + // ===================== 新增的API签名方法(支持Query和Body参数签名) ===================== + + /** + * 构建待签名字符串(支持Query和Body参数) + * 参数名按ASCII排序,拼接格式:key1=value1&key2=value2,前后包裹appSecret + * + * @param queryParams Query参数 + * @param bodyParams Body参数(表单格式) + * @return 待签名字符串 + */ + private static String buildSignString(Map queryParams, Map bodyParams) { + String appSecret = "psi_api_sign_secret"; + Map allParams = new HashMap<>(); + + // 合并Query参数(排除sign) + if (queryParams != null) { + for (Map.Entry entry : queryParams.entrySet()) { + if (!"sign".equals(entry.getKey()) && entry.getValue() != null && !entry.getValue().isEmpty()) { + allParams.put(entry.getKey(), entry.getValue()); + } + } + } + + // 合并Body参数(排除sign) + if (bodyParams != null) { + for (Map.Entry entry : bodyParams.entrySet()) { + if (!"sign".equals(entry.getKey()) && entry.getValue() != null && !entry.getValue().isEmpty()) { + allParams.put(entry.getKey(), entry.getValue()); + } + } + } + + // 参数名ASCII排序 + List keys = new ArrayList<>(allParams.keySet()); + Collections.sort(keys); + + // 构建参数字符串 + StringBuilder paramPairs = new StringBuilder(); + for (int i = 0; i < keys.size(); i++) { + if (i > 0) { + paramPairs.append("&"); + } + paramPairs.append(keys.get(i)).append("=").append(allParams.get(keys.get(i))); + } + + // 前后包裹appSecret + return appSecret + paramPairs.toString() + appSecret; + } + + /** + * 计算签名(支持MD5和SHA256) + * + * @param signString 待签名字符串 + * @param signMethod 签名方法(md5或sha256) + * @return 签名字符串(大写) + */ + private static String calculateSign(String signString, String signMethod) { + if ("sha256".equalsIgnoreCase(signMethod)) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] digest = md.digest(signString.getBytes(StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b)); + } + return sb.toString().toUpperCase(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-256 algorithm not found", e); + } + } else { + // 默认使用MD5 + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(signString.getBytes(StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b)); + } + return sb.toString().toUpperCase(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 algorithm not found", e); + } + } + } + + + /** + * 通用带签名和认证的GET请求(支持指定签名方法) + * + * @param baseUrl 完整的基础URL(包含IP和路径,如:http://192.168.101.213:9090/api/admin/employee/list) + * @param queryParams Query参数(会自动添加签名) + * @param authorizationToken Bearer Token(可选,传null则不添加) + * @param signMethod 签名方法(md5或sha256) + * @return 响应内容 + */ + public static String getWithSign(String baseUrl, Map queryParams, String authorizationToken, String signMethod) { + // 复制参数,避免修改原Map + Map paramsWithSign = new HashMap<>(); + if (queryParams != null) { + paramsWithSign.putAll(queryParams); + } + + // 如果签名方法未指定且参数中没有sign_method,使用默认值 + if (signMethod != null && !paramsWithSign.containsKey("sign_method")) { + paramsWithSign.put("sign_method", signMethod); + } + + // 获取实际的签名方法 + String actualSignMethod = paramsWithSign.getOrDefault("sign_method", "md5"); + + // 构建待签名字符串 + String signString = buildSignString(paramsWithSign, null); + System.out.println("待签名字符串: " + signString); + + // 计算签名 + String sign = calculateSign(signString, actualSignMethod); + System.out.println("计算签名: " + sign); + + // 将签名添加到参数中 + paramsWithSign.put("sign", sign); + + // 构建完整URL + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl); + for (Map.Entry entry : paramsWithSign.entrySet()) { + if (entry.getValue() != null && !entry.getValue().isEmpty()) { + builder.queryParam(entry.getKey(), entry.getValue()); + } + } + String finalUrl = builder.toUriString(); + System.out.println("请求URL: " + finalUrl); + + // 创建 RestTemplate + RestTemplate restTemplate = createRestTemplateWithUtf8(); + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + if (authorizationToken != null && !authorizationToken.isEmpty()) { + headers.set("Authorization", "Bearer " + authorizationToken); + } + + // 发送请求 + HttpEntity requestEntity = new HttpEntity<>(null, headers); + ResponseEntity response = restTemplate.exchange( + finalUrl, + HttpMethod.GET, + requestEntity, + String.class + ); + + return response.getBody(); + } + + /** + * 通用带签名和认证的POST表单请求(支持指定签名方法) + * + * @param baseUrl 完整的基础URL + * @param queryParams Query参数(可选) + * @param bodyParams Body表单参数(会自动添加签名) + * @param authorizationToken Bearer Token(可选) + * @param signMethod 签名方法(md5或sha256) + * @return 响应内容 + */ + public static String postFormWithSign(String baseUrl, Map queryParams, + Map bodyParams, String authorizationToken, + String signMethod) { + // 复制参数,避免修改原Map + Map queryWithSign = new HashMap<>(); + Map bodyWithSign = new HashMap<>(); + + if (queryParams != null) { + queryWithSign.putAll(queryParams); + } + if (bodyParams != null) { + bodyWithSign.putAll(bodyParams); + } + + // 如果签名方法未指定且参数中没有sign_method,使用默认值 + if (signMethod != null && !bodyWithSign.containsKey("sign_method")) { + bodyWithSign.put("sign_method", signMethod); + } + + // 获取实际的签名方法 + String actualSignMethod = bodyWithSign.getOrDefault("sign_method", "md5"); + + // 构建待签名字符串(包含Query和Body参数) + String signString = buildSignString(queryWithSign, bodyWithSign); + System.out.println("待签名字符串: " + signString); + + // 计算签名 + String sign = calculateSign(signString, actualSignMethod); + System.out.println("计算签名: " + sign); + + // 将签名添加到Body参数中 + bodyWithSign.put("sign", sign); + + // 构建完整URL(带Query参数) + String finalUrl = baseUrl; + if (queryWithSign != null && !queryWithSign.isEmpty()) { + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl); + for (Map.Entry entry : queryWithSign.entrySet()) { + if (entry.getValue() != null && !entry.getValue().isEmpty()) { + builder.queryParam(entry.getKey(), entry.getValue()); + } + } + finalUrl = builder.toUriString(); + } + System.out.println("请求URL: " + finalUrl); + + // 创建 RestTemplate + RestTemplate restTemplate = createRestTemplateWithUtf8(); + + // 构建表单数据 + MultiValueMap body = new LinkedMultiValueMap<>(); + for (Map.Entry entry : bodyWithSign.entrySet()) { + if (entry.getValue() != null) { + body.add(entry.getKey(), entry.getValue()); + } + } + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED); + if (authorizationToken != null && !authorizationToken.isEmpty()) { + headers.set("Authorization", "Bearer " + authorizationToken); + } + + // 发送请求 + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + ResponseEntity response = restTemplate.postForEntity(finalUrl, requestEntity, String.class); + + return response.getBody(); + } + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/JsonObjUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/JsonObjUtil.java new file mode 100644 index 0000000..0456575 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/JsonObjUtil.java @@ -0,0 +1,336 @@ +package org.dromara.zhishu.util; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.zhishu.enums.PddOrderEnum; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +public class JsonObjUtil { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static String getString(JsonObject orderObject, String code) { + + + if (orderObject.get(code).getClass().equals(JsonObject.class)) { + return orderObject.get(code).getAsJsonObject().toString(); + } + if (orderObject.get(code).getClass().equals(JsonArray.class)) { + return orderObject.get(code).getAsJsonArray().toString(); + } + + String res = ""; + try { + res = orderObject.get(code).getAsString(); + + } catch (Exception e) { +// System.out.println("11111111111111111111111111:"+code); + e.printStackTrace(); + } + + if (ObjectUtils.isNotEmpty(res)) { + return res; + } + + return null; + } + + public static BigDecimal getDecimal(JsonObject orderObject, String code) { + String res = orderObject.get(code).getAsString(); + + if (ObjectUtils.isNotEmpty(res)) { + return new BigDecimal(res); + } + + return null; + } + + + public static Long getLong(JsonObject orderObject, String code) { + String res = orderObject.get(code).getAsString(); + + if (ObjectUtils.isNotEmpty(res)) { + return Long.valueOf(res); + } + + return null; + } + + // 将下划线命名转为小驼峰命名(保持缩写大写) + public static String toLowerCamelCaseKeepAbbr(String input) { + StringBuilder result = new StringBuilder(); + boolean nextUpperCase = false; + int wordStart = 0; // 标记单词开始位置 + + for (int i = 0; i < input.length(); i++) { + char current = input.charAt(i); + + if (current == '_') { + nextUpperCase = true; + wordStart = i + 1; // 下一个单词开始位置 + } else { + if (nextUpperCase) { + // 检查是否是常见的缩写 + String remaining = input.substring(wordStart); + if (remaining.startsWith("pdd") || remaining.startsWith("isbn") || + remaining.startsWith("id") || remaining.startsWith("url") || + remaining.startsWith("api") || remaining.startsWith("sql")) { + // 如果是缩写且后面还有下划线,整个缩写都大写 + if (remaining.indexOf('_', 1) > 0) { + result.append(remaining.substring(0, remaining.indexOf('_', 1)).toUpperCase()); + i = wordStart + remaining.indexOf('_', 1) - 1; + } else { + // 最后一个单词,首字母大写 + result.append(Character.toUpperCase(remaining.charAt(0))); + result.append(remaining.substring(1).toLowerCase()); + i = input.length() - 1; + } + } else { + // 普通单词,首字母大写 + result.append(Character.toUpperCase(current)); + } + nextUpperCase = false; + } else { + // 第一个字符小写 + if (i == 0) { + result.append(Character.toLowerCase(current)); + } else { + result.append(current); + } + } + } + } + + return result.toString(); + } + + // 将下划线命名转为小驼峰命名 + public static String toLowerCamelCase(String input) { + StringBuilder result = new StringBuilder(); + boolean nextUpperCase = false; + + for (int i = 0; i < input.length(); i++) { + char current = input.charAt(i); + + if (current == '_') { + nextUpperCase = true; + } else { + if (nextUpperCase) { + result.append(Character.toUpperCase(current)); + nextUpperCase = false; + } else { + result.append(Character.toLowerCase(current)); + } + } + } + + return result.toString(); + } + + // 递归处理 Map 和 List 结构 + @SuppressWarnings("unchecked") + public static Object convertKeysToCamelCase(Object object) { + if (object instanceof Map) { + Map map = (Map) object; + Map convertedMap = new LinkedHashMap<>(); + + for (Map.Entry entry : map.entrySet()) { + String key = (String) entry.getKey(); + Object value = entry.getValue(); + + String camelKey = toLowerCamelCase(key); + convertedMap.put(camelKey, convertKeysToCamelCase(value)); + } + + return convertedMap; + } else if (object instanceof List) { + List list = (List) object; + List convertedList = new ArrayList<>(); + + for (Object item : list) { + convertedList.add(convertKeysToCamelCase(item)); + } + + return convertedList; + } else { + return object; + } + } + + // 递归处理 Map 和 List 结构(保持缩写大写) + @SuppressWarnings("unchecked") + public static Object convertKeysToCamelCaseKeepAbbr(Object object) { + if (object instanceof Map) { + Map map = (Map) object; + Map convertedMap = new LinkedHashMap<>(); + + for (Map.Entry entry : map.entrySet()) { + String key = (String) entry.getKey(); + Object value = entry.getValue(); + + String camelKey = toLowerCamelCaseKeepAbbr(key); + convertedMap.put(camelKey, convertKeysToCamelCaseKeepAbbr(value)); + } + + return convertedMap; + } else if (object instanceof List) { + List list = (List) object; + List convertedList = new ArrayList<>(); + + for (Object item : list) { + convertedList.add(convertKeysToCamelCaseKeepAbbr(item)); + } + + return convertedList; + } else { + return object; + } + } + + // 主方法:将 JSON 字符串转为 Map,并转换 key 为驼峰命名 + public static String jsonToMapWithCamelKeys(String jsonString) { + try{ + ObjectMapper objectMapper = new ObjectMapper(); + Object rawMap = objectMapper.readValue(jsonString, Object.class); + return JsonUtil.transferToJson(convertKeysToCamelCase(rawMap)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // 主方法:将 JSON 字符串转为 Map,并转换 key 为驼峰命名(保持缩写大写) + public static String jsonToMapWithCamelKeysKeepAbbr(String jsonString) { + try{ + ObjectMapper objectMapper = new ObjectMapper(); + Object rawMap = objectMapper.readValue(jsonString, Object.class); + return JsonUtil.transferToJson(convertKeysToCamelCaseKeepAbbr(rawMap)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // 将驼峰命名转为下划线命名 + public static String toSnakeCase(String input) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char current = input.charAt(i); + if (Character.isUpperCase(current) && i > 0) { + result.append('_'); + result.append(Character.toLowerCase(current)); + } else { + result.append(Character.toLowerCase(current)); + } + } + return result.toString(); + } + + // 递归处理 Map 和 List 结构,将所有 key 转为下划线命名 + @SuppressWarnings("unchecked") + public static Object convertKeysToSnakeCase(Object object) { + if (object instanceof Map) { + Map map = (Map) object; + Map convertedMap = new LinkedHashMap<>(); + + for (Map.Entry entry : map.entrySet()) { + String key = (String) entry.getKey(); + Object value = entry.getValue(); + + String snakeKey = toSnakeCase(key); + convertedMap.put(snakeKey, convertKeysToSnakeCase(value)); + } + + return convertedMap; + } else if (object instanceof List) { + List list = (List) object; + List convertedList = new ArrayList<>(); + + for (Object item : list) { + convertedList.add(convertKeysToSnakeCase(item)); + } + + return convertedList; + } else { + return object; + } + } + + // 主方法:将对象转为 JSON 字符串,并转换 key 为下划线命名 + public static String objectToJsonWithSnakeKeys(Object object) { + try{ + ObjectMapper objectMapper = new ObjectMapper(); + String jsonString = objectMapper.writeValueAsString(object); + Object rawMap = objectMapper.readValue(jsonString, Object.class); + return objectMapper.writeValueAsString(convertKeysToSnakeCase(rawMap)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 从网络URL读取JSON并解析为Map + * @param urlString JSON文件的网络地址 + * @return 包含JSON数据的Map + * @throws IOException 如果读取或解析失败 + */ + public static Map parseJsonFromUrl(String urlString) throws IOException { + HttpURLConnection connection = null; + BufferedReader reader = null; + + try { + // 创建URL连接 + URL url = new URL(urlString); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + + // 检查响应代码 + int responseCode = connection.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK) { + throw new IOException("HTTP请求失败,响应码: " + responseCode); + } + + // 读取响应内容 + reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + + // 解析JSON到Map + return objectMapper.readValue(response.toString(), + new TypeReference>() {}); + + } finally { + // 关闭资源 + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (connection != null) { + connection.disconnect(); + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/MapUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/MapUtils.java new file mode 100644 index 0000000..5fe4618 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/MapUtils.java @@ -0,0 +1,93 @@ +package org.dromara.zhishu.util; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import com.fasterxml.jackson.databind.DeserializationFeature; + +public class MapUtils { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + static { + // 配置ObjectMapper忽略未知属性 + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + + public static Map convertToMap(Object obj) { + try { + Map map = new HashMap<>(); + for (PropertyDescriptor pd : java.beans.Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors()) { + if ("class".equals(pd.getName())) continue; + Method getter = pd.getReadMethod(); + Object value = getter != null ? getter.invoke(obj) : null; + map.put(pd.getName(), value); + } + return map; + }catch (Exception e){ + return new HashMap<>(); + } + } + + /** + * map转为实体类 + * @param map + * @param clazz + * @return + * @param + */ + public static T convertToObject(Map map, Class clazz) { + try { + return objectMapper.convertValue(map, clazz); + } catch (Exception e) { + throw new RuntimeException("转换失败", e); + } + } + + /** + * 转换Map的key为驼峰命名 + * @param sourceMap 原始Map + * @return 新Map + */ + public static Map convertKeys(Map sourceMap) { + Map resultMap = new LinkedHashMap<>(); + + for (Map.Entry entry : sourceMap.entrySet()) { + String newKey = underscoreToCamel(entry.getKey()); + resultMap.put(newKey, entry.getValue()); + } + + return resultMap; + } + + /** + * 将下划线命名转为驼峰命名 + * @param str 下划线格式的字符串 + * @return 驼峰格式的字符串 + */ + public static String underscoreToCamel(String str) { + if (str == null || str.isEmpty()) { + return str; + } + + StringBuilder result = new StringBuilder(); + String[] parts = str.split("_"); + + // 第一个单词全小写 + result.append(parts[0].toLowerCase()); + + // 后续单词首字母大写 + for (int i = 1; i < parts.length; i++) { + if (!parts[i].isEmpty()) { + result.append(parts[i].substring(0, 1).toUpperCase()) + .append(parts[i].substring(1).toLowerCase()); + } + } + + return result.toString(); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ObjectComparatorUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ObjectComparatorUtils.java new file mode 100644 index 0000000..14108d2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ObjectComparatorUtils.java @@ -0,0 +1,47 @@ +package org.dromara.zhishu.util; + +import java.lang.reflect.Field; + +public class ObjectComparatorUtils { + + public static boolean compareCommonFields(Object obj1, Object obj2) { + if (obj1 == null || obj2 == null) { + return obj1 == obj2; + } + + Field[] fields1 = obj1.getClass().getDeclaredFields(); + Field[] fields2 = obj2.getClass().getDeclaredFields(); + + for (Field field1 : fields1) { + field1.setAccessible(true); + for (Field field2 : fields2) { + field2.setAccessible(true); + if (field1.getName().equals(field2.getName()) && field1.getType().equals(field2.getType())) { + try { + // 比较两个字段的值 + if (!compareFieldValues(field1.get(obj1), field2.get(obj2))) { + return false; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + return false; + } + } + } + } + return true; + } + + private static boolean compareFieldValues(Object value1, Object value2) { + // 如果两个值都是null,认为它们相等 + if (value1 == null && value2 == null) { + return true; + } + // 如果其中一个为null(另一个不为null),则不相等 + if (value1 == null || value2 == null) { + return false; + } + // 使用equals方法比较值 + return value1.equals(value2); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddRequestUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddRequestUtil.java new file mode 100644 index 0000000..25201e9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddRequestUtil.java @@ -0,0 +1,135 @@ +package org.dromara.zhishu.util; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import com.pdd.pop.sdk.http.PopClient; +import com.pdd.pop.sdk.http.PopHttpClient; +import com.pdd.pop.sdk.http.api.pop.request.PddOrderNumberListIncrementGetRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddOrderNumberListIncrementGetResponse; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.checkerframework.checker.units.qual.C; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.domain.dto.PddOrderIncrementQuery; +import org.dromara.zhishu.enums.PddResCodeEnum; +import org.dromara.zhishu.mapper.ShopMapper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Log4j2 +@RequiredArgsConstructor +public class PddRequestUtil { + + + @Resource + ShopMapper shopMapper; + + @Value("${pdd.app.clientId}") + private String clientId; + + @Value("${pdd.app.clientSecret}") + private String clientSecret; + + + // 调用拼多多增量 获取订单 + public String getIncrementRequest(PddOrderIncrementQuery query){ + + //todo 获取所有的店铺列表 + PopClient client = new PopHttpClient(clientId, clientSecret); + PddOrderNumberListIncrementGetRequest request = new PddOrderNumberListIncrementGetRequest(); + + request.setEndUpdatedAt(query.getEnd_updated_at()); + request.setIsLuckyFlag(query.getIs_lucky_flag()); + request.setOrderStatus(query.getOrder_status()); + request.setPage(query.getPage()); + request.setRefundStatus(query.getRefund_status()); + request.setStartUpdatedAt(query.getStart_updated_at()); + request.setTradeType(query.getTrade_type()); + request.setUseHasNext(true); + PddOrderNumberListIncrementGetResponse response = null; + try { + response = client.syncInvoke(request, query.getAccess_token()); + } catch (Exception e) { + throw new RuntimeException(e); + } +// System.out.println(JsonUtil.transferToJson(response)); + String res = JsonUtil.transferToJson(response); + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); + //字符串转换成对象 + JsonObject obj = gson.fromJson(res, JsonObject.class); + + if (ObjectUtils.isNotEmpty(obj.get(PddResCodeEnum.ERR.getCode()))) { + //报错信息 + JsonObject error_response = obj.get(PddResCodeEnum.ERR.getCode()).getAsJsonObject(); + log.error("调取拼多多接口失败{}", error_response); + } + // 如果存在就继续去调用 + if( ObjectUtils.isNotEmpty(obj.get(PddResCodeEnum.HAS_NEXT.getCode())) && obj.get(PddResCodeEnum.ORDER_LIST_OK.getCode()).getAsBoolean()){ + query.setPage(query.getPage()+1); + getIncrementRequest(query); + } + + if (ObjectUtils.isNotEmpty(obj.get(PddResCodeEnum.ORDER_SN_LIST.getCode()))) { + JsonArray asJsonArray = obj.getAsJsonObject(PddResCodeEnum.ORDER_SN_LIST.getCode()).getAsJsonArray(PddResCodeEnum.ORDER_LIST.getCode()); + if (ObjectUtils.isNotEmpty(asJsonArray)) { + // todo 写入数据库的操作 + + } + + } + + return ""; + } + + + + + + //todo 第一次新增店铺的 需要写一个从授权到最后的整个时间 +// @Scheduled(cron="*/15 * * * * *") + public void increment() { + + List shopList = shopMapper.selectList(null); + + //先查询上次的更新时间 + + for (Shop shop : shopList) { + + PddOrderIncrementQuery pddOrderIncrementQuery = new PddOrderIncrementQuery(); + + pddOrderIncrementQuery.setAccess_token(shop.getToken()); + + pddOrderIncrementQuery.setPage(1); + //发货状态,1-待发货,2-已发货待签收,3-已签收,5-全部 + pddOrderIncrementQuery.setOrder_status(5); + //订单类型(是否抽奖订单),0-全部,1-非抽奖订单,2-抽奖订单 + pddOrderIncrementQuery.setIs_lucky_flag(0); + // 售后状态,1-无售后或售后关闭,2-售后处理中,3-退款中,4-退款成功 5-全部 + pddOrderIncrementQuery.setRefund_status(5); + + long start_updated_at = shop.getStartUpdatedAt(); + long end_updated_at = start_updated_at + 300000; + + pddOrderIncrementQuery.setEnd_updated_at(end_updated_at); + pddOrderIncrementQuery.setStart_updated_at(start_updated_at); + + + getIncrementRequest(pddOrderIncrementQuery); + + + } + + } + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddUtils.java new file mode 100644 index 0000000..c767efc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddUtils.java @@ -0,0 +1,91 @@ +package org.dromara.zhishu.util; + +import com.pdd.pop.sdk.common.util.JsonUtil; +import com.pdd.pop.sdk.http.PopClient; +import com.pdd.pop.sdk.http.PopHttpClient; +import com.pdd.pop.sdk.http.api.file.request.PddGoodsImgUploadRequest; +import com.pdd.pop.sdk.http.api.file.response.PddGoodsImgUploadResponse; +import com.pdd.pop.sdk.http.api.pop.request.PddGoodsSpecIdGetRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddGoodsSpecIdGetResponse; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +public class PddUtils { + + private static final String clientId = "203c5a7ba8bd4b8488d5e26f93052642"; + + private static final String clientSecret = "892ffaa86e12b7a3d8d2942b669d9aa520ad8179"; + + /** + * 上传图片 + * @param file + * @param accessToken + * @return + */ + public static Map pddImageUpload(MultipartFile file, String accessToken) { + Map map = new HashMap<>(); + + try { + // 使用NIO创建临时文件 + Path tempFile = Files.createTempFile("pdd_upload_", null); + + try { + // 传输文件 + file.transferTo(tempFile.toFile()); + + // 执行上传 + PopClient client = new PopHttpClient(clientId, clientSecret); + PddGoodsImgUploadRequest request = new PddGoodsImgUploadRequest(); + request.setFile(tempFile.toAbsolutePath().toString()); + + PddGoodsImgUploadResponse response = client.syncInvoke(request, accessToken); + + if (response.getErrorResponse() != null) { + map.put("success",false); + map.put("message", JsonUtil.transferToJson(response.getErrorResponse())); + } else { + map.put("success",true); + map.put("message", "上传成功"); + map.put("url", response.getGoodsImgUploadResponse().getUrl()); + map.put("service_url",response.getGoodsImgUploadResponse().getUrl()); + } + + } finally { + // 确保删除临时文件 + Files.deleteIfExists(tempFile); + } + + } catch (Exception e) { + map.put("success",false); + map.put("message", "上传失败: " + e.getMessage()); + } + return map; + } + + + /** + * pdd.goods.spec.id.get生成商家自定义的规格 + * @param accessToken + * @param specName + * @return + */ + public static PddGoodsSpecIdGetResponse.GoodsSpecIdGetResponse getGoodsSpecId(String accessToken,String specName){ + PopClient client = new PopHttpClient(clientId, clientSecret); + + PddGoodsSpecIdGetRequest request = new PddGoodsSpecIdGetRequest(); + request.setParentSpecId(0L); + request.setSpecName(specName); + PddGoodsSpecIdGetResponse response = null; + try { + response = client.syncInvoke(request, accessToken); + } catch (Exception e) { + return null; + } + return response.getGoodsSpecIdGetResponse(); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UrlMultipartFile.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UrlMultipartFile.java new file mode 100644 index 0000000..2ef83ed --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UrlMultipartFile.java @@ -0,0 +1,75 @@ +package org.dromara.zhishu.util; + +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.URL; + +public class UrlMultipartFile implements MultipartFile { + + private final String name; + private final String originalFilename; + private final String contentType; + private final byte[] content; + + public UrlMultipartFile(String imageUrl, String fileName) throws IOException { + this.originalFilename = fileName; + this.name = "file"; + this.contentType = "image/jpeg"; + + // 下载图片内容到字节数组 + URL url = new URL(imageUrl); + try (InputStream inputStream = url.openStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + this.content = outputStream.toByteArray(); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public String getOriginalFilename() { + return originalFilename; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public boolean isEmpty() { + return content.length == 0; + } + + @Override + public long getSize() { + return content.length; + } + + @Override + public byte[] getBytes() throws IOException { + return content; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(content); + } + + @Override + public void transferTo(File dest) throws IOException, IllegalStateException { + try (FileOutputStream fos = new FileOutputStream(dest)) { + fos.write(content); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UrlUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UrlUtil.java new file mode 100644 index 0000000..ad1a2d2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UrlUtil.java @@ -0,0 +1,60 @@ +package org.dromara.zhishu.util; + +import org.springframework.stereotype.Component; + +@Component +public final class UrlUtil { + + public static String getUrl(){return "./file/";} + // public static String getUrl(){return "D:\\ShopGoodsData\\";} + + // pdd服务地址 + public static String getPddServiceUrl(){ return "http://pdd.buzhiyushu.cn"; } // 线上 + + public static String getKfzServiceUrl(){ return "http://146.56.227.42:8095"; } // 本地测试 + + // 万里牛服务地址 + public static String getWlnServiceUrl(){ return "http://146.56.227.42:9003"; } // 线上 + + // 资源服务地址 + public static String getFileServiceUrl(){ return "http://175.27.224.66:8093"; } // 本地测试 + + // 线上用内网 + public static String getUploadImgUrl(){return "http://10.206.0.10:8069";} + // 线上用内网 + public static String getImgResultUrl(){return "http://10.206.0.10:8070";} + + /** + * 拉取店铺商品任务 + */ + public static String getShopGoodsTaskUrl(){ + // return "http://localhost:18099"; + // return "http://10.206.0.9:14003"; + return "http://119.45.237.193:14013"; + } + + public static String getServiceGoUrl(){ +// return "http://118.195.130.47:9091"; + return "http://119.45.237.193:9096"; + } + + public static String getgoofishServiceUrl(){ return "http://146.56.192.164:19095"; } + + /** + * 新订单服务地址 + */ + public static String getOrderServiceUrl(){ + return "http://119.45.237.193:8073"; + //return "http://localhost:8075"; + } + + public static String getNewTaskUrl(){ + return "http://36.212.7.246:8283"; +// return "http://192.168.101.156:8080"; + } + + public static String getNewWarehouse(){ + // return "http://192.168.101.213:9090"; + return "https://psi.api.buzhiyushu.cn"; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ArtNoMoveMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ArtNoMoveMapper.xml new file mode 100644 index 0000000..6e93910 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ArtNoMoveMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/EmployeeMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/EmployeeMapper.xml new file mode 100644 index 0000000..f7eb8b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/EmployeeMapper.xml @@ -0,0 +1,36 @@ + + + + + INSERT INTO wave_employee (id, name, user_id, creat_time, update_time, del_flag) + VALUES (#{id}, #{name}, #{userId}, #{creatTime}, #{updateTime}, #{delFlag}) + + + + UPDATE wave_employee SET name = #{employeeName}, update_time = #{updateTime} + WHERE id = #{id} + + AND user_id = #{userid} + + + + + + + UPDATE wave_employee SET del_flag = 1, update_time = UNIX_TIMESTAMP() + WHERE id = #{id} + + AND user_id = #{userId} + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/LogisticsMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/LogisticsMapper.xml new file mode 100644 index 0000000..db988a7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/LogisticsMapper.xml @@ -0,0 +1,106 @@ + + + + + update t_logistics + + + `template_name` = #{templateName}, + + + `delivery_province` = #{deliveryProvince}, + + + `delivery_city` = #{deliveryCity}, + + + `delivery_area` = #{deliveryArea}, + + + `delivery_address` = #{deliveryAddress}, + + + `shipping` = #{shipping}, + + + `shipping_range` = #{shippingRange}, + + + pricing_method = #{pricingMethod}, + + + remark = #{remark}, + + + fir_price = #{firPrice}, + + + contact = #{contact}, + + + phone_number = #{phoneNumber}, + + + full_address = #{fullAddress}, + + + status = #{status}, + + + where id = #{id} + + + + + + + + + + + INSERT INTO `t_logistics` + (`template_name`, `delivery_province`, `delivery_city`, `delivery_area`, `delivery_address`, + `pricing_method`, `shipping`, `fir_wbv`, `fir_price`, `continue_wbv`, `continue_price`, + `status`, `shipping_range`, `warehouse_id`,remark) + VALUES (#{templateName}, #{deliveryProvince}, #{deliveryCity}, #{deliveryArea}, + #{deliveryAddress}, #{pricingMethod}, #{shipping}, #{firWbv}, #{firPrice}, + #{continueWbv}, + #{continuePrice}, #{status}, #{shippingRange}, #{warehouseId},#{remark}) + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/NewUserBoMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/NewUserBoMapper.xml new file mode 100644 index 0000000..112ed4d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/NewUserBoMapper.xml @@ -0,0 +1,30 @@ + + + + + +-- 在t_audit表中插入user_id + insert into t_audit(user_id) values(#{userId}) + + + insert into t_audit_info(id,audit_id,company_name,company_type,contact_person,contact_phone,email,license,remark,card_identity,license_name,license_number, + adress,business_license,license_time,business_license_time) + values(#{id},#{auditId},#{companyName},#{companyType},#{contactPerson},#{contactPhone},#{email},#{license},#{remark},#{cardIdentity},#{licenseName},#{licenseNumber}, + #{adress},#{businessLicense},#{licenseTime},#{businessLicenseTime}) + + + + update sys_user set email=#{email} where user_id = #{userId} + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PrintTemplateMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PrintTemplateMapper.xml new file mode 100644 index 0000000..0f7b4c3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PrintTemplateMapper.xml @@ -0,0 +1,58 @@ + + + + + + + + + + AND (t.create_by = #{bo.createBy} or t.create_by = '1') + + + + AND t.print_template_name LIKE CONCAT('%', #{bo.printTemplateName}, '%') + + + + AND t.status = #{bo.status} + + AND del_flag = 0 + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningTaskByShopMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningTaskByShopMapper.xml new file mode 100644 index 0000000..9499516 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningTaskByShopMapper.xml @@ -0,0 +1,729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + delete from `${tableName}` + + + AND success_data ->> '$.totalPrice' >= #{priceDown} + + + AND success_data ->> '$.totalPrice' <= #{priceUp} + + + AND success_data ->> '$.finishTime' >= #{startDate} + + + AND success_data ->> '$.finishTime' <= #{endDate} + + + AND success_data ->> '$.isOnSale' = #{isOnSale} + + + AND isbn = #{isbn} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CREATE TABLE `${tableName}` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键', + `task_id` bigint DEFAULT NULL COMMENT '任务id', + `task_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '任务名称', + `priority` int DEFAULT NULL COMMENT '优先级', + `data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '内容json字符串', + `status` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '状态 0 待执行 1已查询 2已发送 3 执行完成 4 失败 5暂停 6 删除', + `call_back_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '任务执行完返回的数据', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `goods_id` bigint DEFAULT NULL COMMENT '三方平台id', + `shop_id` bigint NOT NULL COMMENT '店铺id', + `random_num` bigint DEFAULT NULL COMMENT '随机数', + `shop_md5_prefix` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci GENERATED ALWAYS AS (upper(substr(md5(`shop_id`),1,1))) STORED NOT NULL COMMENT 'shop_id的MD5首字母', + `task_type` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '任务类型', + `success_data` text COLLATE utf8mb4_general_ci COMMENT '任务成功上传数据', + `isbn` VARCHAR(17) GENERATED ALWAYS AS (SUBSTRING_INDEX(SUBSTRING_INDEX(success_data, '"isbn":"', -1), '"', 1)) STORED COMMENT '从success_data中提取的ISBN号', + -- 新增 goods_code 虚拟列 + `goods_code` VARCHAR(100) GENERATED ALWAYS AS ( + CASE + WHEN JSON_VALID(success_data) THEN + JSON_UNQUOTE(JSON_EXTRACT(success_data, '$.goodsCode')) + ELSE NULL + END + ) STORED COMMENT '从success_data中提取的商品编码', + -- 新增 sku_code 虚拟列 + `sku_code` VARCHAR(100) GENERATED ALWAYS AS ( + CASE + WHEN JSON_VALID(success_data) THEN + JSON_UNQUOTE(JSON_EXTRACT(success_data, '$.skuCode')) + ELSE NULL + END + ) STORED COMMENT '从success_data中提取的SKU编码', + + PRIMARY KEY (`id`,`shop_md5_prefix`) USING BTREE, + KEY `index_status` (`status`) USING BTREE, + KEY `index_task_id` (`task_id`), + KEY `index_task_goods_shop_id` (`task_id`,`shop_id`,`goods_id`) USING BTREE, + KEY `index_goods_id` (`goods_id`) USING BTREE, + KEY `idx_isbn` (`isbn`) COMMENT 'ISBN索引', + -- 新增 goods_code 索引 + KEY `idx_goods_code` (`goods_code`) COMMENT '商品编码索引', + -- 新增 sku_code 索引 + KEY `idx_sku_code` (`sku_code`) COMMENT 'SKU编码索引' + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='执行的任务(按shop_id的MD5首字母分区)' + PARTITION BY LIST COLUMNS(shop_md5_prefix) + (PARTITION p0 VALUES IN ('0') ENGINE = InnoDB, + PARTITION p1 VALUES IN ('1') ENGINE = InnoDB, + PARTITION p2 VALUES IN ('2') ENGINE = InnoDB, + PARTITION p3 VALUES IN ('3') ENGINE = InnoDB, + PARTITION p4 VALUES IN ('4') ENGINE = InnoDB, + PARTITION p5 VALUES IN ('5') ENGINE = InnoDB, + PARTITION p6 VALUES IN ('6') ENGINE = InnoDB, + PARTITION p7 VALUES IN ('7') ENGINE = InnoDB, + PARTITION p8 VALUES IN ('8') ENGINE = InnoDB, + PARTITION p9 VALUES IN ('9') ENGINE = InnoDB, + PARTITION pA VALUES IN ('A') ENGINE = InnoDB, + PARTITION pB VALUES IN ('B') ENGINE = InnoDB, + PARTITION pC VALUES IN ('C') ENGINE = InnoDB, + PARTITION pD VALUES IN ('D') ENGINE = InnoDB, + PARTITION pE VALUES IN ('E') ENGINE = InnoDB, + PARTITION pF VALUES IN ('F') ENGINE = InnoDB) + + + + + INSERT INTO `${tableName}` ( + task_id, task_name, priority, data, status, + call_back_data, create_time, goods_id, shop_id, + random_num, task_type, success_data + ) VALUES ( + #{task.taskId}, #{task.taskName}, #{task.priority}, #{task.data}, #{task.status}, + #{task.callBackData}, #{task.createTime}, #{task.goodsId}, #{task.shopId}, + #{task.randomNum}, #{task.taskType}, #{task.successData} + ) + + + + + UPDATE `${tableName}` + + + task_id = #{task.taskId}, + + + task_name = #{task.taskName}, + + + priority = #{task.priority}, + + + data = #{task.data}, + + + status = #{task.status}, + + + call_back_data = #{task.callBackData}, + + + create_time = #{task.createTime}, + + + goods_id = #{task.goodsId}, + + + shop_id = #{task.shopId}, + + + random_num = #{task.randomNum}, + + + task_type = #{task.taskType}, + + + success_data = #{task.successData}, + + + WHERE id = #{task.id} + + + + INSERT INTO `${tableName}` ( + task_id, + shop_id, + goods_id, + random_num, + task_name, + priority, + data, + status, + call_back_data, + task_type, + success_data, + create_time + ) VALUES + + ( + #{item.taskId}, + #{item.shopId}, + #{item.goodsId}, + #{item.randomNum}, + #{item.taskName}, + #{item.priority}, + #{item.data}, + #{item.status}, + #{item.callBackData}, + #{item.taskType}, + #{item.successData}, + now() + ) + + + + + update `${tableName}` set status = '3' + + + + delete from `${tableName}` + + + + delete from `${tableName}` where status = #{status} + + + + delete from `${tableName}` where task_id != #{taskId} + + + + + + delete + from `${tableName}` + where goods_id = #{goodsId} + + + + + + + + + + + + + + UPDATE + `${tableName}` + SET + success_data = #{successDataJsonStr} + WHERE + id = #{id} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopDepotMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopDepotMapper.xml new file mode 100644 index 0000000..1d9bc00 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopDepotMapper.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + select id, shop_id, depot_id, create_time, update_time + from t_shop_depot_aotu + + + + + + delete from t_shop_depot_aotu where shop_id = #{shopId} + + + + insert into t_shop_depot_aotu + + shop_id, + depot_id, + create_time, + update_time, + + + #{shopId}, + #{depotId}, + #{createTime}, + #{updateTime}, + + + + + INSERT INTO t_shop_depot_aotu (id, shop_id, depot_id, create_time, update_time) + VALUES + + (#{item.id}, #{item.shopId}, #{item.depotId}, #{item.createTime}, #{item.updateTime}) + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsMapper.xml new file mode 100644 index 0000000..a054bd7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsMapper.xml @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id, trilateral_id, img, finish_time, total_price, isbn, title, quality, + goods_code, shop_type, stock, is_on_sale, sku_code, sku_id, shop_id + + + + + + + + CREATE TABLE IF NOT EXISTS `${tableName}` ( + `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `trilateral_id` VARCHAR(100) DEFAULT NULL COMMENT '商品id', + `img` VARCHAR(3000) DEFAULT NULL COMMENT '图片地址', + `finish_time` VARCHAR(50) DEFAULT NULL COMMENT '创建时间', + `total_price` VARCHAR(20) DEFAULT NULL COMMENT '价格 单位分', + `isbn` VARCHAR(20) DEFAULT NULL COMMENT 'ISBN号', + `title` VARCHAR(500) DEFAULT NULL COMMENT '标题', + `quality` VARCHAR(10) DEFAULT NULL COMMENT '品相 八五品就是85 全新就是100', + `goods_code` VARCHAR(100) DEFAULT NULL COMMENT '商品编码', + `shop_type` VARCHAR(10) DEFAULT NULL COMMENT '店铺类型 1拼多多 2孔夫子 5闲鱼', + `stock` VARCHAR(20) DEFAULT NULL COMMENT '库存', + `is_on_sale` VARCHAR(5) DEFAULT NULL COMMENT '上下架状态 1上架 0下架', + `sku_code` VARCHAR(100) DEFAULT NULL COMMENT 'sku编号', + `sku_id` VARCHAR(100) DEFAULT NULL COMMENT 'skuId', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_trilateral_id` (`trilateral_id`), + KEY `idx_isbn` (`isbn`), + KEY `idx_goods_code` (`goods_code`), + KEY `idx_sku_code` (`sku_code`), + KEY `idx_is_on_sale` (`is_on_sale`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='商品信息表' + + + + + INSERT INTO `${tableName}` ( + trilateral_id, img, finish_time, total_price, isbn, title, + quality, goods_code, shop_type, stock, is_on_sale, sku_code, sku_id, shop_id + ) VALUES ( + #{trilateralId}, #{img}, #{finishTime}, #{totalPrice}, #{isbn}, #{title}, + #{quality}, #{goodsCode}, #{shopType}, #{stock}, #{isOnSale}, #{skuCode}, #{skuId}, #{shopId} + ) + + + + + INSERT INTO `${tableName}` ( + trilateral_id, img, finish_time, total_price, isbn, title, + quality, goods_code, shop_type, stock, is_on_sale, sku_code, sku_id + ) VALUES + + ( + #{item.trilateralId}, #{item.img}, #{item.finishTime}, #{item.totalPrice}, #{item.isbn}, #{item.title}, + #{item.quality}, #{item.goodsCode}, #{item.shopType}, #{item.stock}, #{item.isOnSale}, + #{item.skuCode}, #{item.skuId} + ) + + + + + + DELETE FROM `${tableName}` WHERE id = #{id} + + + + + DELETE FROM `${tableName}` + + + AND trilateral_id = #{trilateralId} + + + AND isbn = #{isbn} + + + AND shop_id = #{shopId} + + + AND is_on_sale = #{isOnSale} + + + + + + + UPDATE `${tableName}` + + + trilateral_id = #{trilateralId}, + + + img = #{img}, + + + finish_time = #{finishTime}, + + + total_price = #{totalPrice}, + + + isbn = #{isbn}, + + + title = #{title}, + + + quality = #{quality}, + + + goods_code = #{goodsCode}, + + + shop_type = #{shopType}, + + + stock = #{stock}, + + + is_on_sale = #{isOnSale}, + + + sku_code = #{skuCode}, + + + sku_id = #{skuId}, + + + WHERE id = #{id} + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM `${tableName}` + WHERE id IN + + #{id} + + + + + + + + + UPDATE `${tableName}` + SET is_on_sale = #{isOnSale} + WHERE trilateral_id = #{trilateralId} + + + + + UPDATE `${tableName}` + SET is_on_sale = #{isOnSale} + WHERE trilateral_id IN + + #{trilateralId} + + + + + + + + + + + + DELETE FROM `${tableName}` + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopMapper.xml new file mode 100644 index 0000000..fe4feea --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopMapper.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + update t_shop set sku_spec = #{skuSpec} where id = #{id} + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopWarehouseAutoMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopWarehouseAutoMapper.xml new file mode 100644 index 0000000..8687eb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopWarehouseAutoMapper.xml @@ -0,0 +1,77 @@ + + + + + + + select id, shop_id,shop_name,shop_type, user_id,warehouse_id + from shop_warehouse_auto + + + + + DELETE FROM shop_warehouse_auto + WHERE shop_id = #{shopId} + + + + + DELETE FROM shop_warehouse_auto + WHERE id = #{id} + + + + + INSERT INTO shop_warehouse_auto + (shop_id,shop_name,shop_type, user_id,warehouse_id) + VALUES + (#{shopId},#{shopName},#{shopType}, #{userId}, #{warehouseId}) + + + + + + + + + + + + + + + + UPDATE shop_warehouse_auto + + shop_id = #{shopId}, + shop_name = #{shopName}, + shop_type = #{shopType}, + user_id = #{userId}, + warehouse_id = #{warehouseId}, + + WHERE id = #{id} + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/SpecMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/SpecMapper.xml new file mode 100644 index 0000000..7781528 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/SpecMapper.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/StockChangeLogMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/StockChangeLogMapper.xml new file mode 100644 index 0000000..a2418db --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/StockChangeLogMapper.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/SyncLogMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/SyncLogMapper.xml new file mode 100644 index 0000000..3e8e90c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/SyncLogMapper.xml @@ -0,0 +1,69 @@ + + + + + + + select id, user_id, type, create_by, msg + from sync_log + + + + + + + + + + + INSERT INTO sync_log + (user_id, type, create_by, msg) + VALUES + (#{userId}, #{type}, #{createBy}, #{msg}) + + + + + UPDATE sync_log + + user_id = #{userId}, + type = #{type}, + create_by = #{createBy}, + msg = #{msg}, + + WHERE id = #{id} + + + + + DELETE FROM sync_log + WHERE id = #{id} + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TDepotMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TDepotMapper.xml new file mode 100644 index 0000000..6ee787c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TDepotMapper.xml @@ -0,0 +1,309 @@ + + + + + INSERT INTO t_freight(shelves_id,code) VALUES + + (#{s},#{number}) + + + + + + INSERT INTO t_shelves (depot_id,she_cap_max,code) VALUES + + (#{id},#{sheQuantityMax},#{number}) + + + + INSERT INTO t_isbn_con(old_isbn, new_isbn, create_time, update_time) + VALUES (#{isbn}, #{newisbn}, now(), now()); + + + + + DELETE FROM t_shelves + WHERE depot_id IN + + #{id} + + + + + DELETE FROM t_freight + WHERE shelves_id IN + + #{id} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShelvesMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShelvesMapper.xml new file mode 100644 index 0000000..2466601 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShelvesMapper.xml @@ -0,0 +1,198 @@ + + + + + + + insert into t_shelves(name,she_cap_max,unit,code,depot_id,tenant_id) values(#{name},#{sheCapMax},#{unit},#{code},#{depotId},#{tenantId}) + + + INSERT INTO t_freight(shelves_id,code) VALUESs + + (#{id},#{number}) + + + + + update t_shelves set depot_id=#{depotId} where id=#{id} + + + + + + + update t_shelves set name=#{name},she_cap_max=#{sheCapMax},code=#{code} where id=#{id} + + + + + DELETE FROM t_freight + WHERE shelves_id IN + + #{id} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopOrderDetailMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopOrderDetailMapper.xml new file mode 100644 index 0000000..9f5b8cc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopOrderDetailMapper.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TaskPauseMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TaskPauseMapper.xml new file mode 100644 index 0000000..a4b9d71 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TaskPauseMapper.xml @@ -0,0 +1,24 @@ + + + + + + INSERT INTO t_task_pause ( + task_id, + shop_id, + create_by, + create_time + ) VALUES ( + #{taskId}, + #{shopId}, + #{createBy}, + now() + ) + + + + delete from t_task_pause where task_id = #{taskId} + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserTAuditMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserTAuditMapper.xml new file mode 100644 index 0000000..39a82ad --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserTAuditMapper.xml @@ -0,0 +1,49 @@ + + + + + update t_audit set update_time = now(),status=#{status} where user_id = #{userId} + + + delete from t_audit where id=#{auditId}; + + + delete from t_audit_info where id in + + #{id} + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ViolationMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ViolationMapper.xml new file mode 100644 index 0000000..09d48ef --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ViolationMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopGoodsMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopGoodsMapper.xml new file mode 100644 index 0000000..f3080a0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopGoodsMapper.xml @@ -0,0 +1,580 @@ + + + + + + + + + + insert into t_task_list(task_type,depot_ids,file_name,data_num,task_status,create_time,user_id) values (1, + (select CONCAT(name, unit) from t_depot where id=#{depotId} and user_id=#{userId}),#{filename},#{count},3,now(),#{userId}) + + + update t_freight set art_no = #{artNo} where code = #{thirdChar} and shelves_id= + (SELECT id from t_shelves where `code`=#{secondChar} and depot_id= + (select id from t_depot where code=#{firstChar})) + + + update zhishu_shop_goods set inventory = #{inventory} + + + user_id = #{userId} + + + and product_id = #{productId} + + + and goods_name = #{goodsName} + + + and isbn = #{isbn} + + + and price = #{price} + + + and condition_code = #{conditionCode} + + + and price= #{price} + + + and depot_id = #{depotId} + + + + + + + + update zhishu_shop_goods set inventory = #{inventory} + + user_id = #{userId} + + and product_id = #{productId} + + + and goods_name = #{goodsName} + + + and isbn = #{isbn} + + + and price = #{price} + + + and condition_code = #{conditionCode} + + + and fix_price = #{fixPrice} + + + and art_no = #{artNo} + + + + + + update zhishu_shop_goods set inventory = #{newInventory} + where user_id = #{userId} + and isbn = #{barcode} + and LEFT(art_no, 12) = LEFT(#{artNo}, 12) + and price = #{price} + and condition_code = #{letterCode} + + + //更新除了库存其他字段 + update zhishu_shop_goods + + + price = #{price}, + + + fix_price = #{fixPrice}, + + + goods_name = #{goodsName}, + + + item_number = #{itemNumber}, + + + product_id = #{productId}, + + + where id=#{id} + + + update zhishu_shop_goods set art_no = concat(#{beartNo},SUBSTRING(art_no, 6)),depot_id=#{deId} + where id in + + #{id} + + + + delete from zhishu_shop_goods where id in + + #{id} + + + + delete from zhishu_shop_goods where id in + + #{id} + + + + delete from t_shop_goods_published where shop_goods_id =#{id} + + + + + + + insert into t_book_audit(user_id, goods_name, isbn, art_no, price, condition_code,item_number, fix_price, product_id,status,create_time,update_time,tenant_id,inventory) + values (#{userId},#{goodsName},#{isbn},#{artNo},#{price},#{conditionCode},#{itemNumber},#{fixPrice},#{productId},2,now(),now(),"000000",#{inventory}) + + + insert into t_stock_change_log (id,shop_goods_id,before_inv, after_inv,create_by,create_time,update_by,update_time,type,about_id) VALUES(null,#{update.id},#{inventory},#{update.inventory},#{update.userId},now(),#{update.userId},now(),1,"0") + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + update zhishu_shop_goods + + + art_no = #{artNo}, + + + depot_id = #{depotId}, + + update_time = now() + + where id = #{id} and user_id = #{userId} + + + + + update zhishu_shop_goods + set is_join_distribution = #{isJoinDistribution} + where art_no LIKE CONCAT(#{artNoPrefix}, '%') and user_id = #{userId} and del_flag = '0' and is_join_distribution != #{isJoinDistribution} + limit #{limitNum} + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopImagesMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopImagesMapper.xml new file mode 100644 index 0000000..0d267bb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopImagesMapper.xml @@ -0,0 +1,29 @@ + + + + + + + diff --git a/script/docker/redis/conf/redis.conf b/script/docker/redis/conf/redis.conf new file mode 100644 index 0000000..72255c6 --- /dev/null +++ b/script/docker/redis/conf/redis.conf @@ -0,0 +1,28 @@ +# redis 密码 +requirepass ruoyi123 + +# key 监听器配置 +# notify-keyspace-events Ex + +# 配置持久化文件存储路径 +dir /redis/data +# 配置rdb +# 15分钟内有至少1个key被更改则进行快照 +save 900 1 +# 5分钟内有至少10个key被更改则进行快照 +save 300 10 +# 1分钟内有至少10000个key被更改则进行快照 +save 60 10000 +# 开启压缩 +rdbcompression yes +# rdb文件名 用默认的即可 +dbfilename dump.rdb + +# 开启aof +appendonly yes +# 文件名 +appendfilename "appendonly.aof" +# 持久化策略,no:不同步,everysec:每秒一次,always:总是同步,速度比较慢 +# appendfsync always +appendfsync everysec +# appendfsync no diff --git a/script/leave/leave1.json b/script/leave/leave1.json new file mode 100644 index 0000000..0cf67bc --- /dev/null +++ b/script/leave/leave1.json @@ -0,0 +1,75 @@ +{ + "flowCode" : "leave1", + "flowName" : "请假申请-普通", + "category" : "1", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "200,200|200,200", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "d5ee3ddf-3968-4379-a86f-9ceabde5faac", + "nextNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42", + "skipType" : "PASS", + "coordinate" : "220,200;310,200" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "360,200|360,200", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "dd515cdd-59f6-446f-94ca-25ca062afb42", + "nextNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf", + "skipType" : "PASS", + "coordinate" : "410,200;490,200" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf", + "nodeName" : "组长", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "540,200|540,200", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "78fa8e5b-e809-44ed-978a-41092409ebcf", + "nextNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "skipType" : "PASS", + "coordinate" : "590,200;670,200" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "nodeName" : "部门主管", + "permissionFlag" : "role:3,role:4", + "nodeRatio" : 0.000, + "coordinate" : "720,200|720,200", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "a8abf15f-b83e-428a-86cc-033555ea9bbe", + "nextNodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d", + "skipType" : "PASS", + "coordinate" : "770,200;880,200" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "8b82b7d7-8660-455e-b880-d6d22ea3eb6d", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "900,200|900,200", + "skipAnyNode" : "N", + "formCustom" : "N" + } ] +} \ No newline at end of file diff --git a/script/sql/ry_job.sql b/script/sql/ry_job.sql new file mode 100644 index 0000000..c6ec01b --- /dev/null +++ b/script/sql/ry_job.sql @@ -0,0 +1,519 @@ +SET NAMES utf8mb4; + +CREATE TABLE `sj_namespace` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `name` varchar(64) NOT NULL COMMENT '名称', + `unique_id` varchar(64) NOT NULL COMMENT '唯一id', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_name` (`name`), + UNIQUE KEY `uk_unique_id` (`unique_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='命名空间'; + +INSERT INTO `sj_namespace` VALUES (1, 'Development', 'dev', '', 0, now(), now()); +INSERT INTO `sj_namespace` VALUES (2, 'Production', 'prod', '', 0, now(), now()); + +CREATE TABLE `sj_group_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '组名称', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '组描述', + `token` varchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' COMMENT 'token', + `group_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用', + `version` int(11) NOT NULL COMMENT '版本号', + `group_partition` int(11) NOT NULL COMMENT '分区', + `id_generator_mode` tinyint(4) NOT NULL DEFAULT 1 COMMENT '唯一id生成模式 默认号段模式', + `init_scene` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否初始化场景 0:否 1:是', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='组配置'; + +INSERT INTO `sj_group_config` VALUES (1, 'dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); +INSERT INTO `sj_group_config` VALUES (2, 'prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, now(), now()); + +CREATE TABLE `sj_notify_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `notify_name` varchar(64) NOT NULL DEFAULT '' COMMENT '通知名称', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务', + `notify_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知状态 0、未启用 1、启用', + `recipient_ids` varchar(128) NOT NULL COMMENT '接收人id列表', + `notify_threshold` int(11) NOT NULL DEFAULT 0 COMMENT '通知阈值', + `notify_scene` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知场景', + `rate_limiter_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '限流状态 0、未启用 1、启用', + `rate_limiter_threshold` int(11) NOT NULL DEFAULT 0 COMMENT '每秒限流阈值', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='通知配置'; + +CREATE TABLE `sj_notify_recipient` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `recipient_name` varchar(64) NOT NULL COMMENT '接收人名称', + `notify_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook', + `notify_attribute` varchar(512) NOT NULL COMMENT '配置属性', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id` (`namespace_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='告警通知接收人'; + +CREATE TABLE `sj_retry_dead_letter_0` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_namespace_id_group_name_unique_id` (`namespace_id`, `group_name`, `unique_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='死信队列表'; + +CREATE TABLE `sj_retry_task_0` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `next_trigger_at` datetime NOT NULL COMMENT '下次触发时间', + `retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数', + `retry_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '重试状态 0、重试中 1、成功 2、最大重试次数', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_namespace_id_group_name_task_type` (`namespace_id`, `group_name`, `task_type`), + KEY `idx_namespace_id_group_name_retry_status` (`namespace_id`, `group_name`, `retry_status`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`), + UNIQUE KEY `uk_name_unique_id` (`namespace_id`, `group_name`, `unique_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务表'; + +CREATE TABLE `sj_retry_task_log` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `idempotent_id` varchar(64) NOT NULL COMMENT '幂等id', + `biz_no` varchar(64) NOT NULL DEFAULT '' COMMENT '业务编号', + `executor_name` varchar(512) NOT NULL DEFAULT '' COMMENT '执行器名称', + `args_str` text NOT NULL COMMENT '执行方法参数', + `ext_attrs` text NOT NULL COMMENT '扩展字段', + `retry_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '重试状态 0、重试中 1、成功 2、最大次数', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`), + KEY `idx_retry_status` (`retry_status`), + KEY `idx_idempotent_id` (`idempotent_id`), + KEY `idx_unique_id` (`unique_id`), + KEY `idx_biz_no` (`biz_no`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务日志基础信息表'; + +CREATE TABLE `sj_retry_task_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `unique_id` varchar(64) NOT NULL COMMENT '同组下id唯一', + `message` longtext NOT NULL COMMENT '异常信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `unique_id`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务调度日志信息记录表'; + +CREATE TABLE `sj_retry_scene_config` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `scene_name` varchar(64) NOT NULL COMMENT '场景名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `scene_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用', + `max_retry_count` int(11) NOT NULL DEFAULT 5 COMMENT '最大重试次数', + `back_off` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式', + `trigger_interval` varchar(16) NOT NULL DEFAULT '' COMMENT '间隔时长', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `deadline_request` bigint(20) unsigned NOT NULL DEFAULT 60000 COMMENT 'Deadline Request 调用链超时 单位毫秒', + `executor_timeout` int(11) unsigned NOT NULL DEFAULT 5 COMMENT '任务执行超时时间,单位秒', + `route_key` tinyint(4) NOT NULL DEFAULT 4 COMMENT '路由策略', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='场景配置'; + +CREATE TABLE `sj_server_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `host_id` varchar(64) NOT NULL COMMENT '主机id', + `host_ip` varchar(64) NOT NULL COMMENT '机器ip', + `host_port` int(16) NOT NULL COMMENT '机器端口', + `expire_at` datetime NOT NULL COMMENT '过期时间', + `node_type` tinyint(4) NOT NULL COMMENT '节点类型 1、客户端 2、是服务端', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_expire_at_node_type` (`expire_at`, `node_type`), + UNIQUE KEY `uk_host_id_host_ip` (`host_id`, `host_ip`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='服务器节点'; + +CREATE TABLE `sj_distributed_lock` +( + `name` varchar(64) NOT NULL COMMENT '锁名称', + `lock_until` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '锁定时长', + `locked_at` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '锁定时间', + `locked_by` varchar(255) NOT NULL COMMENT '锁定者', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='锁定表'; + +CREATE TABLE `sj_system_user` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `username` varchar(64) NOT NULL COMMENT '账号', + `password` varchar(128) NOT NULL COMMENT '密码', + `role` tinyint(4) NOT NULL DEFAULT 0 COMMENT '角色:1-普通用户、2-管理员', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_username` (`username`) USING BTREE +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户表'; + +-- pwd: admin +INSERT INTO `sj_system_user` VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now()); + +CREATE TABLE `sj_system_user_permission` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `system_user_id` bigint(20) NOT NULL COMMENT '系统用户id', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name_system_user_id` (`namespace_id`, `group_name`, `system_user_id`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户权限表'; + +CREATE TABLE `sj_sequence_alloc` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL DEFAULT '' COMMENT '组名称', + `max_id` bigint(20) NOT NULL DEFAULT 1 COMMENT '最大id', + `step` int(11) NOT NULL DEFAULT 100 COMMENT '步长', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 COMMENT ='号段模式序号ID分配表'; + +-- 分布式调度DDL +CREATE TABLE `sj_job` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_name` varchar(64) NOT NULL COMMENT '名称', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '参数类型 ', + `next_trigger_at` bigint(13) NOT NULL COMMENT '下次触发时间', + `job_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务状态 0、关闭、1、开启', + `task_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '任务类型 1、集群 2、广播 3、切片', + `route_key` tinyint(4) NOT NULL DEFAULT 4 COMMENT '路由策略', + `executor_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '执行器类型', + `executor_info` varchar(255) DEFAULT NULL COMMENT '执行器名称', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `block_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', + `max_retry_times` int(11) NOT NULL DEFAULT 0 COMMENT '最大重试次数', + `parallel_num` int(11) NOT NULL DEFAULT 1 COMMENT '并行数', + `retry_interval` int(11) NOT NULL DEFAULT 0 COMMENT '重试间隔(s)', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `resident` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否是常驻任务', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `owner_id` bigint(20) NULL COMMENT '负责人id', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_job_status_bucket_index` (`job_status`, `bucket_index`), + KEY `idx_create_dt` (`create_dt`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务信息'; + +INSERT INTO `sj_job` VALUES (1, 'dev', 'ruoyi_group', 'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1, '', '', 0 , now(), now()); + +CREATE TABLE `sj_job_log_message` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '任务批次id', + `task_id` bigint(20) NOT NULL COMMENT '调度任务id', + `message` longtext NOT NULL COMMENT '调度信息', + `log_num` int(11) NOT NULL DEFAULT 1 COMMENT '日志数量', + `real_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上报时间', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_id` (`task_batch_id`, `task_id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='调度日志'; + +CREATE TABLE `sj_job_task` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `task_batch_id` bigint(20) NOT NULL COMMENT '调度任务id', + `parent_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '父执行器id', + `task_status` tinyint NOT NULL DEFAULT 0 COMMENT '执行的状态 0、失败 1、成功', + `retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '重试次数', + `mr_stage` tinyint DEFAULT NULL COMMENT '动态分片所处阶段 1:map 2:reduce 3:mergeReduce', + `leaf` tinyint NOT NULL DEFAULT '1' COMMENT '叶子节点', + `task_name` varchar(255) NOT NULL DEFAULT '' COMMENT '任务名称', + `client_info` varchar(128) DEFAULT NULL COMMENT '客户端地址 clientId#ip:port', + `wf_context` text DEFAULT NULL COMMENT '工作流全局上下文', + `result_message` text NOT NULL COMMENT '执行结果', + `args_str` text DEFAULT NULL COMMENT '执行方法参数', + `args_type` tinyint NOT NULL DEFAULT 1 COMMENT '参数类型 ', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_task_batch_id_task_status` (`task_batch_id`, `task_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务实例'; + +CREATE TABLE `sj_job_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务id', + `workflow_node_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流节点id', + `parent_workflow_node_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流任务父批次id', + `workflow_task_batch_id` bigint(20) NOT NULL DEFAULT 0 COMMENT '工作流任务批次id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', + `execution_at` bigint(13) NOT NULL DEFAULT 0 COMMENT '任务执行时间', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `parent_id` varchar(64) NOT NULL DEFAULT '' COMMENT '父节点', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`job_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`), + KEY `idx_workflow_task_batch_id_workflow_node_id` (`workflow_task_batch_id`, `workflow_node_id`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='任务批次'; + +CREATE TABLE `sj_job_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `business_id` bigint NOT NULL COMMENT '业务id (job_id或workflow_id)', + `system_task_type` tinyint(4) NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `success_num` int NOT NULL DEFAULT 0 COMMENT '执行成功-日志数量', + `fail_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `fail_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `stop_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `stop_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `cancel_num` int NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `cancel_reason` varchar(512) NOT NULL DEFAULT '' COMMENT '失败原因', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_namespace_id_group_name_business_id` (`namespace_id`, `group_name`, business_id), + UNIQUE KEY `uk_trigger_at_system_task_type_business_id` (`trigger_at`, `system_task_type`, `business_id`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Job'; + +CREATE TABLE `sj_retry_summary` +( + `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称', + `scene_name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '场景名称', + `trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间', + `running_num` int NOT NULL DEFAULT 0 COMMENT '重试中-日志数量', + `finish_num` int NOT NULL DEFAULT 0 COMMENT '重试完成-日志数量', + `max_count_num` int NOT NULL DEFAULT 0 COMMENT '重试到达最大次数-日志数量', + `suspend_num` int NOT NULL DEFAULT 0 COMMENT '暂停重试-日志数量', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_trigger_at` (`trigger_at`), + UNIQUE KEY `uk_scene_name_trigger_at` (`namespace_id`, `group_name`, `scene_name`, `trigger_at`) USING BTREE +) ENGINE = InnoDB + AUTO_INCREMENT = 1 + DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Retry'; + +CREATE TABLE `sj_workflow` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `workflow_name` varchar(64) NOT NULL COMMENT '工作流名称', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '工作流状态 0、关闭、1、开启', + `trigger_type` tinyint(4) NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间', + `trigger_interval` varchar(255) NOT NULL COMMENT '间隔时长', + `next_trigger_at` bigint(13) NOT NULL COMMENT '下次触发时间', + `block_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行', + `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', + `description` varchar(256) NOT NULL DEFAULT '' COMMENT '描述', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '上下文', + `notify_ids` varchar(128) NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表', + `bucket_index` int(11) NOT NULL DEFAULT 0 COMMENT 'bucket', + `version` int(11) NOT NULL COMMENT '版本号', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流'; + +CREATE TABLE `sj_workflow_node` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `node_name` varchar(64) NOT NULL COMMENT '节点名称', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `job_id` bigint(20) NOT NULL COMMENT '任务信息id', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流ID', + `node_type` tinyint(4) NOT NULL DEFAULT 1 COMMENT '1、任务节点 2、条件节点', + `expression_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '1、SpEl、2、Aviator 3、QL', + `fail_strategy` tinyint(4) NOT NULL DEFAULT 1 COMMENT '失败策略 1、跳过 2、阻塞', + `workflow_node_status` tinyint(4) NOT NULL DEFAULT 1 COMMENT '工作流节点状态 0、关闭、1、开启', + `priority_level` int(11) NOT NULL DEFAULT 1 COMMENT '优先级', + `node_info` text DEFAULT NULL COMMENT '节点信息 ', + `version` int(11) NOT NULL COMMENT '版本号', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流节点'; + +CREATE TABLE `sj_workflow_task_batch` +( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `namespace_id` varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id', + `group_name` varchar(64) NOT NULL COMMENT '组名称', + `workflow_id` bigint(20) NOT NULL COMMENT '工作流任务id', + `task_batch_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功', + `operation_reason` tinyint(4) NOT NULL DEFAULT 0 COMMENT '操作原因', + `flow_info` text DEFAULT NULL COMMENT '流程信息', + `wf_context` text DEFAULT NULL COMMENT '全局上下文', + `execution_at` bigint(13) NOT NULL DEFAULT 0 COMMENT '任务执行时间', + `ext_attrs` varchar(256) NULL DEFAULT '' COMMENT '扩展字段', + `version` int(11) NOT NULL DEFAULT 1 COMMENT '版本号', + `deleted` tinyint(4) NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`), + KEY `idx_job_id_task_batch_status` (`workflow_id`, `task_batch_status`), + KEY `idx_create_dt` (`create_dt`), + KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`) +) ENGINE = InnoDB + AUTO_INCREMENT = 0 + DEFAULT CHARSET = utf8mb4 COMMENT ='工作流批次'; diff --git a/script/sql/sqlserver/sqlserver_ry_job.sql b/script/sql/sqlserver/sqlserver_ry_job.sql new file mode 100644 index 0000000..97addc3 --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_job.sql @@ -0,0 +1,2778 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : Microsoft SQL Server + Date: 2024-12-27 22:24:37 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + name nvarchar(64) NOT NULL, + unique_id nvarchar(64) NOT NULL, + description nvarchar(256) NOT NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_namespace' +GO + +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Development', N'dev', N'', 0, getdate(), getdate()) +GO +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES (N'Production', N'prod', N'', 0, getdate(), getdate()) +GO + +-- sj_group_config +CREATE TABLE sj_group_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + description nvarchar(256) NOT NULL DEFAULT '', + token nvarchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status tinyint NOT NULL DEFAULT 0, + version int NOT NULL, + group_partition int NOT NULL, + id_generator_mode tinyint NOT NULL DEFAULT 1, + init_scene tinyint NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'token', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'token' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'分区', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'group_partition' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'唯一id生成模式 默认号段模式', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'id_generator_mode' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否初始化场景 0:否 1:是', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'init_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_group_config' +GO + +INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate()) +GO +INSERT INTO sj_group_config(namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, bucket_index, create_dt, update_dt) VALUES (N'prod', N'ruoyi_group', N'', N'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', N'1', N'1', N'0', N'1', N'1', N'4', getdate(), getdate()) +GO + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + notify_name nvarchar(64) NOT NULL DEFAULT '', + system_task_type tinyint NOT NULL DEFAULT 3, + notify_status tinyint NOT NULL DEFAULT 0, + recipient_ids nvarchar(128) NOT NULL, + notify_threshold int NOT NULL DEFAULT 0, + notify_scene tinyint NOT NULL DEFAULT 0, + rate_limiter_status tinyint NOT NULL DEFAULT 0, + rate_limiter_threshold int NOT NULL DEFAULT 0, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收人id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'recipient_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知场景', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'notify_scene' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'限流状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'rate_limiter_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'每秒限流阈值', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'rate_limiter_threshold' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_config' +GO + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + recipient_name nvarchar(64) NOT NULL, + notify_type tinyint NOT NULL DEFAULT 0, + notify_attribute nvarchar(512) NOT NULL, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'接收人名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'recipient_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'notify_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'配置属性', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'notify_attribute' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'告警通知接收人', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_notify_recipient' +GO + +-- sj_retry_dead_letter_0 +CREATE TABLE sj_retry_dead_letter_0 +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + task_type tinyint NOT NULL DEFAULT 1, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id) +GO + +CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id) +GO +CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no) +GO +CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'死信队列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_dead_letter_0' +GO + +-- sj_retry_task_0 +CREATE TABLE sj_retry_task_0 +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + next_trigger_at datetime2 NOT NULL, + retry_count int NOT NULL DEFAULT 0, + retry_status tinyint NOT NULL DEFAULT 0, + task_type tinyint NOT NULL DEFAULT 1, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id) +GO + +CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type) +GO +CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status) +GO +CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id) +GO +CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no) +GO +CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态 0、重试中 1、成功 2、最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'retry_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_0' +GO + +-- sj_retry_task_log +CREATE TABLE sj_retry_task_log +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_name nvarchar(64) NOT NULL, + idempotent_id nvarchar(64) NOT NULL, + biz_no nvarchar(64) NOT NULL DEFAULT '', + executor_name nvarchar(512) NOT NULL DEFAULT '', + args_str nvarchar(max) NOT NULL, + ext_attrs nvarchar(max) NOT NULL, + retry_status tinyint NOT NULL DEFAULT 0, + task_type tinyint NOT NULL DEFAULT 1, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name) +GO +CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status) +GO +CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id) +GO +CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id) +GO +CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no) +GO +CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'幂等id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'idempotent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务编号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'biz_no' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'executor_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试状态 0、重试中 1、成功 2、最大次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'retry_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、重试数据 2、回调数据', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务日志基础信息表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log' +GO + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + unique_id nvarchar(64) NOT NULL, + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id) +GO +CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'同组下id唯一', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'unique_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'异常信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务调度日志信息记录表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_task_log_message' +GO + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + scene_status tinyint NOT NULL DEFAULT 0, + max_retry_count int NOT NULL DEFAULT 5, + back_off tinyint NOT NULL DEFAULT 1, + trigger_interval nvarchar(16) NOT NULL DEFAULT '', + notify_ids nvarchar(128) NOT NULL DEFAULT '', + deadline_request bigint NOT NULL DEFAULT 60000, + executor_timeout int NOT NULL DEFAULT 5, + route_key tinyint NOT NULL DEFAULT 4, + description nvarchar(256) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组状态 0、未启用 1、启用', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'scene_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'max_retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、默认等级 2、固定间隔时间 3、CRON 表达式', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'back_off' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'Deadline Request 调用链超时 单位毫秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'deadline_request' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景配置', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_scene_config' +GO + +-- sj_server_node +CREATE TABLE sj_server_node +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + host_id nvarchar(64) NOT NULL, + host_ip nvarchar(64) NOT NULL, + host_port int NOT NULL, + expire_at datetime2 NOT NULL, + node_type tinyint NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip) +GO + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name) +GO +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主机id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器ip', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_ip' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'机器端口', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'host_port' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'过期时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'expire_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点类型 1、客户端 2、是服务端', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'服务器节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_server_node' +GO + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name nvarchar(64) NOT NULL PRIMARY KEY, + lock_until datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_by nvarchar(255) NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'lock_until' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'locked_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定者', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'locked_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'锁定表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_distributed_lock' +GO + +-- sj_system_user +CREATE TABLE sj_system_user +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + username nvarchar(64) NOT NULL, + password nvarchar(128) NOT NULL, + role tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'账号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'username' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'密码', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'password' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'角色:1-普通用户、2-管理员', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'role' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user' +GO + +-- pwd: admin +INSERT INTO sj_system_user(username, password, role, create_dt, update_dt) VALUES (N'admin', N'465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', N'2', getdate(), getdate()) +GO + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + group_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + system_user_id bigint NOT NULL, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'system_user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'系统用户权限表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_system_user_permission' +GO + +-- sj_sequence_alloc +CREATE TABLE sj_sequence_alloc +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + max_id bigint NOT NULL DEFAULT 1, + step int NOT NULL DEFAULT 100, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'max_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'步长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'step' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'号段模式序号ID分配表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_sequence_alloc' +GO + +-- sj_job +CREATE TABLE sj_job +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_name nvarchar(64) NOT NULL, + args_str nvarchar(max) NULL DEFAULT NULL, + args_type tinyint NOT NULL DEFAULT 1, + next_trigger_at bigint NOT NULL, + job_status tinyint NOT NULL DEFAULT 1, + task_type tinyint NOT NULL DEFAULT 1, + route_key tinyint NOT NULL DEFAULT 4, + executor_type tinyint NOT NULL DEFAULT 1, + executor_info nvarchar(255) NULL DEFAULT NULL, + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + block_strategy tinyint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + max_retry_times int NOT NULL DEFAULT 0, + parallel_num int NOT NULL DEFAULT 1, + retry_interval int NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + resident tinyint NOT NULL DEFAULT 0, + notify_ids nvarchar(128) NOT NULL DEFAULT '', + owner_id bigint NULL, + description nvarchar(256) NOT NULL DEFAULT '', + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name) +GO +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index) +GO +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'job_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'job_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 1、集群 2、广播 3、切片', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'路由策略', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'route_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行器名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'最大重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'max_retry_times' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'并行数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'parallel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试间隔 ( s ) ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'retry_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'是否是常驻任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'resident' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'负责人id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'owner_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job' +GO + +INSERT INTO sj_job (namespace_id, group_name, job_name, args_str, args_type, next_trigger_at, job_status, task_type, route_key, executor_type, executor_info, trigger_type, trigger_interval, block_strategy,executor_timeout, max_retry_times, parallel_num, retry_interval, bucket_index, resident, notify_ids, owner_id, description, ext_attrs, deleted, create_dt, update_dt) VALUES (N'dev', N'ruoyi_group', N'demo-job', null, 1, 1710344035622, 1, 1, 4, 1, N'testJobExecutor', 2, N'60', 1, 60, 3, 1, 1, 116, 0, N'', 1, N'', N'', 0, getdate(), getdate()) +GO + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + task_id bigint NOT NULL, + message nvarchar(max) NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id) +GO +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt) +GO +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'task_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'log_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上报时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'real_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度日志', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_log_message' +GO + +-- sj_job_task +CREATE TABLE sj_job_task +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + parent_id bigint NOT NULL DEFAULT 0, + task_status tinyint NOT NULL DEFAULT 0, + retry_count int NOT NULL DEFAULT 0, + mr_stage tinyint NULL DEFAULT NULL, + leaf tinyint NOT NULL DEFAULT '1', + task_name nvarchar(255) NOT NULL DEFAULT '', + client_info nvarchar(128) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + result_message nvarchar(max) NOT NULL, + args_str nvarchar(max) NULL DEFAULT NULL, + args_type tinyint NOT NULL DEFAULT 1, + ext_attrs nvarchar(256) NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status) +GO +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt) +GO +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'调度任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父执行器id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行的状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试次数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'retry_count' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'动态分片所处阶段 1:map 2:reduce 3:mergeReduce', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'mr_stage' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'叶子节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'leaf' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'task_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端地址 clientId#ip:port', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'client_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流全局上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行结果', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'result_message' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行方法参数', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'args_str' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'参数类型 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'args_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务实例', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task' +GO + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_node_id bigint NOT NULL DEFAULT 0, + parent_workflow_node_id bigint NOT NULL DEFAULT 0, + workflow_task_batch_id bigint NOT NULL DEFAULT 0, + task_batch_status tinyint NOT NULL DEFAULT 0, + operation_reason tinyint NOT NULL DEFAULT 0, + execution_at bigint NOT NULL DEFAULT 0, + system_task_type tinyint NOT NULL DEFAULT 3, + parent_id nvarchar(64) NOT NULL DEFAULT '', + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status) +GO +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt) +GO +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name) +GO +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务父批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'parent_workflow_node_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务批次id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'workflow_task_batch_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_task_batch' +GO + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + business_id bigint NOT NULL, + system_task_type tinyint NOT NULL DEFAULT 3, + trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + success_num int NOT NULL DEFAULT 0, + fail_num int NOT NULL DEFAULT 0, + fail_reason nvarchar(512) NOT NULL DEFAULT '', + stop_num int NOT NULL DEFAULT 0, + stop_reason nvarchar(512) NOT NULL DEFAULT '', + cancel_num int NOT NULL DEFAULT 0, + cancel_reason nvarchar(512) NOT NULL DEFAULT '', + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id) +GO + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'业务id ( job_id或workflow_id ) ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'business_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务类型 3、JOB任务 4、WORKFLOW任务', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'system_task_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行成功-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'success_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'fail_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'fail_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'stop_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'stop_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'执行失败-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'cancel_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'cancel_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Job', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_job_summary' +GO + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL DEFAULT '', + scene_name nvarchar(50) NOT NULL DEFAULT '', + trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + running_num int NOT NULL DEFAULT 0, + finish_num int NOT NULL DEFAULT 0, + max_count_num int NOT NULL DEFAULT 0, + suspend_num int NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at) +GO + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'场景名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'scene_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'统计时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试中-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'running_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试完成-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'finish_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'重试到达最大次数-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'max_count_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'暂停重试-日志数量', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'suspend_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'DashBoard_Retry', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_retry_summary' +GO + +-- sj_workflow +CREATE TABLE sj_workflow +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + workflow_name nvarchar(64) NOT NULL, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + workflow_status tinyint NOT NULL DEFAULT 1, + trigger_type tinyint NOT NULL, + trigger_interval nvarchar(255) NOT NULL, + next_trigger_at bigint NOT NULL, + block_strategy tinyint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + description nvarchar(256) NOT NULL DEFAULT '', + flow_info nvarchar(max) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + notify_ids nvarchar(128) NOT NULL DEFAULT '', + bucket_index int NOT NULL DEFAULT 0, + version int NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt) +GO +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'workflow_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'workflow_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'触发类型 1.CRON 表达式 2. 固定时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'trigger_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'间隔时长', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'trigger_interval' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'下次触发时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'next_trigger_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'阻塞策略 1、丢弃 2、覆盖 3、并行', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'block_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行超时时间,单位秒', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'executor_timeout' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'描述', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'description' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'通知告警场景配置id列表', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'notify_ids' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'bucket', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'bucket_index' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow' +GO + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name nvarchar(64) NOT NULL, + group_name nvarchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_id bigint NOT NULL, + node_type tinyint NOT NULL DEFAULT 1, + expression_type tinyint NOT NULL DEFAULT 0, + fail_strategy tinyint NOT NULL DEFAULT 1, + workflow_node_status tinyint NOT NULL DEFAULT 1, + priority_level int NOT NULL DEFAULT 1, + node_info nvarchar(max) NULL DEFAULT NULL, + version int NOT NULL, + ext_attrs nvarchar(256) NULL DEFAULT '', + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt) +GO +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务信息id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'job_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流ID', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、任务节点 2、条件节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'1、SpEl、2、Aviator 3、QL', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'expression_type' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'失败策略 1、跳过 2、阻塞', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'fail_strategy' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点状态 0、关闭、1、开启', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'workflow_node_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'优先级', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'priority_level' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'节点信息 ', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'node_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流节点', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_node' +GO + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id bigint NOT NULL PRIMARY KEY IDENTITY, + namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name nvarchar(64) NOT NULL, + workflow_id bigint NOT NULL, + task_batch_status tinyint NOT NULL DEFAULT 0, + operation_reason tinyint NOT NULL DEFAULT 0, + flow_info nvarchar(max) NULL DEFAULT NULL, + wf_context nvarchar(max) NULL DEFAULT NULL, + execution_at bigint NOT NULL DEFAULT 0, + ext_attrs nvarchar(256) NULL DEFAULT '', + version int NOT NULL DEFAULT 1, + deleted tinyint NOT NULL DEFAULT 0, + create_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP +) +GO + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status) +GO +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt) +GO +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name) +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'命名空间id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'namespace_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'组名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'group_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流任务id', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'workflow_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务批次状态 0、失败 1、成功', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'task_batch_status' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'操作原因', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'operation_reason' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'流程信息', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'flow_info' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'全局上下文', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'wf_context' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'任务执行时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'execution_at' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'ext_attrs' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本号', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'逻辑删除 1、删除', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'deleted' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'create_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'修改时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch', + 'COLUMN', N'update_dt' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'工作流批次', + 'SCHEMA', N'dbo', + 'TABLE', N'sj_workflow_task_batch' +GO diff --git a/script/sql/update/oracle/update_5.1.1-5.1.2.sql b/script/sql/update/oracle/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..d7c030c --- /dev/null +++ b/script/sql/update/oracle/update_5.1.1-5.1.2.sql @@ -0,0 +1,6 @@ +delete from sys_menu where menu_id in (1604, 1605); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', 1, 0, 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, sysdate, null, null, ''); + diff --git a/script/sql/update/oracle/update_5.1.2-5.2.0.sql b/script/sql/update/oracle/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..1aa585a --- /dev/null +++ b/script/sql/update/oracle/update_5.1.2-5.2.0.sql @@ -0,0 +1,9 @@ +ALTER TABLE sys_dept ADD (dept_category varchar2(100) DEFAULT NULL) COMMENT '部门类别编码'; +COMMENT ON COLUMN sys_dept.dept_category IS '部门类别编码'; +ALTER TABLE sys_post ADD (dept_id number(20) NOT NULL) COMMENT '部门id'; +COMMENT ON COLUMN sys_post.dept_id IS '部门id'; +ALTER TABLE sys_post ADD (post_category VARCHAR2(100) DEFAULT NULL) COMMENT '岗位类别编码'; +COMMENT ON COLUMN sys_post.post_category IS '岗位类别编码'; +UPDATE sys_post SET dept_id = 100; +UPDATE sys_post SET dept_id = 103 where post_id = 1; +UPDATE sys_menu SET menu_name = 'SnailJob控制台', path = 'snailjob', component = 'monitor/snailjob/index', perms = 'monitor:snailjob:list', remark = 'SnailJob控制台菜单' WHERE menu_id = 120; diff --git a/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql b/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..2238536 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.1.0-5.1.1.sql @@ -0,0 +1,19 @@ +ALTER TABLE sys_logininfor ADD client_key nvarchar(32) DEFAULT '' NULL +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'客户端', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'client_key' +GO + +ALTER TABLE sys_logininfor ADD device_type nvarchar(32) DEFAULT '' NULL +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'设备类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'device_type' +GO diff --git a/stockSynchronize/stock_sync_log_2025-11-28.txt b/stockSynchronize/stock_sync_log_2025-11-28.txt new file mode 100644 index 0000000..7cfc180 --- /dev/null +++ b/stockSynchronize/stock_sync_log_2025-11-28.txt @@ -0,0 +1,9 @@ +=== Method Parameter Log === +Time: 2025-11-28 15:49:19 +Method: stockSynchronize +Parameters: + Parameter 1: {"taskType":"STOCK_SYNCHRONIZE","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1990614835765604353","imageSelect":"1","deleteNum":0,"synchronizationType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}]} + Parameter 2: {"params":{},"id":1994312636073259010,"taskType":"STOCK_SYNCHRONIZE","shopIds":"1990614835765604353","shopNames":"志诚纸品店","fileName":"手动库存同步任务","dataNum":0,"taskStatus":"0"} + Parameter 3: 1916358871501082626 +============================= + diff --git a/stockSynchronize/stock_sync_log_2026-05-19.txt b/stockSynchronize/stock_sync_log_2026-05-19.txt new file mode 100644 index 0000000..64b2aa9 --- /dev/null +++ b/stockSynchronize/stock_sync_log_2026-05-19.txt @@ -0,0 +1,9 @@ +=== Method Parameter Log === +Time: 2026-05-19 16:20:19 +Method: stockSynchronize +Parameters: + Parameter 1: {"taskType":"STOCK_SYNCHRONIZE","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"imageSelect":"1","deleteNum":0,"shopIds":"2054805126617468929","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"} + Parameter 2: {"params":{},"id":2056651133513375745,"taskType":"STOCK_SYNCHRONIZE","shopIds":"2054805126617468929","shopNames":"亦欧家居店","fileName":"excel表格更新:","dataNum":0,"taskStatus":"0"} + Parameter 3: 1965254774327533570 +============================= +