commit 35fa3721c5f15608b11998feef90f87281386bed Author: 凌尛 <1254210241@qq.com> Date: Mon Jun 15 13:48:57 2026 +0800 初版提交 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2ef2c59 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# erp \ No newline at end of file diff --git a/file/log/centerBooksAdd_1916358871501082626_1.txt b/file/log/centerBooksAdd_1916358871501082626_1.txt new file mode 100644 index 0000000..c6dc975 --- /dev/null +++ b/file/log/centerBooksAdd_1916358871501082626_1.txt @@ -0,0 +1,351 @@ + +【2026-01-20 13:32:33】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-01-20 13:32:33】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2013484773489025025","taskType":"1","shopIds":"2006557053525397505","shopNames":"志诚纸品店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d301edd6-9de7-4b05-bf04-6cb671aa1b7c_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006557053525397505","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-01-20 13:39:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-01-20 13:39:40】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2013486565350219777","taskType":"1","shopIds":"2006557053525397505","shopNames":"志诚纸品店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/1fb39e22-29d5-49a3-9092-27234b2dc7e0_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006557053525397505","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"} +【2026-01-26 16:17:46】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-01-26 16:17:46】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2015700678402940929","taskType":"1","shopIds":"1995373681100910593","shopNames":"志诚图书店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":100,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":100,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/43d1e842-2645-4418-9af7-0a5239d3655a_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-01-26 16:17:57】【返回参数】null +【2026-01-26 16:17:57】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-01-26 16:52:35】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-01-26 16:52:35】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2015709440610181122","taskType":"1","shopIds":"1995373681100910593","shopNames":"志诚图书店","fileName":"excel表格更新:task_template_1768886957287.xlsx","dataNum":100,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":100,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0ecc4aa4-3355-41db-8d9e-1b59b8532242_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"} +【2026-01-26 16:52:43】【返回参数】null +【2026-01-26 16:52:43】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-02-08 13:41:37】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-02-08 13:41:37】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2020372423449829378","taskType":"1","shopIds":"2006241414755627010","shopNames":"品博","fileName":"excel表格更新:task_template_1770529245267.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":5,"fileName":"task_template_1770529245267.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f16eb452-b33d-494f-9849-51f503d9d2bd_task_template_1770529245267.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006241414755627010","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-02-08 13:41:37】【返回参数】null +【2026-02-08 13:41:37】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-02-08 13:47:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-02-08 13:47:40】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2020373948133859330","taskType":"1","shopIds":"2006241414755627010","shopNames":"品博","fileName":"excel表格更新:task_template_1770529245267.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":5,"fileName":"task_template_1770529245267.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/24a7401d-b340-41f0-981a-03c522b2a77e_task_template_1770529245267.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006241414755627010","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-02-08 13:47:41】【返回参数】null +【2026-02-08 13:47:41】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-02-08 13:54:02】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-02-08 13:54:02】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2020375549208748033","taskType":"1","shopIds":"2006241414755627010","shopNames":"品博","fileName":"excel表格更新:task_template_1770529245267.xlsx","dataNum":5,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":5,"fileName":"task_template_1770529245267.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d0a34799-1aeb-4e1e-b031-39a1c2849adc_task_template_1770529245267.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2006241414755627010","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-02-08 13:54:03】【返回参数】null +【2026-02-08 13:54:03】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:10:17】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:10: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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/2f011223-3ab4-460e-97b5-41d55700e34c_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-04 17:10:32】【系统异常】【异常方法】addGoods +【2026-03-04 17:10:32】【系统异常】【异常内容】java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap') + at java.base/java.util.HashMap.forEach(HashMap.java:1421) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:248) + 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-04 17:10:32】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:11:17】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:11: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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4af5b618-5d3f-456c-a9c1-ad4e957639ff_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-04 17:11:48】【系统异常】【异常方法】addGoods +【2026-03-04 17:11:48】【系统异常】【异常内容】java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap') + at java.base/java.util.HashMap.forEach(HashMap.java:1421) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:248) + 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-04 17:11:48】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:13:11】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:13:11】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b97adc6a-5512-442f-8a96-52183021e6eb_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-04 17:13:40】【系统异常】【异常方法】addGoods +【2026-03-04 17:13:40】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:250) + 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-04 17:13:40】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:13:56】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:13:56】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/8eb77905-7c95-40a6-a8c0-acc547dc2512_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-04 17:14:12】【系统异常】【异常方法】addGoods +【2026-03-04 17:14:12】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:250) + 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-04 17:14:12】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:15:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:15:27】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7b761a18-ad42-4cc1-95ee-83160446a2d3_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-04 17:16:01】【系统异常】【异常方法】addGoods +【2026-03-04 17:16:01】【系统异常】【异常内容】java.lang.ClassCastException: class java.util.HashMap cannot be cast to class java.lang.String (java.util.HashMap and java.lang.String are in module java.base of loader 'bootstrap') + at java.base/java.util.HashMap.forEach(HashMap.java:1421) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:264) + 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-04 17:16:01】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:17:25】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:17:25】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/dd92d5b1-677e-4ce6-ae96-92d2004c88c9_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-04 17:18:06】【系统异常】【异常方法】addGoods +【2026-03-04 17:18:07】【系统异常】【异常内容】java.lang.ClassCastException: class java.util.HashMap cannot be cast to class java.lang.String (java.util.HashMap and java.lang.String are in module java.base of loader 'bootstrap') + at java.base/java.util.HashMap.forEach(HashMap.java:1421) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:264) + 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-04 17:18:14】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:21:48】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-04 17:21: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":[{"proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/896274d9-d773-4a22-bc5a-3852cc794b43_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-04 17:25:35】【系统异常】【异常方法】addGoods +【2026-03-04 17:25:35】【系统异常】【异常内容】java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.lang.String (java.util.ArrayList and java.lang.String are in module java.base of loader 'bootstrap') + at java.base/java.util.HashMap.forEach(HashMap.java:1421) + at org.dromara.zhishu.util.InterfaceUtils.postForm(InterfaceUtils.java:240) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:266) + 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-04 17:25:35】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:10:01】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:10:01】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0e1fb1d8-29af-49d4-9a1d-0a36f5533c81_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:10:29】【返回参数】null +【2026-03-05 13:10:29】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:12:09】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:12:09】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a892e033-5c93-4b48-b70a-adc5acf751db_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:12:10】【返回参数】null +【2026-03-05 13:12:10】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:13:16】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:13: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":[{"proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ac313af0-7711-4bf1-af46-472f1552bfba_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:23:57】【返回参数】null +【2026-03-05 13:23:57】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:25:18】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:25: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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/64ac0c9d-cac4-4624-95be-479818295e2e_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:33:26】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:33:26】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/735f415f-0458-432f-a58d-7e49751c9f4d_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:37:45】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:37: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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/86a57566-0fa0-4c36-98a9-8fbdd1e5a778_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:40:23】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:40: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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/09f17fa6-36a0-4e56-b51c-30854417d708_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:40:29】【系统异常】【异常方法】addGoods +【2026-03-05 13:40:29】【系统异常】【异常内容】org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://103.236.74.207:8283/task/create": Connect timed out + 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:248) + 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.SocketTimeoutException: Connect timed out + at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:551) + 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-05 13:40:29】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:40:57】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:40: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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/83b138df-c60b-4288-8ff3-e79b756c7386_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:41:59】【返回参数】null +【2026-03-05 13:41:59】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:45:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 13:45:15】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0f6883b3-6038-4d34-9b1b-9a4e5db7fb1f_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 13:45:17】【返回参数】null +【2026-03-05 13:45:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 15:01:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 15:01:39】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b64ceafc-e75c-4725-a987-421f345226d5_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1916358871501082626"} +【2026-03-05 15:01:40】【返回参数】null +【2026-03-05 15:01:40】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 17:28:29】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 17:28:29】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/104f3c70-22ef-4598-838d-8946b7866561_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2029489046873382913\",\"msg\":\"成功\"}\n"},"userId":"1916358871501082626"} +【2026-03-05 17:28:35】【返回参数】null +【2026-03-05 17:28:35】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 17:35:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-05 17:35:19】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ae73d8c0-d17f-422b-b3ea-2790f48e2001_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2029490760825380865\",\"msg\":\"成功\"}\n"},"userId":"1916358871501082626"} +【2026-03-10 09:57:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 09:57:39】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0f16470e-d7d2-4a74-95ca-527b6b6926be_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"} +【2026-03-10 10:00:10】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 10:00: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":[{"proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/71b08c28-455f-4ca1-bf28-4cfe8d21716a_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"} +【2026-03-10 10:03:52】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-03-10 10:03:52】【执行参数】{"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":"1916358871501082626","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"task_template_1768886957287.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/e276e4e4-b52f-4074-9d44-0a4ed8ac153b_task_template_1768886957287.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"1995373681100910593","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1916358871501082626"} +【2026-03-10 10:04:09】【返回参数】null +【2026-03-10 10:04:09】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods \ No newline at end of file diff --git a/file/log/centerBooksAdd_1965254774327533570_4.txt b/file/log/centerBooksAdd_1965254774327533570_4.txt new file mode 100644 index 0000000..90fcdc2 --- /dev/null +++ b/file/log/centerBooksAdd_1965254774327533570_4.txt @@ -0,0 +1,336 @@ + +【2025-11-08 08:43:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-11-08 08:43:34】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1986957732971384833","taskType":"EDIT_STOCK_GOODS","shopIds":"1940355994419642369","shopNames":"古威文具礼品专营店","fileName":"excel表格上传:更新库存.xlsx","dataNum":3,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"EDIT_STOCK_GOODS","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1940355994419642369","data":{"total":3,"fileName":"更新库存.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/50894f85-9a07-4527-b117-b4c1b05dde6f_更新库存.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1965254774327533570"} +【2025-11-08 08:43:34】【系统异常】【异常方法】addGoods +【2025-11-08 08:43:34】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "String.toCharArray()" because "val" is null + at java.base/java.math.BigDecimal.(BigDecimal.java:900) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:244) + 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-11-08 08:43:34】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-11-08 08:44:48】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-11-08 08:44:48】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1986958045090516994","taskType":"EDIT_STOCK_GOODS","shopIds":"1940355994419642369","shopNames":"古威文具礼品专营店","fileName":"excel表格上传:更新库存.xlsx","dataNum":3,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"EDIT_STOCK_GOODS","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1940355994419642369","data":{"total":3,"fileName":"更新库存.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/91c2c5eb-9a9c-44e9-b4bb-4ac784133f20_更新库存.xlsx"},"imageSelect":"1","deleteNum":0},"userId":"1965254774327533570"} +【2025-11-08 08:44:48】【系统异常】【异常方法】addGoods +【2025-11-08 08:44:48】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "String.toCharArray()" because "val" is null + at java.base/java.math.BigDecimal.(BigDecimal.java:900) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:244) + 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-11-08 08:44:48】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-13 09:20:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-13 09:20:51】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2043499624554655746","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:新发布商品模板.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f91c2096-854d-4a73-8fa0-40a8075fff50_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"},"userId":"1965254774327533570"} +【2026-04-13 09:20:53】【返回参数】null +【2026-04-13 09:20:53】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 10:26:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 10:26:05】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"新发布商品模板.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/9d359ccb-32ea-4b5f-a19c-07ad5d299636_新发布商品模板.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2044603196746182658\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 10:26:06】【返回参数】null +【2026-04-16 10:26:06】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:06:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:06:15】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ce467766-d204-4a7b-bac4-dc5a9b506163_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044673709124284417\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:06:15】【返回参数】null +【2026-04-16 15:06:15】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:07:10】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:07: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f5639497-2949-4a0a-8c9e-1970bdbaca49_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044673940914106369\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:07:36】【返回参数】null +【2026-04-16 15:07:36】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:09:35】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:09:35】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a2f18b45-dc29-4a91-9af3-f74e0cb2287b_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044674547817312258\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:09:55】【返回参数】null +【2026-04-16 15:09:55】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:11:32】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:11: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7803a21e-3f1a-4ed9-949a-01cdd51667c5_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044675039247134722\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:11:35】【返回参数】null +【2026-04-16 15:11:35】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:14:37】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:14:37】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/08e13481-da0d-4443-95b1-99031ad198b7_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044675816292282369\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:14:38】【返回参数】null +【2026-04-16 15:14:38】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:15:50】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:15: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/6721fcbf-e7bb-42c5-b86b-0eb9ba68d9a8_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2044676123617325058\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:15:51】【返回参数】null +【2026-04-16 15:15:51】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:16:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:16:39】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a3271d95-2ced-453c-9c59-8843c87d1efb_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044676325912801282\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:18:36】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:18: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":[{"proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0d8e7f18-ced5-4e95-b79d-1a9c5b3a1994_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044676819477524482\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:18:59】【返回参数】null +【2026-04-16 15:18:59】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:22:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:22:05】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/76c9e511-af83-4188-9ec9-339544ba89ae_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2044677694208012290\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-16 15:22:05】【返回参数】null +【2026-04-16 15:22:05】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:24:23】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:24:23】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044678275270795266","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4a997bb6-a82e-46f0-8854-605b77f5f59f_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-04-16 15:24:24】【返回参数】null +【2026-04-16 15:24:24】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:26:16】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:26:16】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044678748044337154","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/59abecc2-6509-45be-a2e5-b62dd11bb72c_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-04-16 15:26:17】【返回参数】null +【2026-04-16 15:26:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:27:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:27:19】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044679013053046786","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/fb88b057-1f65-4be3-a08a-4b3a4e5ed085_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-04-16 15:27:20】【返回参数】null +【2026-04-16 15:27:20】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:30:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:30:05】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044679707529060354","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c2fd224d-93e7-4e25-8906-ce34e3867184_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-04-16 15:30:16】【返回参数】null +【2026-04-16 15:30:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:31:13】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:31:13】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044679992125169665","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4817c483-0313-4732-a3d5-a2c85f52672a_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-04-16 15:31:16】【返回参数】null +【2026-04-16 15:31:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:33:36】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-16 15:33:36】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2044680595056369665","taskType":"1","shopIds":"2000809400724316161","shopNames":"书海寻源cs1","fileName":"excel表格更新:baseInfo_1776307622338.xlsx","dataNum":1,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776307622338.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/2376be6d-86ab-4b37-aa38-99c9ea38cccf_baseInfo_1776307622338.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2000809400724316161","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-04-16 15:33:37】【返回参数】null +【2026-04-16 15:33:37】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-17 15:22:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-17 15:22:27】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":133535,"fileName":"task_template_1776408308595.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/dccd453a-bce1-4eea-8be5-8b14398b9091_task_template_1776408308595.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2045040173987557377\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-17 15:31:08】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-17 15:31: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":133535,"fileName":"task_template_1776408308595.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7b0cedd6-5139-42a3-8e4d-708826773270_task_template_1776408308595.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2045042358829871105\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 14:51:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 14:51:27】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7b1ea6a0-f39d-4dc4-9efb-e59799d33a11_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2046119528465633281\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 14:52:00】【返回参数】null +【2026-04-20 14:52:00】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 14:54:02】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 14:54:02】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7bd22644-6316-444c-b4f8-d0f4690f25d9_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046120179140595714\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 14:56:52】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 14:56:52】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4dfde870-33c7-4cc4-834a-e53c74b4cae4_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046120893040496641\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 14:57:36】【返回参数】null +【2026-04-20 14:57:36】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:05:50】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:05: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ec66bb8b-69dc-412d-8494-a7bba8b48316_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046123147927687170\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:06:20】【返回参数】null +【2026-04-20 15:06:20】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:10:06】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:10: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":[{"proportion":100,"addNum":0}],"data":{"total":12,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ec66bb8b-69dc-412d-8494-a7bba8b48316_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046124222147661825\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:10:17】【返回参数】null +【2026-04-20 15:10:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:29:41】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:29: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c29629cc-0ce2-4651-9a71-826a85c3d4ea_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046129148831666177\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:29:46】【返回参数】null +【2026-04-20 15:29:46】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:31:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:31:34】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/9173f024-bf8d-452a-af10-8941f70e5b95_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046129621793968129\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:31:39】【返回参数】null +【2026-04-20 15:31:39】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:32:43】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:32:43】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d04844b3-493e-4a8f-b252-294adf31632d_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046129914136956930\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:32:49】【返回参数】null +【2026-04-20 15:32:49】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:34:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:34:40】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/8cebea0b-408b-40a4-bae8-7745fcf99a67_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046130402291027969\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:34:45】【返回参数】null +【2026-04-20 15:34:45】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:36:09】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:36:09】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7fb41e5e-88c3-4aab-80c2-f7f34acf2c89_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046130778071306242\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:36:15】【返回参数】null +【2026-04-20 15:36:15】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:42:12】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:42:12】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/e51e95d1-e75e-4fca-91ea-ad14495aeef8_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046132298221293570\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:42:17】【返回参数】null +【2026-04-20 15:42:17】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:43:06】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:43: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/5cfe33c4-d678-4dda-b692-2484f733cbaa_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046132525678399490\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:43:11】【返回参数】null +【2026-04-20 15:43:11】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:46:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:46: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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7f56b37d-dc50-4b1b-afad-1f0b94476ce7_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046133383535202305\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:46:36】【返回参数】null +【2026-04-20 15:46:36】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:48:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-20 15:48:51】【执行参数】{"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":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776666774463.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/91894544-f7b2-4977-9b60-c6717e4c204f_baseInfo_1776666774463.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046133972956549122\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-20 15:48:56】【返回参数】null +【2026-04-20 15:48:56】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-21 15:34:03】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-21 15:34:03】【执行参数】{"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,"way":"2"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7d606bd4-718d-4632-a862-0bc6423aba1a_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046492643871916034\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-21 15:35:18】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-21 15:35: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,"way":"0"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/6c44f2e6-77bf-4546-8328-3767483b134a_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2046492961305231362\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-21 16:55:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-21 16:55:34】【执行参数】{"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,"way":"2"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/93de46fe-f77d-4b90-bf10-65044b53fcdb_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046513159244570626\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-21 16:55:57】【返回参数】null +【2026-04-21 16:55:57】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-21 16:56:26】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-21 16:56:26】【执行参数】{"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,"way":"2"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":1,"fileName":"baseInfo_1776671934641.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0c409529-4a38-4adf-b34b-5ae86caf2eba_baseInfo_1776671934641.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2042843272765263874","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2046513379311312897\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-04-21 16:56:48】【返回参数】null +【2026-04-21 16:56:48】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-09 11:45:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-09 11:45:15】【执行参数】{"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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":6,"fileName":"志诚.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/43e733bd-b6d9-4b01-b644-fd67c501e6bf_志诚.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2052958038187192321\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-09 11:45:16】【返回参数】null +【2026-05-09 11:45:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-09 11:48:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-09 11:48: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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":4,"fileName":"闲鱼商品.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b395071d-127a-48f5-a9da-e7047e9b072c_闲鱼商品.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2052958856936304642\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-09 11:48:30】【返回参数】null +【2026-05-09 11:48:30】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-09 13:20:01】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-09 13:20:01】【执行参数】{"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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":4,"fileName":"闲鱼商品.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/51291a87-9af4-4cb6-9f54-94794db7f69c_闲鱼商品.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2052981886706135042\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-09 13:20:01】【返回参数】null +【2026-05-09 13:20:01】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-16 13:20:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-16 13:20:34】【执行参数】{"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,"way":"0"},"map":{"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":7,"fileName":"加密表格.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/be61ca59-b074-4f5e-a649-0e68a7eed3fb_加密表格.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2054805126617468929","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055518748859691009\",\"msg\":\"成功\"}\n"},"userId":"1965254774327533570"} +【2026-05-16 13:25:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-16 13:25:19】【执行参数】{"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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":7,"fileName":"加密表格.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/66b41482-acc1-4a6e-a856-9d29047cd28d_加密表格.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055519946794856450\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2054805126617468929","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-16 13:26:39】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-16 13:26:39】【执行参数】{"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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":7,"fileName":"加密表格.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/2f217c7a-45c1-4903-8ac8-d94d3c3b4f85_加密表格.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055520280783089666\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2054805126617468929","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-16 13:28:54】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-16 13:28: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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":6,"fileName":"志诚.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/87379338-3fa3-4557-ac15-956e9738b6dd_志诚.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2055520846435315713\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2054805126617468929","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-18 11:52:25】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 11:52:25】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2056221341643239426","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:简创甄选书籍-测试数据.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c08b3732-7557-4892-834c-ea37aa3d035b_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-05-18 11:52:25】【系统异常】【异常方法】addGoods +【2026-05-18 11:52:25】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null + 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:569) + 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:569) + 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:840) + +【2026-05-18 11:52:25】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 11:53:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 11:53:05】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2056221510325563394","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:简创甄选书籍-测试数据.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/77d39ea1-9c47-495c-9273-04e430e09e5f_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-05-18 11:53:12】【系统异常】【异常方法】addGoods +【2026-05-18 11:53:12】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null + 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:569) + 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:569) + 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:840) + +【2026-05-18 11:53:12】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 11:53:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 11:53:30】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"2056221614864396289","taskType":"1","shopIds":"2031685168119377922","shopNames":"简创甄选书籍","fileName":"excel表格更新:简创甄选书籍-测试数据.xlsx","dataNum":2,"taskStatus":"0","status":null,"threadId":null,"relationId":null,"way":"2"},"map":{"bookCategoryAppoint":0,"taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/302ca3a5-5629-48d2-8b37-2ea0036c8b25_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2031685168119377922","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2"},"userId":"1965254774327533570"} +【2026-05-18 11:55:22】【系统异常】【异常方法】addGoods +【2026-05-18 11:55:22】【系统异常】【异常内容】java.lang.NullPointerException: Cannot invoke "Object.toString()" because the return value of "java.util.Map.get(Object)" is null + 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:569) + 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:569) + 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:840) + +【2026-05-18 11:55:22】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 11:57:34】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 11:57:34】【执行参数】{"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,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/385afd29-24b2-4c80-a239-d09c71b9de46_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056222637107929089\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2031685168119377922","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-18 11:57:43】【返回参数】null +【2026-05-18 11:57:43】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 13:03:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 13:03:51】【执行参数】{"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,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/54dd6d25-c4f0-4501-9b66-aae1be13c16c_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056239317095768065\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2031685168119377922","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-18 13:03:54】【返回参数】null +【2026-05-18 13:03:54】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 14:33:27】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 14:33:27】【执行参数】{"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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/6a6f3bbc-a367-479f-9a55-db129cbedaef_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2056261865716015106\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-18 14:37:29】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 14:37:29】【执行参数】{"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,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f1be0ec8-f095-4dc9-94d5-fde7e5404101_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056262883182862338\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2031685168119377922","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-18 14:37:30】【返回参数】null +【2026-05-18 14:37:30】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 14:39:07】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-18 14:39: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,"way":"2"},"map":{"bookCategoryAppoint":0,"data":{"total":2,"fileName":"简创甄选书籍-测试数据.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d1063931-7a40-4595-8e7f-d240f76e48f3_简创甄选书籍-测试数据.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2056263292014256130\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828096496140289","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-05-18 14:39:07】【返回参数】null +【2026-05-18 14:39:07】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-06-03 15:09:49】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-06-03 15:09: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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":198,"fileName":"闲鱼.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/a36296b5-3c88-41e1-bf2c-1ef8d13f6080_闲鱼.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2062069223054589954\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} +【2026-06-03 15:14:21】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-06-03 15:14:21】【执行参数】{"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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":198,"fileName":"闲鱼.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/d4e36220-61f5-4bb9-9167-53870cafbe45_闲鱼.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2062070365880795138\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1965254774327533570","proportion":100,"addNum":0}],"shopIds":"2026828423056261121","synchronizationType":"1","bookCategory":"0"},"userId":"1965254774327533570"} \ No newline at end of file diff --git a/file/log/centerBooksAdd_1967112570379649025_440.txt b/file/log/centerBooksAdd_1967112570379649025_440.txt new file mode 100644 index 0000000..5b4369b --- /dev/null +++ b/file/log/centerBooksAdd_1967112570379649025_440.txt @@ -0,0 +1,9 @@ + +【2025-09-30 18:24:25】【日志开始,方法名称:centerBooks】【centerBooksAdd】中心书库发布商品 +【2025-09-30 18:24:25】【执行参数】{"result":[{"isbn":"9787568918695","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572019722","title":"中学生思辨日知录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.41,"price":22.41,"shippingFee":1,"differencePrice":-23.41,"GoodsUrl":"https://book.kongfz.com/250369/7507863640","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4986191/4593582d712cdd2c_b.jpg","GoodsImgCount":"1","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518418466","title":"萨巴厨房 粗粮细做","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.3,"price":3.3,"shippingFee":5,"differencePrice":-8.3,"GoodsUrl":"https://book.kongfz.com/802508/8631264293","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dffbcfeb/6b008f588aa38d92_b.jpg","GoodsImgCount":"1","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514810813","title":"植物大战僵尸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":8,"shippingFee":3,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/566350/8842775522","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bebcbeee/b169dfd45b2c6889_b.jpg","GoodsImgCount":"5","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535688316","title":"(未拆封)小王子(唯美绘本典藏版,凯特·格林威大奖提名曼纽拉·阿德雷亚尼全新绘制)【浦睿文化出品】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2,"shippingFee":5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/695844/8215712304","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaddfcfe/5f734b0719ebcbe7_b.jpg","GoodsImgCount":"6","onSaleCount":99,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501559565","title":"诗词格律手册,,","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":4,"shippingFee":8,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/241320/6143640925","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbfdfacc/9361917dd464d637_b.jpg","GoodsImgCount":"4","onSaleCount":50,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100023085","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020157563","title":"西藏天空(茅盾文学奖得主、《尘埃落定》作者阿来作品。人如何才能成为真正的人?平等的爱才能铸就幸福)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/9617/8175403971","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1149758/0861d76b41b79344_b.jpg","GoodsImgCount":"3","onSaleCount":129,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521729405","title":"长期有耐心美团的成长与进化逻辑 丁西坡 中信出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.3,"price":15.3,"shippingFee":5,"differencePrice":-20.3,"GoodsUrl":"https://book.kongfz.com/910533/8776640084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdfcbfce/dc3b3f0f770b2564_b.jpg","GoodsImgCount":"1","onSaleCount":141,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559607577","title":"正版书籍命运:掌控你人生的命脉玄机 重塑人生主宰命运改变人生成功与运气","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.98,"price":8.98,"shippingFee":5,"differencePrice":-13.98,"GoodsUrl":"https://book.kongfz.com/442545/7044016865","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/12608860/b7aaf035a46742d8_b.jpg","GoodsImgCount":"1","onSaleCount":195,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546347110","title":"国学典藏 偏方秘方","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":0.5,"shippingFee":5,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/820017/8708620849","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daeddaef/0236a2498e1ea631_b.jpg","GoodsImgCount":"3","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522201573","title":"影子老师实战指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.15,"price":24.15,"shippingFee":2,"differencePrice":-26.15,"GoodsUrl":"https://book.kongfz.com/476106/8289838819","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaffcfff/5b82a2549640e185_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503322457","title":"实拍图 雄师劲旅 中国人民解放军第十一军征战纪实","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.689999999999998,"price":15.69,"shippingFee":4,"differencePrice":-19.689999999999998,"GoodsUrl":"https://book.kongfz.com/330788/8779037628","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddaadcd/354fcf459e2bc020_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508228327","title":"异国主食美味30种","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.9,"price":5.4,"shippingFee":3.5,"differencePrice":-8.9,"GoodsUrl":"https://book.kongfz.com/719470/7147511958","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/18693003/824e38ad750a4f7c_b.jpg","GoodsImgCount":"4","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506503945","title":"黄石公三略浅说","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":5,"shippingFee":9,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/16576/8322316451","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adcbcefe/735dcc4a5c9de005_b.jpg","GoodsImgCount":"4","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510408366","title":"实拍图 百弊放言","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.77,"price":5.77,"shippingFee":4,"differencePrice":-9.77,"GoodsUrl":"https://book.kongfz.com/330788/8655240012","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbabdeaa/d18897da754846a8_b.jpg","GoodsImgCount":"1","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122197689","title":"化工分离过程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.2,"price":1.2,"shippingFee":3,"differencePrice":-4.2,"GoodsUrl":"https://book.kongfz.com/774181/8784846555","imgBigUrl":"httpstotalPrice://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeccdcc/b03249bc4a0bff33_b.jpg","GoodsImgCount":"10","onSaleCount":145,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508649986","title":"正版二手书光荣与梦想(4)9787508649986","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.89,"price":6.89,"shippingFee":0,"differencePrice":-6.89,"GoodsUrl":"https://book.kongfz.com/765962/8807354840","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/facebfde/3179c1dbe9a1a3e1_b.jpg","GoodsImgCount":"1","onSaleCount":607,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787306038234","title":"新媒渠:中国营销实践版1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.98,"price":6.98,"shippingFee":0,"differencePrice":-6.98,"GoodsUrl":"https://book.kongfz.com/356195/8831898825","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/80acda36e6792b24_b.jpg","GoodsImgCount":"7","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550831971","title":"琴道(论古琴的思想体系)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":44,"price":34,"shippingFee":10,"differencePrice":-44,"GoodsUrl":"https://book.kongfz.com/471874/8103918813","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbcefca/3eaa20070e97dc68_b.jpg","GoodsImgCount":"10","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511517661","title":"中国梦 中国的奋斗与复兴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.199999999999999,"price":4.8,"shippingFee":2.4,"differencePrice":-7.199999999999999,"GoodsUrl":"https://book.kongfz.com/13534/8836412957","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdaaecc/f6e075e551b87645_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538731293","title":"本草纲目","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.35,"price":6.35,"shippingFee":5,"differencePrice":-11.35,"GoodsUrl":"https://book.kongfz.com/798675/8753394509","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afeedaca/c47788d5f78c4552_b.jpg","GoodsImgCount":"1","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805532752","title":"世界名曲欣赏·2·俄罗斯部分","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.5,"price":2.5,"shippingFee":5,"differencePrice":-7.5,"GoodsUrl":"https://book.kongfz.com/469122/8625940704","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feddbdba/17478803856c6a77_b.jpg","GoodsImgCount":"9","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787566801715","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117237321","title":"英汉对照护理英语会话(第2版 英汉对照)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/508346/8881986880","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfdacfb/eecb8ef0a9eceff3_b.jpg","GoodsImgCount":"9","onSaleCount":104,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807058953","title":"景丽瑜伽:瑜伽初级入门(升级版)附光盘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":3.3,"shippingFee":0,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/840504/8228479927","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adfedacd/19bfd9488c0fbb11_b.jpg","GoodsImgCount":"7","onSaleCount":448,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122270795","title":"新SAT阅读长难句精讲30天第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.559999999999999,"price":4.06,"shippingFee":4.5,"differencePrice":-8.559999999999999,"GoodsUrl":"https://book.kongfz.com/877194/8511050402","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fafafbfd/6b7b13835b41f7ec_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508224664","title":"英语语法表解手册 (修订版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":38,"shippingFee":10,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/269417/5120887447","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faecbabe/9519270017db1bd6_b.jpg","GoodsImgCount":"2","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534736025","title":"中国国家地理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.9399999999999995,"price":4.93,"shippingFee":0.01,"differencePrice":-4.9399999999999995,"GoodsUrl":"https://book.kongfz.com/545601/8761272941","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14322431/d91e5ce59a592a24_b.jpg","GoodsImgCount":"2","onSaleCount":151,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787107346361","title":"普通高中教科书教师教学用书生物学选择性必修2生物与环境 人民教育出版社课程教材研究所生物课程教材研究开发中心编著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.5,"price":10.5,"shippingFee":3,"differencePrice":-13.5,"GoodsUrl":"https://book.kongfz.com/681595/8811715235","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdefffb/0fbe52d7dda4ef04_b.jpg","GoodsImgCount":"3","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030207500","title":"大学应用物理 蒲利春 张雪峰 科学出版社 9787030207500","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.87,"price":1.87,"shippingFee":3,"differencePrice":-4.87,"GoodsUrl":"https://book.kongfz.com/195620/8312037668","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5749161/6e89f9d1af7e7989_b.jpg","GoodsImgCount":"1","onSaleCount":72,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213104589","title":"颠覆:马斯克的商业逻辑和创新法则(九品)9787213104589","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.9,"price":9.3,"shippingFee":2.6,"differencePrice":-11.9,"GoodsUrl":"https://book.kongfz.com/20579/8802296569","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbadefca/15c37dc77ff955cf_b.jpg","GoodsImgCount":"1","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535364456","title":"古代传说中的怪物【正版 塑封 发货快】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/891652/8853257427","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acceceed/610520b76a3ebe80_b.jpg","GoodsImgCount":"5","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560417035","title":"对农民让利:一个乡镇党委书记的工作笔记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.8,"price":2.8,"shippingFee":10,"differencePrice":-12.8,"GoodsUrl":"https://book.kongfz.com/20238/6553568561","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2388552/6b834f981ec7e865_b.jpg","GoodsImgCount":"7","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545560978","title":"邓小平","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.18,"price":9.18,"shippingFee":5,"differencePrice":-14.18,"GoodsUrl":"https://book.kongfz.com/805022/8530275546","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21340856/36aaf5bffbf85d8c_b.jpg","GoodsImgCount":"1","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569506563","title":"活着,就该尽点儿兴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":8,"shippingFee":5,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/364917/8345040086","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecccebaa/eae7ce24870491e4_b.jpg","GoodsImgCount":"3","onSaleCount":139,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534338755","title":"中国文化史教程第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.49,"price":1.49,"shippingFee":4,"differencePrice":-5.49,"GoodsUrl":"https://book.kongfz.com/878042/8490636209","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaadffef/7807b51707816c48_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500319368","title":"历代画谱类编:山水(12)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":52,"price":40,"shippingFee":12,"differencePrice":-52,"GoodsUrl":"https://book.kongfz.com/25728/8440709404","imgBigUrl":"https://www0.kfzimg.com/G06/M00/14/79/p4YBAFqisNaAIasgAABrIQx-ikM832_b.jpg","GoodsImgCount":"1","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533258030","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802257481","title":"希腊棺材之谜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.73,"price":12.73,"shippingFee":5,"differencePrice":-17.73,"GoodsUrl":"https://book.kongfz.com/202798/8894676974","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccccbdec/2343a3c4f807db86_b.jpg","GoodsImgCount":"1","onSaleCount":85,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117055352","title":"妇产科手术学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":28,"shippingFee":10,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/760393/8899580666","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffaecbce/b54811d7b2204a06_b.jpg","GoodsImgCount":"3","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532522453","title":"韩愈散文选集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":6,"shippingFee":6,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/263916/8292153110","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abacbbfc/82ed778ad7f2030c_b.jpg","GoodsImgCount":"7","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301347775","title":"中国现代文学三十年(第三版)北京大学钱理群、温儒敏、吴福辉教授著 现当代文学书及中文系考研重要参考书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":13,"shippingFee":10,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/574881/7680988794","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deffdbae/bb726b02bcf65138_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500166207","title":"疫情后中国经济新发展格局","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":1.5,"shippingFee":3,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/838443/8749381946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebecdcad/222250eecf4e488c_b.jpg","GoodsImgCount":"1","onSaleCount":323,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546420950","title":"7岁对了,一辈子就对了","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/712812/7340204569","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbffeec/79cd4560b8c5de05_b.jpg","GoodsImgCount":"4","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807676447","title":"云冈石窟","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.5,"price":8,"shippingFee":4.5,"differencePrice":-12.5,"GoodsUrl":"https://book.kongfz.com/81946/6302388964","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baeaffef/65208eca36d1432c_b.jpg","GoodsImgCount":"4","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305120305","title":"正版新书现货 文学理论读本/IAS励学文丛 9787305120305 阎嘉|主编:周宪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.66,"price":32.66,"shippingFee":5,"differencePrice":-37.66,"GoodsUrl":"https://book.kongfz.com/311632/8812587135","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babdccad/2ba0f4a400d24004_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540485818","title":"散落星河的记忆4:璀璨","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":12,"shippingFee":8,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/639697/5243750723","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfecffea/f776a0acf017e68f_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559652737","title":"看国宝 和爸妈游博物馆","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.9,"price":1.8,"shippingFee":3.1,"differencePrice":-4.9,"GoodsUrl":"https://book.kongfz.com/894143/8701969746","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaabafee/f2595c7b2fd4a550_b.jpg","GoodsImgCount":"6","onSaleCount":261,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503943348","title":"献给阿尔吉侬的花束","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":10,"shippingFee":10,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/498915/7429202611","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbebfaec/d6256a6ee6537fa6_b.jpg","GoodsImgCount":"10","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301085493","title":"简单机械(中文翻译版)——国家地理阅读与写作训练丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/395221/5519963069","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1098/c6f60cc2ccbee2bb_b.jpg","GoodsImgCount":"2","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543211018","title":"寺庙自助游完全手册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":15,"shippingFee":0,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/700859/7742663957","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acecbabc/2d6e70c49c17570e_b.jpg","GoodsImgCount":"3","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801491589","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561327265","title":"正版二手书二手正版重返普罗旺斯97875613272659787561327265","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/765962/8631594226","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babdaece/b00ebe69df5166ff_b.jpg","GoodsImgCount":"1","onSaleCount":341,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543225589","title":"信用评级理论与实务 第二版叶伟春 编格致出版社9787543225589","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.17,"price":4.17,"shippingFee":0,"differencePrice":-4.17,"GoodsUrl":"https://book.kongfz.com/443530/8601138144","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11958278/4e1eb16e9d1c0462_b.jpg","GoodsImgCount":"1","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507547092","title":"我们生命里的“七七”(许倬云、郝柏村、齐邦媛、星云大师等用生命记录一篇篇撼动心灵的故事)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":35,"shippingFee":8,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/274410/7932527162","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddedaaac/5cabe80609502ec1_b.jpg","GoodsImgCount":"7","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787555373070","title":"2023秋状元导学案名师教学设计数学三年级上册样书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":5,"shippingFee":9,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/381029/8749671888","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcedeaf/6bf3c05878ca8f83_b.jpg","GoodsImgCount":"3","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540206956","title":"中国谋略宝鉴第十六卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.01,"price":0.01,"shippingFee":3,"differencePrice":-3.01,"GoodsUrl":"https://book.kongfz.com/360813/5966263658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdbfdfa/62959300371438f8_b.jpg","GoodsImgCount":"2","onSaleCount":330,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518051625","title":"肿瘤医院营养师的防癌抗癌吃法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.790000000000001,"price":5.19,"shippingFee":1.6,"differencePrice":-6.790000000000001,"GoodsUrl":"https://book.kongfz.com/457799/7915187178","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C3/5E/p4YBAFuRCEOAGxQ5AAC90eEIDkQ669_b.jpg","GoodsImgCount":"0","onSaleCount":220,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508079165","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787102041223","title":"物色黑白","quality":0,"qualityText":"","originalPrice":0,"totalPrice":66,"price":66,"shippingFee":0,"differencePrice":-66,"GoodsUrl":"https://book.kongfz.com/319064/8795448603","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbeefaca/c584b2d59a425bfc_b.jpg","GoodsImgCount":"8","onSaleCount":76,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787220108211","title":"瑜伽文库〔5〕:阿育吠陀瑜伽","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.8,"price":19.8,"shippingFee":13,"differencePrice":-32.8,"GoodsUrl":"https://book.kongfz.com/402676/8643741176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeaabefd/2a392099ec628856_b.jpg","GoodsImgCount":"9","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810103855","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806498439","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545435702","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539186887","title":"我的第一本科学漫画书寻宝记系列:巴西寻宝记11","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.51,"price":0.01,"shippingFee":4.5,"differencePrice":-4.51,"GoodsUrl":"https://book.kongfz.com/825588/8886241126","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccedcffa/61ddbfc1f57a12af_b.jpg","GoodsImgCount":"5","onSaleCount":248,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537144704","title":"写给小读者之快乐精灵","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":2,"shippingFee":3,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/774181/8597113775","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfcffafb/d701ee2510c5ed23_b.jpg","GoodsImgCount":"5","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115106124","title":"WindowsAPI函数参考手册 WindowsAPI函数参考手册 编写组编 人民邮电出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.37,"price":24.37,"shippingFee":4,"differencePrice":-28.37,"GoodsUrl":"https://book.kongfz.com/878042/8495444282","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfbeabaa/96a386fdb8bce4df_b.jpg","GoodsImgCount":"1","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535612793","title":"论摄影","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":12,"shippingFee":0,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/26771/8136858550","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eabfccee/3ca1daf23bce666c_b.jpg","GoodsImgCount":"4","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532785445","title":"近代文学批评史(全八卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":411.88,"price":401.88,"shippingFee":10,"differencePrice":-411.88,"GoodsUrl":"https://book.kongfz.com/471874/8695951046","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdabfceb/3089afd17e730b90_b.jpg","GoodsImgCount":"5","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504758415","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500311133","title":"徽派与徽州篆刻研究专辑:西泠印社(总第21辑)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.11,"price":16.11,"shippingFee":0,"differencePrice":-16.11,"GoodsUrl":"https://book.kongfz.com/897296/8237009972","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23068564/6d816b75de4e44ee_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111180623","title":"物业管理沟通艺术","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31,"price":24,"shippingFee":7,"differencePrice":-31,"GoodsUrl":"https://book.kongfz.com/912353/8289311525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdfcefa/39fd857445991f96_b.jpg","GoodsImgCount":"6","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532520756","title":"天涯侠侣册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.26,"price":4.26,"shippingFee":2,"differencePrice":-6.26,"GoodsUrl":"https://book.kongfz.com/1214361/8873449966","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbbddcb/8610a576eb08226a_b.jpg","GoodsImgCount":"4","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787109200845","title":"榨汁机美味食谱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.5,"price":20,"shippingFee":3.5,"differencePrice":-23.5,"GoodsUrl":"https://book.kongfz.com/719470/8585565450","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/18693003/0bfa2608b791ef68_b.jpg","GoodsImgCount":"3","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544763035","title":"三个女人 罗伯特 穆齐尔 译林出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.69,"price":9.69,"shippingFee":4,"differencePrice":-13.69,"GoodsUrl":"https://book.kongfz.com/766912/8858942814","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdefddae/bfa6459d0d82fb08_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541736247","title":"2007年最佳小故事排行榜TOP100感动卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/1207077/8702929036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efcbbdfa/2d9763b9c691fc8d_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507838336","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556021703","title":"女儿的故事 梅子涵 9787556021703 长江少年儿童出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.18,"price":1.68,"shippingFee":2.5,"differencePrice":-4.18,"GoodsUrl":"https://book.kongfz.com/237713/8792049160","imgBigUrl":"https://www0.kfzimg.com/G06/M00/38/4F/p4YBAFqjzVGAQ2WRAABJeXbuA7o046_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533937928","title":"迷狂 精装32开一版一印","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/696299/5906512396","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afabbcbb/9090a343c388e169_b.jpg","GoodsImgCount":"5","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565513671","title":"普通土壤学(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/506902/4876475660","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abbefebc/96f603e5373aadfd_b.jpg","GoodsImgCount":"2","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805646862","title":"野性的证明","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.98,"price":1.98,"shippingFee":3,"differencePrice":-4.98,"GoodsUrl":"https://book.kongfz.com/557002/5846843192","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbaeffbf/4b2a328969a84da5_b.jpg","GoodsImgCount":"6","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501767939","title":"期货-财富永动机","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":2,"shippingFee":4.9,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/26937/3839324520","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbfccfbb/f0d427a5206db5af_b.jpg","GoodsImgCount":"4","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787204009978","title":"红砂勾魂手 品好","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":19,"shippingFee":9,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/303616/8201886650","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafbbaba/e4d9bb837f6179d2_b.jpg","GoodsImgCount":"13","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020165650","title":"岁月静好:蒋勋的日常功课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.46,"price":18.46,"shippingFee":0,"differencePrice":-18.46,"GoodsUrl":"https://book.kongfz.com/792408/8898218361","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2790/02552e196a86ee0f77_b.jpg","GoodsImgCount":"1","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509823743","title":"红色之路烽火","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/730214/8858116427","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbeeebe/f500632e8ecee420_b.jpg","GoodsImgCount":"4","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536472129","title":"拉玛迷境","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34,"price":22,"shippingFee":12,"differencePrice":-34,"GoodsUrl":"https://book.kongfz.com/151474/8535484987","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbddebe/867cffc401ca09c4_b.jpg","GoodsImgCount":"7","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121211515","title":"学而思 培优辅导:初二物理跟踪练习(上下)附答案","quality":0,"qualityText":"","originalPrice":0,"totalPrice":120,"price":110,"shippingFee":10,"differencePrice":-120,"GoodsUrl":"https://book.kongfz.com/23910/8754936757","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3161432/7d4639abda234b4e_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224054538","title":"心血运动论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.67,"price":3.77,"shippingFee":3.9,"differencePrice":-7.67,"GoodsUrl":"https://book.kongfz.com/261575/7984459895","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecfcdcfa/b3872a57908ad1e8_b.jpg","GoodsImgCount":"5","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020081776","title":"芥川龙之介读本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":12,"shippingFee":8,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/689520/8843157283","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babacfce/8db8bcfa2d41f417_b.jpg","GoodsImgCount":"7","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532603763","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510430008","title":"新青瓷之窑变","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.06,"price":3.06,"shippingFee":5,"differencePrice":-8.06,"GoodsUrl":"https://book.kongfz.com/1207077/8886789761","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfdabcaa/1796162e1d9f2e4b_b.jpg","GoodsImgCount":"1","onSaleCount":251,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536564343","title":"夜翼天使","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/470358/4339829959","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfdffca/d07df374b3e13496_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550708471","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507850642","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544624770","title":"新编高级英语语法:A New Advanced English Grammar","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32,"price":20,"shippingFee":12,"differencePrice":-32,"GoodsUrl":"https://book.kongfz.com/830099/8882431094","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbaccbf/781a6310a0eb776e_b.jpg","GoodsImgCount":"9","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115495372","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506290227","title":"墓志书法百品","quality":0,"qualityText":"","originalPrice":0,"totalPrice":57.82,"price":46.82,"shippingFee":11,"differencePrice":-57.82,"GoodsUrl":"https://book.kongfz.com/509141/8585650720","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14014041/28964975e7dc309e_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559634351","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303135660","title":"顾明远教育口述史(增订)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/17747/5768445516","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1970964/2e94e4bdc50d3792_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800880452","title":"龙虎群英 中","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":1.5,"shippingFee":4,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/203004/8899012503","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdabaaea/64e07e07529c21b6_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538290622","title":"PASS初中英语巧记2000词","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":2,"shippingFee":3,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/841015/8684297376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcfffbab/4b67a6d547944648_b.jpg","GoodsImgCount":"4","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101084894","title":"中华经典精粹解读:史记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/702814/8179518138","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/defadbfe/4eea5c6a4809568e_b.jpg","GoodsImgCount":"4","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301270189","title":"文本的隐与显 中国现代文学文献校读论稿 解志熙著 北京大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.8,"price":25.8,"shippingFee":5,"differencePrice":-30.8,"GoodsUrl":"https://book.kongfz.com/903313/8547742130","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfeacbae/ddfb49783c133365_b.jpg","GoodsImgCount":"1","onSaleCount":85,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787552569421","title":"阅读理解超快提分公式","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":10,"shippingFee":0,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/34480/7649697434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/15505652/d3d2322c7ec0cb86_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511717306","title":"中央编译局文库 中国的民主治理 理论与实践 效率政府","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.059999999999999,"price":5.06,"shippingFee":3,"differencePrice":-8.059999999999999,"GoodsUrl":"https://book.kongfz.com/783956/8891177168","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acacbaae/5200429427f763ac_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571209483","title":"墨点字帖:2025秋英语写字同步练习册·必修第三册(新教材)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.01,"price":4.51,"shippingFee":4.5,"differencePrice":-9.01,"GoodsUrl":"https://book.kongfz.com/757284/8792634933","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbefcfaa/0cffeeed9f3fd774_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539448374","title":"历代书法名碑名帖精选:隶书(2)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/27190/365578569","imgBigUrl":"https://www0.kfzimg.com/G03/M01/70/45/pYYBAFWvkZeAZ3boAADmaxNa8ss048_b.jpg","GoodsImgCount":"3","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544246255","title":"星期三的战争 美 加里 施密特著 高雪莲译 南海出版公司","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.3,"price":1.3,"shippingFee":5,"differencePrice":-6.3,"GoodsUrl":"https://book.kongfz.com/672601/8709251624","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfddfcdd/b6b4d1110bf4f714_b.jpg","GoodsImgCount":"1","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787205094157","title":"红楼人物家庭角色论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":81,"price":71,"shippingFee":10,"differencePrice":-81,"GoodsUrl":"https://book.kongfz.com/20509/2274876206","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1930/017c3cfaea4867b6f6_b.jpg","GoodsImgCount":"1","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569912647","title":"美在举手投足间 一个人若举止优雅 心灵也会变得更坚强","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.7,"price":12.7,"shippingFee":5,"differencePrice":-17.7,"GoodsUrl":"https://book.kongfz.com/398369/8265506509","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/debccfdc/6d2d3253fb537795_b.jpg","GoodsImgCount":"1","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538724554","title":"毕淑敏作品2·话说孩子毕淑敏时代文艺出版社9787538724554","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.64,"price":4.64,"shippingFee":0,"differencePrice":-4.64,"GoodsUrl":"https://book.kongfz.com/366030/8301042871","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/29e82405eff322db_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534759819","title":"理学古文史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":5,"shippingFee":10,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/233973/8223713174","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbfabab/c49dd1ce62c4a5fb_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787307043114","title":"数字测图原理与方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/603269/8864023084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aacfabef/22ba103e580191bb_b.jpg","GoodsImgCount":"7","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801516091","title":"我信我能我要","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43.21,"price":32.21,"shippingFee":11,"differencePrice":-43.21,"GoodsUrl":"https://book.kongfz.com/878875/8142977482","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22516043/bd4ef387b1384988_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020161638","title":"袁枚诗选(中国古典文学读本丛书典藏)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.36,"price":21.36,"shippingFee":2,"differencePrice":-23.36,"GoodsUrl":"https://book.kongfz.com/476106/8283375310","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebcdbcdd/18643d009e705fdc_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787220040528","title":"历代笔记小说精华 第四卷 清","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.3,"price":23.3,"shippingFee":5,"differencePrice":-28.3,"GoodsUrl":"https://book.kongfz.com/261116/8560390036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceceadad/4cef7455f3e00ef9_b.jpg","GoodsImgCount":"1","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537733373","title":"少林拳术图说","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/210450/4528748517","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D7/AB/p4YBAFqYwJuAJtQPAACd0cT9L9o331_b.jpg","GoodsImgCount":"1","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800063107","title":"汉语方言词汇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":66.5,"price":61,"shippingFee":5.5,"differencePrice":-66.5,"GoodsUrl":"https://book.kongfz.com/405080/7310375008","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daeceecf/30475e68c2096095_b.jpg","GoodsImgCount":"1","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020075782","title":"唐宋词简释","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.2,"price":7.7,"shippingFee":3.5,"differencePrice":-11.2,"GoodsUrl":"https://book.kongfz.com/206421/8501383468","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6147505/9dea4fd349d3d63a_b.jpg","GoodsImgCount":"2","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531855354","title":"东汉演义之二十八《武瘟神下山》","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":25,"shippingFee":0,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/712837/6676396249","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbfaaede/5fd873f0845c0e19_b.jpg","GoodsImgCount":"6","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516100516","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806683200","title":"上海探戈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.79,"price":1.59,"shippingFee":3.2,"differencePrice":-4.79,"GoodsUrl":"https://book.kongfz.com/739740/7152710203","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbacecee/cac0ec945280e864_b.jpg","GoodsImgCount":"4","onSaleCount":228,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502705329","title":"正版 (同系3本包邮)中国古代航海 中国传统民俗文化政治经济制度系列古代航海活动 海上丝绸之路 郑和下西洋指南针的发明与航海等古代航海事业 9787502705329","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.3,"price":14.3,"shippingFee":6,"differencePrice":-20.3,"GoodsUrl":"https://book.kongfz.com/14409/8719267733","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1570906/9b5183c8dd9004c0_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300305042","title":"小学儿童心理学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":5.5,"shippingFee":1.5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/774690/8698078134","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/12774130/3dec28e005f0c72f_b.jpg","GoodsImgCount":"1","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543579217","title":"少年时飞机大解剖","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6,"price":3,"shippingFee":3,"differencePrice":-6,"GoodsUrl":"https://book.kongfz.com/838443/8811129821","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffaeffad/54baa2c8e92b3e4a_b.jpg","GoodsImgCount":"1","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802128125","title":"中国分省系列地图集 河北省地图集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":7,"shippingFee":5,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/911327/8701948242","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdccbec/8f996e037aa30df2_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101015485","title":"祥云县志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":126,"price":120,"shippingFee":6,"differencePrice":-126,"GoodsUrl":"https://book.kongfz.com/409331/3661003725","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eccfbcdd/733430ba3bdecdfb_b.jpg","GoodsImgCount":"6","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117267304","title":"正版二手 变态心理学(第3版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.69,"price":16.69,"shippingFee":0,"differencePrice":-16.69,"GoodsUrl":"https://book.kongfz.com/549116/8830860499","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D4/28/p4YBAFt-5veAPPw7AABq9rtHFGs112_b.jpg","GoodsImgCount":"1","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218045627","title":"现象学的始基","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.16,"price":32.16,"shippingFee":0,"differencePrice":-32.16,"GoodsUrl":"https://book.kongfz.com/792228/8885481303","imgBigUrl":"https://www0.kfzimg.com/G06/M00/62/A7/p4YBAFuCZAWAOEfaAAA_Rk5xTx8034_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513312097","title":"人骨拼图:林肯·莱姆系列之一","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.27,"price":13.27,"shippingFee":10,"differencePrice":-23.27,"GoodsUrl":"https://book.kongfz.com/915406/8415906199","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecfbead/4d4a0685889879f4_b.jpg","GoodsImgCount":"3","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513653343","title":"商社就是天网","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.94,"price":16.94,"shippingFee":5,"differencePrice":-21.94,"GoodsUrl":"https://book.kongfz.com/202798/8568284655","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfafbfc/c08df37a7d16dd93_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040079869","title":"电子技术基础数字部分第4版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":0.5,"shippingFee":5,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/820017/8732562193","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaecdacd/e70eef6ce74fdfbe_b.jpg","GoodsImgCount":"2","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505725508","title":"盗墓笔记5 谜海归巢","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.92,"price":4.12,"shippingFee":2.8,"differencePrice":-6.92,"GoodsUrl":"https://book.kongfz.com/1093663/8899378239","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daffabac/fe727b4b941bbc33_b.jpg","GoodsImgCount":"1","onSaleCount":362,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509155189","title":"颈腰关节疼痛及注射疗法 第5版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":184,"price":168,"shippingFee":16,"differencePrice":-184,"GoodsUrl":"https://book.kongfz.com/165055/8254619732","imgBigUrl":"https://www0.kfzimg.com/G05/M00/F1/D0/p4YBAFmNI22AdqQ1AAT058m6zlw056_b.jpg","GoodsImgCount":"9","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509641651","title":"实拍图 文化的逻辑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.74,"price":4.74,"shippingFee":5,"differencePrice":-9.74,"GoodsUrl":"https://book.kongfz.com/802501/8561762805","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbabfcdc/6980f786578b04a8_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200044867","title":"梦断紫禁城","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.08,"price":2.08,"shippingFee":3,"differencePrice":-5.08,"GoodsUrl":"https://book.kongfz.com/832065/8677126488","imgBigUrl":"https://www0.kfzimg.com/G06/M00/B0/84/p4YBAFrBjlSAJZRXAADDlnNLY8U712_b.jpg","GoodsImgCount":"1","onSaleCount":162,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801123596","title":"中国民主建国会史稿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":2.2,"shippingFee":3.3,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/912942/8547857084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcefdeae/6c07c7d88214a065_b.jpg","GoodsImgCount":"2","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301139899","title":"地质学原理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":29,"shippingFee":9,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/521012/8429778365","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfbbdbcd/7e66c3c7cba28ccd_b.jpg","GoodsImgCount":"4","onSaleCount":150,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787104019404","title":"中国现代话剧教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":2,"shippingFee":8,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/23363/8631048802","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3089567/3d8d13eefa1391ea_b.jpg","GoodsImgCount":"3","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506671965","title":"温室气体核算体系:企业价值链(范围三)核算与报告标准","quality":0,"qualityText":"","originalPrice":0,"totalPrice":88,"price":78,"shippingFee":10,"differencePrice":-88,"GoodsUrl":"https://book.kongfz.com/12885/7710497039","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aeaedccf/213af3af7a5412cd_b.jpg","GoodsImgCount":"3","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108016850","title":"人·兽·鬼","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.779999999999999,"price":5.77,"shippingFee":0.01,"differencePrice":-5.779999999999999,"GoodsUrl":"https://book.kongfz.com/877749/8801481679","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/421097e73bed945d_b.jpg","GoodsImgCount":"3","onSaleCount":382,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111350118","title":"材料力学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":14,"shippingFee":8,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/190848/8546617490","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebfbffac/bbc9b45a3879d75e_b.jpg","GoodsImgCount":"1","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539996301","title":"纳粹医生:医学屠杀与种族灭绝心理学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":22,"shippingFee":7,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/677955/8132923615","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efaecfbb/b6bb3ab2cfa17bb1_b.jpg","GoodsImgCount":"10","onSaleCount":171,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117141598","title":"实地解剖学(本科创新教材)(第2版)羊惠君9787117141598人民卫生出版社羊惠君 编人民卫生出版社9787117141598","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":10,"shippingFee":0,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/810267/8649014717","imgBigUrl":"https://www0.kfzimg.com/G06/M00/20/51/p4YBAFqaTeyAWKo9AAB4_CSZkNs668_b.jpg","GoodsImgCount":"2","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532785230","title":"彩虹几度","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.5,"price":10,"shippingFee":7.5,"differencePrice":-17.5,"GoodsUrl":"https://book.kongfz.com/274142/6240614349","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbfddad/7d7cfe731f17e04d_b.jpg","GoodsImgCount":"4","onSaleCount":103,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801456915","title":"世界艳史 彩图版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.36,"price":1.36,"shippingFee":3,"differencePrice":-4.36,"GoodsUrl":"https://book.kongfz.com/791250/8511647318","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babfecff/e3ea21a762374dc7_b.jpg","GoodsImgCount":"1","onSaleCount":285,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805202174","title":"白话尚书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.2,"price":8.2,"shippingFee":4,"differencePrice":-12.2,"GoodsUrl":"https://book.kongfz.com/203004/8424128025","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdebccad/0b4a13e8667c9f38_b.jpg","GoodsImgCount":"1","onSaleCount":50,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100240147","title":"回望;西南联大沉思录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":44.9,"price":42.9,"shippingFee":2,"differencePrice":-44.9,"GoodsUrl":"https://book.kongfz.com/531424/8836849831","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfecbfde/300a0427a530a221_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556841233","title":"我的第一本科学漫画书 世界寻宝记26 意大利1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.53,"price":1.03,"shippingFee":4.5,"differencePrice":-5.53,"GoodsUrl":"https://book.kongfz.com/1148054/8608793479","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddaabcec/c7db2f605b3fe3d5_b.jpg","GoodsImgCount":"1","onSaleCount":136,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521728057","title":"薛暮桥年谱 1904-1952","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":24.8,"shippingFee":5,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/180897/8428895461","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceceafce/caceb3157ab2e82e_b.jpg","GoodsImgCount":"1","onSaleCount":128,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547258569","title":"你若不勇敢谁替你坚强思履编9787547258569","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":0.5,"shippingFee":2.8,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/783757/8331651577","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdeddde/efd4c2250ad6a94d_b.jpg","GoodsImgCount":"1","onSaleCount":337,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547122990","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560082073","title":"剑桥雅思听力精练","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.03,"price":9.03,"shippingFee":4,"differencePrice":-13.03,"GoodsUrl":"https://book.kongfz.com/884251/8122170338","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaeeafee/47b06a1e8e364586_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550605015","title":"高盛在中国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3,"price":4.29,"shippingFee":0.01,"differencePrice":-4.3,"GoodsUrl":"https://book.kongfz.com/836621/8847676368","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeccebf/0ebeedb9d50da249_b.jpg","GoodsImgCount":"4","onSaleCount":263,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559639769","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302112785","title":"第三次改革:中国非营利部门战略研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.89,"price":6.39,"shippingFee":1.5,"differencePrice":-7.89,"GoodsUrl":"https://book.kongfz.com/774690/8186180572","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AB/04/p4YBAFr8MJuAGAghAAA1z6WS3zI917_b.jpg","GoodsImgCount":"1","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530771389","title":"35公斤的希望","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.84,"price":8.04,"shippingFee":3.8,"differencePrice":-11.84,"GoodsUrl":"https://book.kongfz.com/1213190/8836708018","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dafaafec/7cf7665548548831_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533937102","title":"名家散文典藏·平凹散文:丑石","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.9,"price":5.9,"shippingFee":3,"differencePrice":-8.9,"GoodsUrl":"https://book.kongfz.com/681595/8690093248","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddbdffb/4f941801eb25debf_b.jpg","GoodsImgCount":"3","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536015920","title":"周易八卦实解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34,"price":28,"shippingFee":6,"differencePrice":-34,"GoodsUrl":"https://book.kongfz.com/907443/8170308109","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafeecaf/897ff4b8c0710df5_b.jpg","GoodsImgCount":"7","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516606476","title":"实干成就梦想","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":4.8,"shippingFee":5,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/350027/5033853984","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcacdab/2a63dd061ea42499_b.jpg","GoodsImgCount":"7","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301354377","title":"你写的论文,为什么老师总看不上?","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.58,"price":26.58,"shippingFee":3,"differencePrice":-29.58,"GoodsUrl":"https://book.kongfz.com/787155/8780056007","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13196094/1eec498b7026e22c_b.jpg","GoodsImgCount":"1","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122223289","title":"【正版二手】建筑结构与选型崔钦淑9787122223289化学工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.78,"price":3.78,"shippingFee":0,"differencePrice":-3.78,"GoodsUrl":"https://book.kongfz.com/805904/7166459946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/febaefaf/7e1ada906fcd9fe5_b.jpg","GoodsImgCount":"6","onSaleCount":101,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530215982","title":"风声","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.4,"price":7.4,"shippingFee":4,"differencePrice":-11.4,"GoodsUrl":"https://book.kongfz.com/203004/8422969956","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcaedba/f9c5e1712684ca6f_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511273048","title":"麻省理工商学院最具影响力的商业哲学课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.66,"price":12.66,"shippingFee":0,"differencePrice":-12.66,"GoodsUrl":"https://book.kongfz.com/792228/8901674659","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E2/0D/p4YBAFqY5zyAO8BbAADniLoteH8960_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502844684","title":"主力行为盘口解密二 随机发","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":6,"shippingFee":2,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/755561/8872649902","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbcffdcc/041163d5f287171b_b.jpg","GoodsImgCount":"3","onSaleCount":152,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504486004","title":"中国传统民俗文化 中国古代城墙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.8100000000000005,"price":1.81,"shippingFee":5,"differencePrice":-6.8100000000000005,"GoodsUrl":"https://book.kongfz.com/23607/8261593719","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deacabba/95b12624c888dc2c_b.jpg","GoodsImgCount":"1","onSaleCount":147,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507753936","title":"环喜马拉雅区域研究编译文集二——佐米亚、边疆与跨界","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33.3,"price":27.3,"shippingFee":6,"differencePrice":-33.3,"GoodsUrl":"https://book.kongfz.com/522587/8886443261","imgBigUrl":"https://www0.kfzimg.com/G06/M00/37/D8/p4YBAFsnavWAAHndAABM74pZ9cE770_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504691422","title":"百年耕耘 金善宝传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.58,"price":24.58,"shippingFee":5,"differencePrice":-29.58,"GoodsUrl":"https://book.kongfz.com/716746/8485861144","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddccfdfa/320fa35108c02c52_b.jpg","GoodsImgCount":"2","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121350894","title":"服装设计效果图手绘教程 全彩","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.6899999999999995,"price":0.69,"shippingFee":5,"differencePrice":-5.6899999999999995,"GoodsUrl":"https://book.kongfz.com/1215524/8813604508","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decedfeb/df55bfbeacd0bdc0_b.jpg","GoodsImgCount":"2","onSaleCount":110,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530858394","title":"最具人气的110篇微型小说","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":2.2,"shippingFee":5,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/820017/8708554212","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dedacdcd/5f5491cc457f068e_b.jpg","GoodsImgCount":"2","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509130520","title":"吕仁和临床经验集(第二辑)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":38,"shippingFee":10,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/273906/7915510103","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afaccaba/e01e4552aa321dbb_b.jpg","GoodsImgCount":"5","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101021264","title":"启功丛稿 论文卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/15897/8530660645","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebfcbfae/f929a4dd9ca3e4b8_b.jpg","GoodsImgCount":"6","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541126628","title":"和气生财","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.39,"price":0.89,"shippingFee":4.5,"differencePrice":-5.39,"GoodsUrl":"https://book.kongfz.com/898393/8830817137","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedbcfde/d399a83aa69886b0_b.jpg","GoodsImgCount":"3","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561716977","title":"天然美容法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.98,"price":6.98,"shippingFee":4,"differencePrice":-10.98,"GoodsUrl":"https://book.kongfz.com/787407/7457083905","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beedbcfc/e65d9aa20e1a0495_b.jpg","GoodsImgCount":"5","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513177245","title":"原生家庭创伤和疗愈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.49,"price":3.49,"shippingFee":5,"differencePrice":-8.49,"GoodsUrl":"https://book.kongfz.com/716746/8530263030","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccaeaddb/d3877c98415ad8ec_b.jpg","GoodsImgCount":"1","onSaleCount":94,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549622993","title":"七种武器 2 碧玉九 多情环 古龙 文汇出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.65,"price":8.65,"shippingFee":4,"differencePrice":-12.65,"GoodsUrl":"https://book.kongfz.com/878042/8892052988","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebfebeff/ee8c98cacf018c9f_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516123911","title":"正学 第1辑 程水金 主编中国社会科学出版社9787516123911","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.3,"price":6.3,"shippingFee":0,"differencePrice":-6.3,"GoodsUrl":"https://book.kongfz.com/248516/8445608487","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/5695f680954765b6_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541541247","title":"白话资治通鉴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.08,"price":4.48,"shippingFee":1.6,"differencePrice":-6.08,"GoodsUrl":"https://book.kongfz.com/457799/8458628865","imgBigUrl":"https://www0.kfzimg.com/G06/M00/DB/5D/p4YBAFqYz9yAHTnOAADftrtdLbw543_b.jpg","GoodsImgCount":"1","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547908471","title":"《增广贤文》行楷硬笔字帖","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.19,"price":18.19,"shippingFee":0,"differencePrice":-18.19,"GoodsUrl":"https://book.kongfz.com/792228/8894526011","imgBigUrl":"https://www0.kfzimg.com/G06/M00/5B/8A/p4YBAFqcjB6AXbWlAACxpMJRAxM805_b.jpg","GoodsImgCount":"1","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806051467","title":"中国当代散文精品大观","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.7,"price":5.7,"shippingFee":5,"differencePrice":-10.7,"GoodsUrl":"https://book.kongfz.com/1207201/8732056718","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fadbdafc/d7ca7a014dc6ecd4_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229011628","title":"数字X线成像技术操作规范与剂量优化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.5,"price":14.5,"shippingFee":2,"differencePrice":-16.5,"GoodsUrl":"https://book.kongfz.com/181222/7301030202","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21084698/936f69f883c7f63f_b.jpg","GoodsImgCount":"1","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030438393","title":"原子物理与量子力学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":19,"shippingFee":6,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/219170/8854670030","imgBigUrl":"https://www0.kfzimg.com/G06/M00/0B/61/p4YBAFqZ--OAGdjqAACto8Azpr0414_b.jpg","GoodsImgCount":"1","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535110008","title":"楚辞文化背景研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/257645/8385818159","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eecbadab/53120eaadf8ddada_b.jpg","GoodsImgCount":"13","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559632340","title":"火:鲁米抒情诗","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.8,"price":14,"shippingFee":5.8,"differencePrice":-19.8,"GoodsUrl":"https://book.kongfz.com/1184610/8732818645","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fefffcdc/ef95dd5ef39a5110_b.jpg","GoodsImgCount":"1","onSaleCount":155,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807592501","title":"孔子家语插图本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.859999999999999,"price":0.06,"shippingFee":4.8,"differencePrice":-4.859999999999999,"GoodsUrl":"https://book.kongfz.com/245306/8519611266","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fedfadef/9ceb5bc75d4c177d_b.jpg","GoodsImgCount":"1","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020131617","title":"弹吧 莫扎特 弹吧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":6.1,"shippingFee":5.6,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/1151143/8891642184","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/debdabbc/1d8c6f57855cbebb_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567530416","title":"大夏书系·我的教育信条","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":3,"shippingFee":7,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/251066/6314429244","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dddbfebd/e08eb5004a5a2688_b.jpg","GoodsImgCount":"6","onSaleCount":149,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508698144","title":"认知尺度","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.14,"price":6.54,"shippingFee":1.6,"differencePrice":-8.14,"GoodsUrl":"https://book.kongfz.com/457799/8340498745","imgBigUrl":"https://www0.kfzimg.com/G07/M00/5D/39/qoYBAFxtK26AJQSTAAEIhLXCEPk917_b.jpg","GoodsImgCount":"1","onSaleCount":168,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108056115","title":"蔡澜作品自选集9:一缕余香","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.76,"price":17.76,"shippingFee":5,"differencePrice":-22.76,"GoodsUrl":"https://book.kongfz.com/640398/8325606114","imgBigUrl":"https://www0.kfzimg.com/G06/M00/92/9B/p4YBAFqeNLeATHCWAACUTSWV7sA518_b.jpg","GoodsImgCount":"1","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534084669","title":"自怡书迹(篆书卷)/黄宾虹书法集粹","quality":0,"qualityText":"","originalPrice":0,"totalPrice":300,"price":290,"shippingFee":10,"differencePrice":-300,"GoodsUrl":"https://book.kongfz.com/668742/7408798391","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eccfdcab/c60bd3db8bb088c3_b.jpg","GoodsImgCount":"1","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500083498","title":"亚洲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.58,"price":23.58,"shippingFee":0,"differencePrice":-23.58,"GoodsUrl":"https://book.kongfz.com/492548/8866390914","imgBigUrl":"https://www0.kfzimg.com/G06/M00/83/39/p4YBAFsp0mWAAVA_AAF056wk3DA841_b.jpg","GoodsImgCount":"1","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787210115472","title":"锁定高端:中小企业的出路【正版 塑封 发货快】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":62.8,"price":52.8,"shippingFee":10,"differencePrice":-62.8,"GoodsUrl":"https://book.kongfz.com/891652/8701830203","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebbfacbc/3f994e3345e47706_b.jpg","GoodsImgCount":"5","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301188378","title":"我要做个好家长:家庭教育的核心理念和操作方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.68,"price":4.68,"shippingFee":0,"differencePrice":-4.68,"GoodsUrl":"https://book.kongfz.com/840504/8515494439","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfdbaebd/c66372e6c229f47e_b.jpg","GoodsImgCount":"8","onSaleCount":101,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550623736","title":"子海精华编:四存编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":11,"shippingFee":5,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/737771/8807102818","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F6/AD/p4YBAFqyPJaAVf3fAABnbpaPYeo653_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539670140","title":"一念永恒6 耳根 安徽文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35.67,"price":30.67,"shippingFee":5,"differencePrice":-35.67,"GoodsUrl":"https://book.kongfz.com/878060/8899600389","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbabfcbb/b37d38ca1a66ebf0_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509716229","title":"社会学之思","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.5,"price":12.5,"shippingFee":6,"differencePrice":-18.5,"GoodsUrl":"https://book.kongfz.com/770286/8333236126","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeefbcb/2d1619b6ae1c99c7_b.jpg","GoodsImgCount":"10","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800735912","title":"最大化你的自尊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.88,"price":4.38,"shippingFee":3.5,"differencePrice":-7.88,"GoodsUrl":"https://book.kongfz.com/819139/8780150484","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbcbafcf/16ff682d72d85325_b.jpg","GoodsImgCount":"5","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117117968","title":"一病一页速成系列·症状与体征(翻译版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":30,"shippingFee":5,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/244916/7672342792","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcbafce/36e348e3b2781add_b.jpg","GoodsImgCount":"5","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503419843","title":"国民党将领谈国共大决战:战场较量","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.16,"price":8.66,"shippingFee":1.5,"differencePrice":-10.16,"GoodsUrl":"https://book.kongfz.com/774690/8698048698","imgBigUrl":"https://www0.kfzimg.com/G06/M00/90/C0/p4YBAFqnIWGAZPmWAACgYFH2BdA325_b.jpg","GoodsImgCount":"1","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535437822","title":"谈美书简:大家文论经典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.89,"price":0.09,"shippingFee":4.8,"differencePrice":-4.89,"GoodsUrl":"https://book.kongfz.com/780405/7794576703","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bebffdbd/621954b1d9ca687b_b.jpg","GoodsImgCount":"4","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511708991","title":"光明大手印:实修心髓(下卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/271386/8128810121","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdeefdfc/812225588f075059_b.jpg","GoodsImgCount":"6","onSaleCount":172,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512516236","title":"等我·遇繁","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.2,"price":8.2,"shippingFee":2,"differencePrice":-10.2,"GoodsUrl":"https://book.kongfz.com/545601/8868078177","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdedecc/1f05c7eabb2dae12_b.jpg","GoodsImgCount":"2","onSaleCount":255,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501255726","title":"与爱有关 1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.779999999999999,"price":3.28,"shippingFee":1.5,"differencePrice":-4.779999999999999,"GoodsUrl":"https://book.kongfz.com/772556/8042035571","imgBigUrl":"https://www0.kfzimg.com/G06/M00/37/61/p4YBAFqbSJeAI6TRAAC8PL7kUTA655_b.jpg","GoodsImgCount":"1","onSaleCount":125,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806845394","title":"第三届全国会计知识大赛法规汇编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2.5,"shippingFee":4.5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/285622/5472130653","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfaccbbc/877daef6e53689dc_b.jpg","GoodsImgCount":"3","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545823349","title":"中国城市轨道交通年鉴2023","quality":0,"qualityText":"","originalPrice":0,"totalPrice":88,"price":80,"shippingFee":8,"differencePrice":-88,"GoodsUrl":"https://book.kongfz.com/15878/8635018981","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdbbefdf/7203761aa85bddbe_b.jpg","GoodsImgCount":"7","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520206716","title":"故宫里的大怪兽 木之精灵","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":0.5,"shippingFee":4.5,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/531994/8811950065","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daddabbc/19753635be32a51a_b.jpg","GoodsImgCount":"1","onSaleCount":176,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806960325","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515307497","title":"结构与明暗 素描几何形体单体训练","quality":0,"qualityText":"","originalPrice":0,"totalPrice":60,"price":50,"shippingFee":10,"differencePrice":-60,"GoodsUrl":"https://book.kongfz.com/28297/8404195016","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aacefaab/a69030f0b920a813_b.jpg","GoodsImgCount":"4","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113253271","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539169903","title":"怪杰佐罗力之魔法师的弟子","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":4.4,"shippingFee":2.5,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/782278/8853393863","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdcecfc/7a4f8f77be4872f0_b.jpg","GoodsImgCount":"4","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505411937","title":"东风破","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.65,"price":2.25,"shippingFee":2.4,"differencePrice":-4.65,"GoodsUrl":"https://book.kongfz.com/692223/8848001982","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeabbada/18d4a6e00b5282e5_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540776886","title":"极简黄河史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.899999999999999,"price":5.3,"shippingFee":5.6,"differencePrice":-10.899999999999999,"GoodsUrl":"https://book.kongfz.com/1151143/8749172406","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbfaddcc/1c4188e8273e071e_b.jpg","GoodsImgCount":"2","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801432322","title":"中国的危机 下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.7,"price":0.7,"shippingFee":5,"differencePrice":-5.7,"GoodsUrl":"https://book.kongfz.com/1207201/8732160973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bffaacfd/55b5e6a712210d46_b.jpg","GoodsImgCount":"1","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522511986","title":"心知肚明9787522511986","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.32,"price":26.32,"shippingFee":4,"differencePrice":-30.32,"GoodsUrl":"https://book.kongfz.com/655396/8896033621","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9868355/0c51063e3a790f70_b.jpg","GoodsImgCount":"1","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508668680","title":"理性的非理性:人人都需要的十堂营销心理课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":10.2,"shippingFee":4.8,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/22176/8708259911","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F1/A6/p4YBAFqZN7eAT8t7AADm2HMJsK8866_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545428117","title":"《市场赢家生存智慧》丛书·高级波段交易:预期、确认、交易期货市场波段的交易策略","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40,"price":35,"shippingFee":5,"differencePrice":-40,"GoodsUrl":"https://book.kongfz.com/806881/8791937670","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdeafbbd/4a7a74100aaf4936_b.jpg","GoodsImgCount":"9","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532757060","title":"培根随笔全集培根","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":7,"shippingFee":0,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/576646/8248968682","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faeebaaf/5aedb15807c176ce_b.jpg","GoodsImgCount":"1","onSaleCount":89,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507322910","title":"中国“三农”问题研究(下)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.9,"price":14,"shippingFee":7.9,"differencePrice":-21.9,"GoodsUrl":"https://book.kongfz.com/266593/8514771412","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edefdaad/eefd5c7965a65e96_b.jpg","GoodsImgCount":"1","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806456095","title":"旋风再起林志颖","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.990000000000002,"price":13.99,"shippingFee":3,"differencePrice":-16.990000000000002,"GoodsUrl":"https://book.kongfz.com/525062/7952933376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffccdbfb/d89b4ebf5e73be91_b.jpg","GoodsImgCount":"4","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519882723","title":"综合能源服务百家实践案例集(2023年版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":95,"price":88,"shippingFee":7,"differencePrice":-95,"GoodsUrl":"https://book.kongfz.com/363535/8017764796","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efbbfadc/fb12de80869054a3_b.jpg","GoodsImgCount":"3","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514367324","title":"【正版二手,当日发货,所见即所得】直指生命的真相","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25.5,"price":15.5,"shippingFee":10,"differencePrice":-25.5,"GoodsUrl":"https://book.kongfz.com/314591/8873898618","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbaeadba/ce7c89c2b3d883b0_b.jpg","GoodsImgCount":"2","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561367186","title":"道德经的奥秘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/327097/8898096706","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daededeb/4052728ffcad3402_b.jpg","GoodsImgCount":"11","onSaleCount":261,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020033232","title":"人有病 :一九四九年后中国文坛纪实","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":2,"shippingFee":15,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/702376/8574002491","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdcbfbed/8f994a0ce4511fd7_b.jpg","GoodsImgCount":"9","onSaleCount":146,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546343815","title":"鲁迅经典文集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":1,"shippingFee":3,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/832065/8677403155","imgBigUrl":"https://www0.kfzimg.com/G06/M00/8F/2B/p4YBAFrJk8GAcBv1AAD2D_aSEjw105_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302611257","title":"趣味数学300题","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.34,"price":23.14,"shippingFee":3.2,"differencePrice":-26.34,"GoodsUrl":"https://book.kongfz.com/739740/8455964241","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabaadee/c56a8a360873d9bf_b.jpg","GoodsImgCount":"4","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515341132","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556073115","title":"李毓佩数学故事智斗系列·数学小子杜鲁克","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.54,"price":6.54,"shippingFee":0,"differencePrice":-6.54,"GoodsUrl":"https://book.kongfz.com/196857/8660963953","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E2/9B/p4YBAFskolqAGC7PAAD-YhhDpOQ512_b.jpg","GoodsImgCount":"1","onSaleCount":99,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805926230","title":"心香泪酒祭吴宓","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.4,"price":2.4,"shippingFee":5,"differencePrice":-7.4,"GoodsUrl":"https://book.kongfz.com/1207077/8774008733","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bceafceb/e6e84c0a6968bedb_b.jpg","GoodsImgCount":"1","onSaleCount":167,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513919159","title":"万物简史 布森特 民主与建设出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.1,"price":2.1,"shippingFee":5,"differencePrice":-7.1,"GoodsUrl":"https://book.kongfz.com/180897/8769178321","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdabbaee/25c282fef18ab380_b.jpg","GoodsImgCount":"1","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787107274169","title":"数学 八年级下 教师教学用书 9787107274169","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.8,"price":6.3,"shippingFee":4.5,"differencePrice":-10.8,"GoodsUrl":"https://book.kongfz.com/1121890/8881703556","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcabafca/a28f75df568c2578_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534607820","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534237003","title":"童年的云彩——冰心儿童文学新作奖获奖作者丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3100000000000005,"price":1.42,"shippingFee":2.89,"differencePrice":-4.3100000000000005,"GoodsUrl":"https://book.kongfz.com/826403/8655659602","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fefdbaec/0ac8ce22befd9b77_b.jpg","GoodsImgCount":"2","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807256465","title":"交通银行史画 中英文本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36,"price":31,"shippingFee":5,"differencePrice":-36,"GoodsUrl":"https://book.kongfz.com/766980/8311121800","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eecbbcfc/36be02eef1c632ec_b.jpg","GoodsImgCount":"1","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546122649","title":"中国文化源与流X-GM","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":7.2,"shippingFee":4.5,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/473622/8709248209","imgBigUrl":"https://www0.kfzimg.com/G06/M00/17/08/p4YBAFsYv3KASa21AAB3m2dwVTA494_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535657886","title":"绯弹的亚里亚.3.蜂蜜色陷阱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.5,"price":12.9,"shippingFee":1.6,"differencePrice":-14.5,"GoodsUrl":"https://book.kongfz.com/464363/8082360131","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1303/f3ae13fed07610a2_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516100158","title":"当代中国简帛学研究:1949-2009","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.6,"price":13.6,"shippingFee":5,"differencePrice":-18.6,"GoodsUrl":"https://book.kongfz.com/285265/8420474812","imgBigUrl":"https://www0.kfzimg.com/G06/M00/09/94/p4YBAFqiQTqAfU-fAAB8biLxNVg251_b.jpg","GoodsImgCount":"0","onSaleCount":89,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562153719","title":"数字媒体艺术设计概论谢成开西南师范大学出版社9787562153719","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.98,"price":3.98,"shippingFee":0,"differencePrice":-3.98,"GoodsUrl":"https://book.kongfz.com/366030/8389757114","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/ab8853cb8613e942_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507744088","title":"中医儿科杂病调治 临床验案心得","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.4,"price":8.4,"shippingFee":5,"differencePrice":-13.4,"GoodsUrl":"https://book.kongfz.com/1146983/8731284798","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccabaeea/bec4a3f3ca202604_b.jpg","GoodsImgCount":"1","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562491927","title":"焦虑症和恐惧症:一种认知的观点","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/722553/8053935000","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbbbefb/06a98a8307a77647_b.jpg","GoodsImgCount":"10","onSaleCount":113,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787215063983","title":"人学的科学之路","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":38,"shippingFee":10,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/677747/5525845992","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebefffaa/2aae35f9a9c3c119_b.jpg","GoodsImgCount":"3","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540736590","title":"《发货快》冰心作品精编 冰心 著,卓如 选编 漓江出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.29,"price":4.29,"shippingFee":0,"differencePrice":-4.29,"GoodsUrl":"https://book.kongfz.com/156492/8477626078","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4362605/2b017963221ae54e_b.jpg","GoodsImgCount":"1","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559602589","title":"*超脑/团灭","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.8,"price":11.9,"shippingFee":3.9,"differencePrice":-15.8,"GoodsUrl":"https://book.kongfz.com/622913/8781293258","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1C/A7/p4YBAFqaPyaASO8OAADjaotTI2g047_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509209028","title":"节能技术(一)(二)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.04,"price":3.04,"shippingFee":5,"differencePrice":-8.04,"GoodsUrl":"https://book.kongfz.com/821188/8009266743","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcbddaa/4441735d2fc83d12_b.jpg","GoodsImgCount":"4","onSaleCount":53,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787557614034","title":"糖尿病调养三部曲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.93,"price":5.93,"shippingFee":3,"differencePrice":-8.93,"GoodsUrl":"https://book.kongfz.com/364423/8154767176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11281955/b1d32f99f88a512f_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807429777","title":"黄庭禅","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40,"price":33,"shippingFee":7,"differencePrice":-40,"GoodsUrl":"https://book.kongfz.com/251066/8876471272","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbbcafe/cc28a29941eab7d3_b.jpg","GoodsImgCount":"8","onSaleCount":74,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111385479","title":"管理者每天读点韩非子","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.4,"price":14.4,"shippingFee":5,"differencePrice":-19.4,"GoodsUrl":"https://book.kongfz.com/1207201/8642575748","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edfbaeff/3799b38ac41be0c2_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787313270368","title":"初中英语语法专练 大字版 知识点梳理 全国 中学英语专练百分百","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.11,"price":12.61,"shippingFee":1.5,"differencePrice":-14.11,"GoodsUrl":"https://book.kongfz.com/772556/7933482079","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10317333/28422663cee46d73_b.jpg","GoodsImgCount":"1","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121357961","title":"HTML+CSS+JavaScript编程从入门到精通 html5+css3基础自学教程web前端开发 网站网页前端设计制作建设","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":3.8,"shippingFee":0,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/590687/8602236711","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/578/6f71cebe6e2fe3c2_b.jpg","GoodsImgCount":"1","onSaleCount":149,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553646091","title":"新东方 直通托福基础教程 写作教育科技集团美国本科考试研究院浙江教育出版社9787553646091","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3,"price":4.3,"shippingFee":0,"differencePrice":-4.3,"GoodsUrl":"https://book.kongfz.com/248516/8440860798","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/7c0909d9fac80f7c_b.jpg","GoodsImgCount":"1","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519777418","title":"国家公诉人出庭指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":107.9,"price":99.9,"shippingFee":8,"differencePrice":-107.9,"GoodsUrl":"https://book.kongfz.com/218476/8455920813","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcbfaae/2f5ea8d721d8f099_b.jpg","GoodsImgCount":"8","onSaleCount":97,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535396464","title":"赛尔号精灵传说第二季5女神的愤怒","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.2,"price":1.2,"shippingFee":3,"differencePrice":-4.2,"GoodsUrl":"https://book.kongfz.com/902124/8232461903","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abacdfca/24cae20760f51e8c_b.jpg","GoodsImgCount":"4","onSaleCount":128,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508251738","title":"跌打损伤偏方验方疗法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":11,"shippingFee":9,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/879205/8386867884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadcbdeb/d46616aff116f328_b.jpg","GoodsImgCount":"4","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810971843","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539673882","title":"诡秘之主 10","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36,"price":30,"shippingFee":6,"differencePrice":-36,"GoodsUrl":"https://book.kongfz.com/738944/8666813116","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebebefcf/5b8c2f0af154a990_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550217454","title":"上帝掷骰子吗?:量子物理史话","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/522252/8881101832","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcedbffe/3bc31a21a55e85fe_b.jpg","GoodsImgCount":"10","onSaleCount":535,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533196677","title":"颞下颌关节外科手术图谱【未开封】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":40,"shippingFee":8,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/20113/8708722394","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2368075/5cc59fca61418e15_b.jpg","GoodsImgCount":"6","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545581447","title":"特工小品 小品绘著 天地出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.6,"price":3.6,"shippingFee":4,"differencePrice":-7.6,"GoodsUrl":"https://book.kongfz.com/878042/8780122369","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aabdbfaf/4c6e809d5f8ac283_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520717281","title":"基层中国:国家治理的基石","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/836297/8270087899","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecbffbbb/e7eba40da48936ea_b.jpg","GoodsImgCount":"5","onSaleCount":221,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503971549","title":"流动的博物馆李德庚9787503971549文化艺术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.6,"price":34.1,"shippingFee":5.5,"differencePrice":-39.6,"GoodsUrl":"https://book.kongfz.com/405080/7310559973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddbfdca/ddfaa51954478712_b.jpg","GoodsImgCount":"1","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301233009","title":"中外物理学精品书系·前沿系列:从抛物线谈起(混沌动力学引论)(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/785604/8009702581","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eefaffee/c4ebf23f89793c3e_b.jpg","GoodsImgCount":"9","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040150780","title":"高中新课程老师教育系列教材:高中音乐新课程教学论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39,"price":30,"shippingFee":9,"differencePrice":-39,"GoodsUrl":"https://book.kongfz.com/233641/6012616143","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdcedcd/c986845d3a146f0c_b.jpg","GoodsImgCount":"18","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508229942","title":"偏方验方治病丛书:胃病偏方验方疗法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/10563/4619429987","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbebdbef/fde06ecabc17f303_b.jpg","GoodsImgCount":"4","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802282452","title":"寒武纪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.4,"price":0.4,"shippingFee":3,"differencePrice":-3.4,"GoodsUrl":"https://book.kongfz.com/884527/8123402741","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfcebaeb/45e505eaf81204fa_b.jpg","GoodsImgCount":"4","onSaleCount":295,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501170388","title":"42部文学名著导读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":3.1,"shippingFee":5,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/700512/8535927223","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbcfbba/7b00d27ca9cbaa29_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516641590","title":"电信诈骗话语模式解读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":12,"shippingFee":5,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/758933/8311513802","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbdaabbc/85b378309fc2d5cf_b.jpg","GoodsImgCount":"2","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508679327","title":"会动的立体小汽车 超级工程车","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.03,"price":15.23,"shippingFee":2.8,"differencePrice":-18.03,"GoodsUrl":"https://book.kongfz.com/1093663/8881837238","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aedffeab/2fc4c6c70426a7cc_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302451402","title":"四川重庆古建筑地图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":132,"price":124,"shippingFee":8,"differencePrice":-132,"GoodsUrl":"https://book.kongfz.com/750186/6510117695","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accbaafc/7966d331b607474d_b.jpg","GoodsImgCount":"2","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560078403","title":"韩国语基础教程4 学生用书韩国西江大学韩国语教育院 著外语教学与研究出版社9787560078403","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.88,"price":4.88,"shippingFee":0,"differencePrice":-4.88,"GoodsUrl":"https://book.kongfz.com/366030/8432554732","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/8c0716368a76c0e7_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802551268","title":"财务报表就像一本故事书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/3092/8441875353","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbafffed/53bad65e508c1600_b.jpg","GoodsImgCount":"5","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564345402","title":"铁路线路与站场","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.9,"price":20.9,"shippingFee":9,"differencePrice":-29.9,"GoodsUrl":"https://book.kongfz.com/900492/8399542894","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23095665/8f6596c31f51ae90_b.jpg","GoodsImgCount":"1","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802543416","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562476443","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513330251","title":"变色龙马克斯","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.52,"price":3.52,"shippingFee":5,"differencePrice":-8.52,"GoodsUrl":"https://book.kongfz.com/716746/8573685578","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efcbddac/009ecce6718456e3_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101115253","title":"古钱极品/中国钱币丛书乙种本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":32,"shippingFee":11,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/23380/8891015518","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaadefed/cc33c8659337be72_b.jpg","GoodsImgCount":"6","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531327493","title":"我恋爱 我容易吗 二手书实拍图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.27,"price":1.77,"shippingFee":5.5,"differencePrice":-7.27,"GoodsUrl":"https://book.kongfz.com/898097/8767090319","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcafceed/ae1ea8b5b115d524_b.jpg","GoodsImgCount":"2","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539198675","title":"我要炼出黄金","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.61,"price":0.11,"shippingFee":2.5,"differencePrice":-2.61,"GoodsUrl":"https://book.kongfz.com/903233/8497337794","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbaedeaf/04d5fa349cc307a6_b.jpg","GoodsImgCount":"7","onSaleCount":405,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117333016","title":"颞下颌关节紊乱病临床诊疗解析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":86.4,"price":77,"shippingFee":9.4,"differencePrice":-86.4,"GoodsUrl":"https://book.kongfz.com/755104/8486452382","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdbcdef/cd8b52f5f18d0870_b.jpg","GoodsImgCount":"11","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533547981","title":"传世中医秘方","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":9,"shippingFee":3,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/566350/8858398045","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edcddbdb/e499acd32b9e1737_b.jpg","GoodsImgCount":"12","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547277898","title":"谭延闿临麻姑仙坛记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":47.35,"price":41.35,"shippingFee":6,"differencePrice":-47.35,"GoodsUrl":"https://book.kongfz.com/533712/7445542462","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdacdfcc/747808d442d68dbd_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122168108","title":"伟大的声音 演讲的力量 高温消毒发货 俞敏洪编 化学工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.199999999999996,"price":35.4,"shippingFee":1.8,"differencePrice":-37.199999999999996,"GoodsUrl":"https://book.kongfz.com/110/8696450340","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffdfacdf/23cd709fa1189c02_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565834691","title":"做最好的自己【全新】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.5,"price":0.5,"shippingFee":3,"differencePrice":-3.5,"GoodsUrl":"https://book.kongfz.com/241879/8585409526","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9187761/e00b22696eefd681_b.jpg","GoodsImgCount":"1","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115558534","title":"我的世界 年鉴2021","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":10,"shippingFee":7,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/696405/6634553010","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afccacdb/d9bfc72e1eb7dc88_b.jpg","GoodsImgCount":"10","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122185471","title":"电子电工技术全图解全集:PLC技术·变频技术速成全图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/760233/6672966429","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfcccaa/b1d730a43c135807_b.jpg","GoodsImgCount":"5","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800471193","title":"紫禁城的黄昏","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":10,"shippingFee":9,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/17163/6977347845","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afedfdcf/0e2cef314cfd9a14_b.jpg","GoodsImgCount":"3","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787574108943","title":"中国古代服饰结构图集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.5,"price":34.5,"shippingFee":7,"differencePrice":-41.5,"GoodsUrl":"https://book.kongfz.com/633822/8836490919","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5126996/a3aa257bc59f9af3_b.jpg","GoodsImgCount":"1","onSaleCount":168,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531004691","title":"邓散木印集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/189253/924912293","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1E/7D/p4YBAFsmYxmAEyJlAAKI5tlWFsM222_b.jpg","GoodsImgCount":"6","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500060833","title":"华罗庚学校初中物理试题解析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/690706/8016636203","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfcaabfb/9f3293f6168eadfd_b.jpg","GoodsImgCount":"10","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539753775","title":"北极熊王:中外动物小说精品","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/437976/8801246014","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbbdecbc/3ca925e159754de4_b.jpg","GoodsImgCount":"2","onSaleCount":140,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547722091","title":"地道英文写作进阶:外刊实用短语句型精选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":57,"price":57,"shippingFee":0,"differencePrice":-57,"GoodsUrl":"https://book.kongfz.com/356195/8896018285","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/c3ee7195f7455908_b.jpg","GoodsImgCount":"6","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302165309","title":"电子商务网站建设实验指导","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.93,"price":13.93,"shippingFee":10,"differencePrice":-23.93,"GoodsUrl":"https://book.kongfz.com/885269/8596565983","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D6/B2/p4YBAFqYvI-ADYiFAAC7RDvbnYE984_b.jpg","GoodsImgCount":"1","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538899429","title":"家有小学生的营养早餐","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.28,"price":0.5,"shippingFee":2.78,"differencePrice":-3.28,"GoodsUrl":"https://book.kongfz.com/785333/8671961291","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdacedec/7f7eb8b6035a3c34_b.jpg","GoodsImgCount":"1","onSaleCount":439,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010086798","title":"家庭文化学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/462357/8563912467","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbebcedf/9544c30b47cda303_b.jpg","GoodsImgCount":"11","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806862339","title":"大画幅摄影","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.85,"price":7.35,"shippingFee":1.5,"differencePrice":-8.85,"GoodsUrl":"https://book.kongfz.com/701775/8774482003","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfdbeabb/07a9faf8ce7aaefc_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572501159","title":"儿童和青少年普拉提 英 切莱斯特 科里 索菲奇 Celeste Corey Zopich 布雷特 霍华德 Brett Howard 道恩玛丽 伊克斯 Dawn Marie Ickes 主编 河南科学技术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.65,"price":15.65,"shippingFee":5,"differencePrice":-20.65,"GoodsUrl":"https://book.kongfz.com/903313/8867129101","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbaecdae/9a66480f20211491_b.jpg","GoodsImgCount":"1","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514222944","title":"洞见 赵昂 文化发展出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.4,"price":1.4,"shippingFee":5,"differencePrice":-6.4,"GoodsUrl":"https://book.kongfz.com/398369/8756316997","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abebbffb/38c9650f51d3487e_b.jpg","GoodsImgCount":"1","onSaleCount":146,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117263764","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787119079493","title":"吃喝玩乐超实用英语会话一本通 希伯伦股份有限公司编 外文出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":4.8,"shippingFee":5,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/180897/8441994084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afffeeaa/477bc761e5ae81c2_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502615178","title":"百战狐狸:职业机构实战操盘讲义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.77,"price":1.27,"shippingFee":5.5,"differencePrice":-6.77,"GoodsUrl":"https://book.kongfz.com/250120/8708646976","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dabebaeb/c9eea535bcbe11db_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561126028","title":"高等学校理工科物理类规划教材:量子力学(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":13,"shippingFee":7,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/217161/6851259518","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbceffdb/21857aa37ee9847a_b.jpg","GoodsImgCount":"4","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787554174623","title":"初一预习视频课英语","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9799999999999995,"price":4.18,"shippingFee":3.8,"differencePrice":-7.9799999999999995,"GoodsUrl":"https://book.kongfz.com/237705/8613570433","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafdfaeb/241850ced0e78c1a_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513533140","title":"英语. 二年级. 上册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.9899999999999998,"price":0.01,"shippingFee":2.98,"differencePrice":-2.9899999999999998,"GoodsUrl":"https://book.kongfz.com/840438/8166411046","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfafdbea/d633d70cee3e5f71_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121436604","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518440917","title":"读醉:宁夏酒庄指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":20,"shippingFee":0,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/10991/8852891015","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addfbadb/e166df1a5914a696_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514507799","title":"斗破苍穹(23)一版一印","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9,"price":0.9,"shippingFee":3,"differencePrice":-3.9,"GoodsUrl":"https://book.kongfz.com/668354/7024201760","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bacbcdcf/c0b24ea31449a10b_b.jpg","GoodsImgCount":"4","onSaleCount":243,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558902406","title":"不一样的圣诞节 达妮拉库洛特,方素珍 少年儿童出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":5.1,"shippingFee":3,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/521005/8337317394","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1B/43/p4YBAFqaO6-ADWX-AACLI7p96U4392_b.jpg","GoodsImgCount":"1","onSaleCount":117,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800420313","title":"难经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":65.9,"price":59.9,"shippingFee":6,"differencePrice":-65.9,"GoodsUrl":"https://book.kongfz.com/169274/8450740779","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbefdeb/17dce85a175b8604_b.jpg","GoodsImgCount":"4","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504747914","title":"王敬之讲田黄 9787504747914 王敬之 著 中国物资出版社 有疑问咨询客服","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.65,"price":12.65,"shippingFee":4,"differencePrice":-16.65,"GoodsUrl":"https://book.kongfz.com/790574/8853963934","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abbddeec/2595703d5b185aa7_b.jpg","GoodsImgCount":"1","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558911934","title":"海豚绘本花园:一家好认真好认真的餐厅","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.51,"price":10.91,"shippingFee":1.6,"differencePrice":-12.51,"GoodsUrl":"https://book.kongfz.com/470338/8091876352","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/16223501/d0ac2cf21ff67db3_b.jpg","GoodsImgCount":"0","onSaleCount":70,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121363634","title":"我超喜欢的趣味数学书 小学四年级 第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.59,"price":6.19,"shippingFee":2.4,"differencePrice":-8.59,"GoodsUrl":"https://book.kongfz.com/692223/8853556029","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adffadfd/7fc165d6fe4fbb20_b.jpg","GoodsImgCount":"1","onSaleCount":139,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509222133","title":"房地产企业全程会计核算与税务处理(第六版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":56,"price":50,"shippingFee":6,"differencePrice":-56,"GoodsUrl":"https://book.kongfz.com/520656/7331763806","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfcdfed/66caec80f6229f38_b.jpg","GoodsImgCount":"4","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510226991","title":"十大业务系列教材——职务犯罪检察业务","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":40,"shippingFee":8,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/584570/8436769476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdeafad/895dbfc10f7deb10_b.jpg","GoodsImgCount":"14","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810756075","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567597013","title":"大夏书系·教育的100种语言:丹麦教育见闻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.5,"price":10,"shippingFee":4.5,"differencePrice":-14.5,"GoodsUrl":"https://book.kongfz.com/585799/8333731294","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14917819/d342c68268bd6844_b.jpg","GoodsImgCount":"5","onSaleCount":90,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506749145","title":"医学衷中参西录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":50,"price":40,"shippingFee":10,"differencePrice":-50,"GoodsUrl":"https://book.kongfz.com/730822/8433255540","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/facdecbd/5cc0c5684378b427_b.jpg","GoodsImgCount":"5","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111288954","title":"供应链物流管理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.1,"price":4.1,"shippingFee":0,"differencePrice":-4.1,"GoodsUrl":"https://book.kongfz.com/733352/8279417108","imgBigUrl":"https://www0.kfzimg.com/G06/M00/58/FA/p4YBAFqcKLyANGCJAAErWD_1er4153_b.jpg","GoodsImgCount":"1","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214287892","title":"海外中国研究丛书·艺术系列 《中正之笔:颜真卿书法与宋代文人政治》赠包","quality":0,"qualityText":"","originalPrice":0,"totalPrice":60.08,"price":60.08,"shippingFee":0,"differencePrice":-60.08,"GoodsUrl":"https://book.kongfz.com/457799/8830585867","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/15505652/82c39efb161a5c45_b.jpg","GoodsImgCount":"1","onSaleCount":117,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501256730","title":"教育就是培养好习惯","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":1.3,"shippingFee":2,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/667558/8863965946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baadebdb/b72ce315488f2b9f_b.jpg","GoodsImgCount":"1","onSaleCount":431,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111326793","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540484958","title":"人类群星闪耀时","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.02,"price":5.42,"shippingFee":1.6,"differencePrice":-7.02,"GoodsUrl":"https://book.kongfz.com/457799/8321235881","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F7/BA/p4YBAFqhnLeANWRTAABg9lSn2Ks131_b.jpg","GoodsImgCount":"1","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556869824","title":"大中华寻宝系列26 新疆寻宝记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.5,"price":6.5,"shippingFee":5,"differencePrice":-11.5,"GoodsUrl":"https://book.kongfz.com/697065/8817518628","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdeffed/4edad2afd5490255_b.jpg","GoodsImgCount":"3","onSaleCount":193,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535429704","title":"少年天子 凌力著 长江文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.99,"price":4.99,"shippingFee":5,"differencePrice":-9.99,"GoodsUrl":"https://book.kongfz.com/1146983/8811740152","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcddced/5334a2f79e1bd2da_b.jpg","GoodsImgCount":"1","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532560868","title":"贾题韬讲坛经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/23153/8780563654","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/effabcae/0243a97a1d72ba14_b.jpg","GoodsImgCount":"15","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507535198","title":"暮色紫禁城 洋帝师眼中的溥仪与近代中国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.25,"price":2.85,"shippingFee":2.4,"differencePrice":-5.25,"GoodsUrl":"https://book.kongfz.com/692223/8222719769","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eabfeccd/807382cae33649cd_b.jpg","GoodsImgCount":"1","onSaleCount":175,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303086641","title":"说话的力量【封面几层书页有被顶破小洞】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":7,"shippingFee":7,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/211464/7174616446","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdceddbd/482a0066db3d5e28_b.jpg","GoodsImgCount":"9","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100034975","title":"美洲三书 扉页有水渍","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/12142/6630865417","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdedcae/cf96f3bd07d5c0df_b.jpg","GoodsImgCount":"7","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506449045","title":"开·合:纽扣拉链的连接艺术(书页干净无笔画。)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/273362/2564607312","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2593/022091c08a2390131d_b.jpg","GoodsImgCount":"4","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302364832","title":"国际物流黄新祥 等主编清华大学出版社9787302364832","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":0.5,"shippingFee":4,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/420387/8678386948","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/12298542/57d47de2dbc7168d_b.jpg","GoodsImgCount":"1","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302025207","title":"实用软件工程 第二版郑人杰等 编著清华大学出版社9787302025207","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.75,"price":3.75,"shippingFee":0,"differencePrice":-3.75,"GoodsUrl":"https://book.kongfz.com/366030/8275536127","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/e72b7e2e2cfde181_b.jpg","GoodsImgCount":"1","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208164208","title":"正版新书现货 宏观航运经济学 9787208164208 (希) 伊莱亚斯·卡拉基索斯, 兰布罗斯·瓦纳维兹著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31.26,"price":26.26,"shippingFee":5,"differencePrice":-31.26,"GoodsUrl":"https://book.kongfz.com/1181534/8500474938","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffaaddac/39f58d121b1b8db4_b.jpg","GoodsImgCount":"1","onSaleCount":67,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533951610","title":"吉姆:吉卜林作品(精装本)2018年1版1印","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.5,"price":25.5,"shippingFee":2,"differencePrice":-27.5,"GoodsUrl":"https://book.kongfz.com/1996/8650425365","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecedaeee/da61038dbe97ad9c_b.jpg","GoodsImgCount":"3","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801739261","title":"秦书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":50,"price":46,"shippingFee":4,"differencePrice":-50,"GoodsUrl":"https://book.kongfz.com/521036/8800425189","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbdafec/d093e26f8cc2c73f_b.jpg","GoodsImgCount":"8","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500690696","title":"边城","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.1,"price":4.1,"shippingFee":0,"differencePrice":-4.1,"GoodsUrl":"https://book.kongfz.com/880899/8678253491","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeedabd/1c5c446cb92761b3_b.jpg","GoodsImgCount":"2","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787570110940","title":"小学生叙事作文 思维导图作文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":1.5,"shippingFee":3,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/783956/8818428031","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffccbfba/91f578f8e6cdd416_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535295439","title":"张景中科普文集:漫话数学(精装典藏版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.84,"price":10.44,"shippingFee":4.4,"differencePrice":-14.84,"GoodsUrl":"https://book.kongfz.com/321650/8279680042","imgBigUrl":"https://www0.kfzimg.com/G06/M00/FE/71/p4YBAFqZclaARCtwAACby3byH0g317_b.jpg","GoodsImgCount":"1","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810462761","title":"大学英语精读-(3)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.14,"price":0.14,"shippingFee":3,"differencePrice":-3.14,"GoodsUrl":"https://book.kongfz.com/1092190/8867494474","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeefbab/adc884da026a2cc7_b.jpg","GoodsImgCount":"1","onSaleCount":257,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544678667","title":"大学英语基础口语教程 3(第2版)学生用书(附光盘)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.14,"price":26.14,"shippingFee":6,"differencePrice":-32.14,"GoodsUrl":"https://book.kongfz.com/444647/8628763673","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dffafdeb/aafce3d1f21adfff_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801567048","title":"中西医结合精神病学/新世纪全国高等医药院校规划教材","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31,"price":31,"shippingFee":0,"differencePrice":-31,"GoodsUrl":"https://book.kongfz.com/698100/8721476824","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceccdbbc/cad5c1ae98d17471_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787576049688","title":"奥数教程 六年级","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.17,"price":20.37,"shippingFee":3.8,"differencePrice":-24.17,"GoodsUrl":"https://book.kongfz.com/624030/8505456371","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4893319/c0ed3496e5c5bbb6_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805183671","title":"晚清小说史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":9,"shippingFee":10,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/179226/7693867371","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbdceed/20efe77062ee6a6f_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500909514","title":"中国武术人名辞典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37,"price":29,"shippingFee":8,"differencePrice":-37,"GoodsUrl":"https://book.kongfz.com/204356/7119094838","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdbdcadd/acc1900622c92670_b.jpg","GoodsImgCount":"7","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533003395","title":"武氏祠汉画像石","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":30,"shippingFee":13,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/24485/304549598","imgBigUrl":"https://www0.kfzimg.com/G03/M01/A0/E8/pYYBAFStYTyAK1C2AAElEuFY5XY899_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200120837","title":"大家小书 中国古代衣食住行","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":6,"shippingFee":4,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/20902/8727045221","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdbdccf/b167e6589d0bbda4_b.jpg","GoodsImgCount":"2","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564071028","title":"蒙台梭利早教方案:0-3岁智力及语言系统训练全书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8600000000000003,"price":1.86,"shippingFee":2,"differencePrice":-3.8600000000000003,"GoodsUrl":"https://book.kongfz.com/624177/8228419387","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadbfcaf/dd1d18ccaac06855_b.jpg","GoodsImgCount":"3","onSaleCount":540,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115602763","title":"孕期冥想心理课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.04,"price":13.04,"shippingFee":2,"differencePrice":-15.04,"GoodsUrl":"https://book.kongfz.com/738826/8492472031","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbbfecda/4b467c05a7ff0e49_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787202025154","title":"河北通史 民国上卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.11,"price":13.11,"shippingFee":5,"differencePrice":-18.11,"GoodsUrl":"https://book.kongfz.com/1154627/8790091931","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafcfaad/346ccaf3ae2ecc3e_b.jpg","GoodsImgCount":"2","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117139618","title":"中药名方现代研究与应用·四物汤现代研究与应用","quality":0,"qualityText":"","originalPrice":0,"totalPrice":73.77,"price":69.27,"shippingFee":4.5,"differencePrice":-73.77,"GoodsUrl":"https://book.kongfz.com/792669/7996883998","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecacccb/cabb099d4ffa62eb_b.jpg","GoodsImgCount":"2","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200131475","title":"向解放军学习有效率组织的管理之道精编版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.14,"price":3.64,"shippingFee":4.5,"differencePrice":-8.14,"GoodsUrl":"https://book.kongfz.com/884575/8886801797","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdcabfd/c4649fe683ed4712_b.jpg","GoodsImgCount":"1","onSaleCount":335,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569912883","title":"雪球帮:为什么世界是今天这样的?","quality":0,"qualityText":"","originalPrice":0,"totalPrice":93,"price":90,"shippingFee":3,"differencePrice":-93,"GoodsUrl":"https://book.kongfz.com/889351/8359062152","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbeedbcc/46cba327d8dc3331_b.jpg","GoodsImgCount":"6","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801752093","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562622963","title":"大学军事教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.58,"price":0.59,"shippingFee":2.99,"differencePrice":-3.58,"GoodsUrl":"https://book.kongfz.com/784293/8214414858","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daacbdaf/63c3a8955499e0dd_b.jpg","GoodsImgCount":"5","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559617910","title":"和孩子一起去艺术博物馆","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":10,"shippingFee":10,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/265261/8694353313","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaebafae/e8ab83ffb9b4f994_b.jpg","GoodsImgCount":"7","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547260388","title":"全新小学生必背文言文注音版小学一二三四五六年级6-12岁语文教材必背文言文全集阅读小古文经典诵读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.99,"price":3.99,"shippingFee":0,"differencePrice":-3.99,"GoodsUrl":"https://book.kongfz.com/787255/8088016248","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1760/01588e892e1dfa98e4_b.jpg","GoodsImgCount":"1","onSaleCount":141,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502963460","title":"气象统计分析与预报方法(第4版)(首页有字迹)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/269417/7879872024","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdacbfe/4f1c6c5fe9e7ab60_b.jpg","GoodsImgCount":"5","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549850372","title":"意林18周年纪念书.B","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.89,"price":2.89,"shippingFee":0,"differencePrice":-2.89,"GoodsUrl":"https://book.kongfz.com/711444/8643457434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20517473/2b74e8a9e24dfb85_b.jpg","GoodsImgCount":"0","onSaleCount":507,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533643638","title":"魅力口才","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.05,"price":0.05,"shippingFee":5,"differencePrice":-5.05,"GoodsUrl":"https://book.kongfz.com/805022/8631298088","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbcaaac/3ebabf676af610eb_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807553274","title":"妖怪山","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.73,"price":3.23,"shippingFee":4.5,"differencePrice":-7.73,"GoodsUrl":"https://book.kongfz.com/765432/8854682434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbcccae/704257a20943f31f_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532137435","title":"静欲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1.5,"shippingFee":3.5,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/253683/8613551636","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6887408/5c50a923c692899b_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506545433","title":"古今中外心理战100例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":10,"shippingFee":7,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/20331/8181661495","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2868/0269943c229e5f365c_b.jpg","GoodsImgCount":"2","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121451928","title":"人人都能玩赚ChatGPT 高温消毒发货 黄小刀 电子工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3,"price":2.5,"shippingFee":1.8,"differencePrice":-4.3,"GoodsUrl":"https://book.kongfz.com/259056/8887865046","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceaeddfd/444fd0181d292df1_b.jpg","GoodsImgCount":"1","onSaleCount":333,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201150321","title":"男孩故事 彩图注音有声版 笨笨狼童书坊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.1,"price":15.1,"shippingFee":5,"differencePrice":-20.1,"GoodsUrl":"https://book.kongfz.com/911923/8608024464","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecaccefc/d5a348a22b1aba4d_b.jpg","GoodsImgCount":"1","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115510907","title":"用图表说话如何简单有效地做数据分析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.8,"price":0.8,"shippingFee":5,"differencePrice":-5.8,"GoodsUrl":"https://book.kongfz.com/700512/8743345578","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebafedac/360e136d8247ad57_b.jpg","GoodsImgCount":"1","onSaleCount":119,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530638491","title":"现代西方历史的故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/6856/8690577625","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddddafae/afdd629a50acab25_b.jpg","GoodsImgCount":"14","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539990378","title":"虹口大爆炸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.48,"price":1.48,"shippingFee":5,"differencePrice":-6.48,"GoodsUrl":"https://book.kongfz.com/750161/8211811207","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fffaeced/9cd2a7b72eb0f4ac_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544542524","title":"从课本到奥数难题点拨 小学五年级 全新升级版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.7,"price":3.7,"shippingFee":3,"differencePrice":-6.7,"GoodsUrl":"https://book.kongfz.com/838443/8877688994","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdfddeb/3a9a15a02db2c2a7_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115477217","title":"足球战术与阵形图解:思路解说、案例分析及训练方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.5,"price":15,"shippingFee":5.5,"differencePrice":-20.5,"GoodsUrl":"https://book.kongfz.com/669776/8842681155","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbfdaca/86189842b664a053_b.jpg","GoodsImgCount":"3","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530653180","title":"师陀散文选集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":1,"shippingFee":7,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/784196/8071376720","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbebaacf/387d7985239551bb_b.jpg","GoodsImgCount":"2","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030409836","title":"化学实验教学论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.16,"price":41.16,"shippingFee":0,"differencePrice":-41.16,"GoodsUrl":"https://book.kongfz.com/1120807/8901560862","imgBigUrl":"https://www0.kfzimg.com/G06/M00/57/62/p4YBAFqcDtqAYjz_AABOWff5Al4841_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806033494","title":"猫国春秋","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25.8,"price":20,"shippingFee":5.8,"differencePrice":-25.8,"GoodsUrl":"https://book.kongfz.com/914318/8378334053","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddbfdbf/f07a2f247617134c_b.jpg","GoodsImgCount":"2","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508534701","title":"超级梦想家像天才一样思考","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.05,"price":1.67,"shippingFee":5.38,"differencePrice":-7.05,"GoodsUrl":"https://book.kongfz.com/311927/8249147995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efffecaf/9f5fba8331161639_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530214008","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543231214","title":"吃掉情绪?——和食物的斗争","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":7,"shippingFee":6,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/22916/7541247337","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3008554/b610294fb1f49931_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521750393","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521300789","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509654163","title":"电力市场经济学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":71,"price":65,"shippingFee":6,"differencePrice":-71,"GoodsUrl":"https://book.kongfz.com/722278/8595373194","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edafadbf/7506fe39a352972e_b.jpg","GoodsImgCount":"7","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111321118","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213093449","title":"如何启动黄金圈思维","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53.49,"price":47.99,"shippingFee":5.5,"differencePrice":-53.49,"GoodsUrl":"https://book.kongfz.com/1153783/8871587942","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22135404/73612320da1a5cec_b.jpg","GoodsImgCount":"4","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806451427","title":"鲁迅书话","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.48,"price":19.98,"shippingFee":6.5,"differencePrice":-26.48,"GoodsUrl":"https://book.kongfz.com/18747/5221530317","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abecbfad/69d613574c951abc_b.jpg","GoodsImgCount":"13","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224140859","title":"现代文分类提升练·语文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.890000000000001,"price":3.89,"shippingFee":3,"differencePrice":-6.890000000000001,"GoodsUrl":"https://book.kongfz.com/771462/8574561248","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdbbead/c63a292e6fe6cc59_b.jpg","GoodsImgCount":"4","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550243576","title":"中华国学经典精粹·蒙学家训必读本:三字经·百家姓·千字文·弟子规","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.09,"price":1.09,"shippingFee":2,"differencePrice":-3.09,"GoodsUrl":"https://book.kongfz.com/624177/8743682753","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edccbabb/8141fa7ddeaca3c0_b.jpg","GoodsImgCount":"2","onSaleCount":764,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200030402","title":"苍生 华夏出版社编 北京出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":6.7,"shippingFee":5,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/398369/8618810522","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acabddfb/87e80f30013d13a0_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805937731","title":"二胡启蒙教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.46,"price":15.96,"shippingFee":3.5,"differencePrice":-19.46,"GoodsUrl":"https://book.kongfz.com/648701/8612669580","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C1/CE/p4YBAFqw4IGAHMeGAAECW5fmF94515_b.jpg","GoodsImgCount":"1","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537852838","title":"红楼梦—八十回回解精鉴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":148,"price":148,"shippingFee":0,"differencePrice":-148,"GoodsUrl":"https://book.kongfz.com/16743/7232736010","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdcebef/655584802429999d_b.jpg","GoodsImgCount":"1","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805191225","title":"金元明清词鉴赏辞典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":20,"shippingFee":9,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/883669/7889815425","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deaaefec/b7bf4814e6897207_b.jpg","GoodsImgCount":"6","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546358055","title":"美联储的秘密","quality":0,"qualityText":"","originalPrice":0,"totalPrice":60,"price":50,"shippingFee":10,"differencePrice":-60,"GoodsUrl":"https://book.kongfz.com/593893/8299743873","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eccffbbf/0b8db257b042f3e0_b.jpg","GoodsImgCount":"4","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300062372","title":"戴高乐书系:我的父亲戴高乐","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.5,"price":9.5,"shippingFee":8,"differencePrice":-17.5,"GoodsUrl":"https://book.kongfz.com/180278/8511632615","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccccaffe/e139d6f440938797_b.jpg","GoodsImgCount":"12","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556125227","title":"画知道答案","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.3,"price":6.3,"shippingFee":5,"differencePrice":-11.3,"GoodsUrl":"https://book.kongfz.com/893135/8473380609","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabefcfc/34f7142558ae9ce0_b.jpg","GoodsImgCount":"1","onSaleCount":153,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122135674","title":"正版二手 现代生物化学 第三版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.55,"price":13.55,"shippingFee":0,"differencePrice":-13.55,"GoodsUrl":"https://book.kongfz.com/745839/8780452119","imgBigUrl":"https://www0.kfzimg.com/G06/M00/CC/AF/p4YBAFqYnVSAGvflAAGZAQiLoGs040_b.jpg","GoodsImgCount":"0","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500168171","title":"极简元宇宙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.01,"price":2.01,"shippingFee":2,"differencePrice":-4.01,"GoodsUrl":"https://book.kongfz.com/755561/8129818306","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aeeaaefa/2ab5dd065e2dd348_b.jpg","GoodsImgCount":"2","onSaleCount":248,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549286348","title":"你哄我一下2 签名本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":3,"shippingFee":9,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/381029/8362454944","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddcbeadb/45eac4be85e7634e_b.jpg","GoodsImgCount":"7","onSaleCount":81,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532759095","title":"意大利风光","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":20,"shippingFee":9,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/638707/5528411427","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/17015971/bb54277e8cd73700_b.jpg","GoodsImgCount":"5","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513321174","title":"巴比伦时代","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.1,"price":9.1,"shippingFee":3,"differencePrice":-12.1,"GoodsUrl":"https://book.kongfz.com/808455/8886959658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbbcaeee/dfc8b85fc3bece6e_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807696001","title":"南烟以北","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.08,"price":0.08,"shippingFee":5,"differencePrice":-5.08,"GoodsUrl":"https://book.kongfz.com/878060/8738813937","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aeacadcc/9dbeb09260474062_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545801064","title":"浑家 拙荆 夫人 刘绍铭 上海书店出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":23,"shippingFee":5,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/878060/8575285157","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abaddfea/2da8202ac0a5e1a4_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513108577","title":"新世纪心理与心理健康教育文库9 人格心理学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.34,"price":4.34,"shippingFee":5,"differencePrice":-9.34,"GoodsUrl":"https://book.kongfz.com/23607/8458656434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deecddbd/1c5a5efca63348db_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535917393","title":"广东茶点:[图集]","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":5,"shippingFee":4,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/769904/8539241272","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcccfcab/4cb012ab8cc45886_b.jpg","GoodsImgCount":"5","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810321556","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800504174","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540213169","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020110971","title":"普希金代表作上尉的女儿 俄 普希金著 磊然译 人民文学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.54,"price":6.54,"shippingFee":5,"differencePrice":-11.54,"GoodsUrl":"https://book.kongfz.com/672601/8830859922","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafebffc/0014b4a285f792dc_b.jpg","GoodsImgCount":"1","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544775854","title":"文学名著经典译林 欧也妮葛朗台 新版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.55,"price":2.55,"shippingFee":3,"differencePrice":-5.55,"GoodsUrl":"https://book.kongfz.com/1181761/8875292333","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbdadbf/1b838edc8ecf18b4_b.jpg","GoodsImgCount":"1","onSaleCount":174,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111523642","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301326640","title":"9787301326640 21世纪教师教育系列~ 外国高等教育史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34.07,"price":29.67,"shippingFee":4.4,"differencePrice":-34.07,"GoodsUrl":"https://book.kongfz.com/27495/8343052854","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4756272/1e6e8023f7617217_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301227671","title":"法律史译评","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.35,"price":15.35,"shippingFee":8,"differencePrice":-23.35,"GoodsUrl":"https://book.kongfz.com/820711/8391037776","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecbffba/bda90fee6c7c1436_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301209974","title":"理解美国:美国文化指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.6,"price":2.6,"shippingFee":3,"differencePrice":-5.6,"GoodsUrl":"https://book.kongfz.com/736627/8382555942","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadcbeda/860f249185e56c97_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503400490","title":"名僧录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":15,"shippingFee":5,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/398369/8195974665","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceabbfae/a43ce3e5787c2a5a_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301320327","title":"侠义三千年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":15,"shippingFee":0,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/419134/4596898069","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeedbec/96ecee234f4f480c_b.jpg","GoodsImgCount":"1","onSaleCount":135,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507514704","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113197445","title":"新手学开公司:创业融资常识","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1,"shippingFee":4,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/1210014/8842706502","imgBigUrl":"https://www0.kfzimg.com/G06/M00/04/EC/p4YBAFqZ55SAPmxSAADXtJjYMto864_b.jpg","GoodsImgCount":"1","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534247293","title":"史记故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.4,"price":4.4,"shippingFee":2,"differencePrice":-6.4,"GoodsUrl":"https://book.kongfz.com/667558/8898517027","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaecaffe/a6a58d3c0ae45e3d_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802113022","title":"人类与宗教","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53.2,"price":42,"shippingFee":11.2,"differencePrice":-53.2,"GoodsUrl":"https://book.kongfz.com/890580/8054767633","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decaefca/8f5bc4523bca53c2_b.jpg","GoodsImgCount":"6","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562858201","title":"中日跨文化交际实用教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.71,"price":3.71,"shippingFee":0,"differencePrice":-3.71,"GoodsUrl":"https://book.kongfz.com/892397/8511714742","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/206/24ff4c4e636a8af1_b.jpg","GoodsImgCount":"1","onSaleCount":162,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506007252","title":"十批判书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.95,"price":18.95,"shippingFee":2,"differencePrice":-20.95,"GoodsUrl":"https://book.kongfz.com/877749/8349858098","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/610ef12388c7aae3_b.jpg","GoodsImgCount":"3","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565107610","title":"幼儿园早期阅读资源. 幸福的种子 大班 导读手册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.8,"price":1.8,"shippingFee":3,"differencePrice":-4.8,"GoodsUrl":"https://book.kongfz.com/225395/6586000622","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabdbbce/277268d26c84ada2_b.jpg","GoodsImgCount":"6","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111607915","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100014205","title":"狄德罗传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/565102/7684520458","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afbfdeaf/49dfb3ffb3e393b9_b.jpg","GoodsImgCount":"9","onSaleCount":76,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532360437","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303113255","title":"伦理学经典著作选读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":52,"price":40,"shippingFee":12,"differencePrice":-52,"GoodsUrl":"https://book.kongfz.com/633074/5274343343","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeaeacae/eb4784a0715850e4_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535378569","title":"芭比小公主影院 芭比之公主学校 新版畅销版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9,"price":1.1,"shippingFee":2.8,"differencePrice":-3.9,"GoodsUrl":"https://book.kongfz.com/1093663/8697070175","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcbcecb/74f6ac0d15ec88fc_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567591547","title":"数学家画传·吴文俊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":10,"shippingFee":9,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/507602/7478663525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ababcabf/f04da9e185cf94d2_b.jpg","GoodsImgCount":"6","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500931003","title":":篮球运动教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.41,"price":3.41,"shippingFee":0,"differencePrice":-3.41,"GoodsUrl":"https://book.kongfz.com/20179/8594547518","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F2/CE/p4YBAFqZPEqAaXIFAAD8_GCgzIw699_b.jpg","GoodsImgCount":"1","onSaleCount":366,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521740196","title":"生命密码3:瘟疫传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":11,"shippingFee":6,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/624944/8895449656","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeeeddc/a0cdba4fddc59c7e_b.jpg","GoodsImgCount":"8","onSaleCount":283,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508235202","title":"职业技能培训丛书:电焊工入门与技巧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.24,"price":9.24,"shippingFee":2,"differencePrice":-11.24,"GoodsUrl":"https://book.kongfz.com/767143/8725850207","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdddabbd/5e8247e98682f766_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040506655","title":"西方政治思想史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":4.5,"shippingFee":0,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/638685/8638161704","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/445/5932042ae57cc3ce_b.jpg","GoodsImgCount":"1","onSaleCount":288,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538725421","title":"《希区柯克悬念故事集》-午夜追踪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.41,"price":4.91,"shippingFee":0.5,"differencePrice":-5.41,"GoodsUrl":"https://book.kongfz.com/156492/8287023578","imgBigUrl":"https://www0.kfzimg.com/G06/M00/4A/BF/p4YBAFqbw2CAMtcwAACLHc8-Kmw376_b.jpg","GoodsImgCount":"1","onSaleCount":127,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229148935","title":"少即是多:北欧自由生活意见新版与断舍离并提的人生整理术,樊登读书会创始人樊登亲自讲书推荐","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.92,"price":9.92,"shippingFee":5,"differencePrice":-14.92,"GoodsUrl":"https://book.kongfz.com/400965/8684128772","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddffccde/e26c93777dcaddbf_b.jpg","GoodsImgCount":"1","onSaleCount":140,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040402025","title":"管理心理学第二2版王晓钧 主编高等教育出版社9787040402025","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.72,"price":3.72,"shippingFee":0,"differencePrice":-3.72,"GoodsUrl":"https://book.kongfz.com/248516/8445959763","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/de788cd5eee0ea96_b.jpg","GoodsImgCount":"1","onSaleCount":126,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500081029","title":"曹汝霖一生之回忆","quality":0,"qualityText":"","originalPrice":0,"totalPrice":107.8,"price":102,"shippingFee":5.8,"differencePrice":-107.8,"GoodsUrl":"https://book.kongfz.com/51215/8461562441","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaefdbce/8c562bf3869c30fd_b.jpg","GoodsImgCount":"3","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030656407","title":"大学物理实验","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.1,"price":1.1,"shippingFee":3,"differencePrice":-4.1,"GoodsUrl":"https://book.kongfz.com/891713/8560427068","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aabafbce/ba4bec806b56ffe0_b.jpg","GoodsImgCount":"3","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122180339","title":"白菜与国王,心与手","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.9,"price":4.9,"shippingFee":0,"differencePrice":-4.9,"GoodsUrl":"https://book.kongfz.com/842883/8265631544","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceaeaadf/e35077eb4df6c14d_b.jpg","GoodsImgCount":"20","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547312964","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301302866","title":"法律研习的方法:作业、考试和论文写作","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":3,"shippingFee":10,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/891541/8813242545","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbdeecf/81217bf603b8cd44_b.jpg","GoodsImgCount":"2","onSaleCount":167,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506240789","title":"GRE 语文仿真试题","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.55,"price":2.55,"shippingFee":4,"differencePrice":-6.55,"GoodsUrl":"https://book.kongfz.com/203004/8427844598","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddcafaaf/ac83988286fb5146_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510454585","title":"中国社会科学全球化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35.81,"price":32.31,"shippingFee":3.5,"differencePrice":-35.81,"GoodsUrl":"https://book.kongfz.com/904671/8421015503","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbeeedeb/033d993974bafbe5_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558308178","title":"肖云峰阳光成长小说系列:我的筷子班主任","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":0.5,"shippingFee":4,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/768172/8469297539","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcfddbee/d237e91dc5b7f728_b.jpg","GoodsImgCount":"4","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040024135","title":"艺术概论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.8,"price":1.8,"shippingFee":3,"differencePrice":-4.8,"GoodsUrl":"https://book.kongfz.com/602194/6362597815","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdecfeb/5da7fa93a557f9aa_b.jpg","GoodsImgCount":"4","onSaleCount":214,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535631329","title":"湖湘篆刻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":90,"price":80,"shippingFee":10,"differencePrice":-90,"GoodsUrl":"https://book.kongfz.com/27254/8219331776","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deeeddaf/74aeb2b4b131791a_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787570612352","title":"小学数学竞赛年鉴:MO2020","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":8,"shippingFee":5,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/426911/7902501351","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/7611848/fda903b85b9134bc_b.jpg","GoodsImgCount":"4","onSaleCount":124,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040285246","title":"正版二手 地球与空间科学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.7,"price":4.7,"shippingFee":0,"differencePrice":-4.7,"GoodsUrl":"https://book.kongfz.com/549116/8836455149","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/917/a23746764cd07ab3_b.jpg","GoodsImgCount":"1","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545812886","title":"三苏评传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":70,"price":58,"shippingFee":12,"differencePrice":-70,"GoodsUrl":"https://book.kongfz.com/23265/8181755497","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addddfac/fa013300f5292783_b.jpg","GoodsImgCount":"7","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510446566","title":"500美元问鼎百事CEO:全球头号女强人卢英德的经营哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/592021/5550361559","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddabecfa/dbc1bfe082195815_b.jpg","GoodsImgCount":"4","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121380440","title":"电气控制与plc技术应用 大中专理科水利电力 刘小春","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":13,"shippingFee":10,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/712076/8416032209","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dccdcafa/dec1e5d38d5f38ee_b.jpg","GoodsImgCount":"6","onSaleCount":53,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542618368","title":"德意志精神漫游","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.31,"price":17.31,"shippingFee":0,"differencePrice":-17.31,"GoodsUrl":"https://book.kongfz.com/919786/8892987379","imgBigUrl":"https://www0.kfzimg.com/G06/M00/6F/AB/p4YBAFqdEgyAcQgWAABHsHusPPc676_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787304008789","title":"艺术赏析概要","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.5,"price":0.5,"shippingFee":3,"differencePrice":-3.5,"GoodsUrl":"https://book.kongfz.com/838443/8859718589","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecffaac/dcae10f91c4a308b_b.jpg","GoodsImgCount":"1","onSaleCount":171,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562296195","title":"考点同步解读 高中化学 选择性必修一 化学反应原理 有笔记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":23,"shippingFee":3,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/211077/7520896879","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceaccafa/ab450e1ce8320b0e_b.jpg","GoodsImgCount":"4","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539947235","title":"铠甲勇士:神秘的陨石1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.8,"price":18,"shippingFee":5.8,"differencePrice":-23.8,"GoodsUrl":"https://book.kongfz.com/747887/6880955959","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbcefbbc/682c32a3d38bb55d_b.jpg","GoodsImgCount":"7","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115375438","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564817688","title":"二手财经应用文写作9787564817688刘鑫","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":2.6,"shippingFee":2.9,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/750659/8426123356","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/affafccf/9af32edd2ccd7249_b.jpg","GoodsImgCount":"1","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503318443","title":"白登之围3 帝国草原三部曲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.5,"price":7.5,"shippingFee":5,"differencePrice":-12.5,"GoodsUrl":"https://book.kongfz.com/798681/8249118687","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeafdca/8450b15747941350_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787557014858","title":"诡秘之主4","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.46,"price":10.46,"shippingFee":5,"differencePrice":-15.46,"GoodsUrl":"https://book.kongfz.com/771462/8867879036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accbddaf/f6fcebe29db0cd77_b.jpg","GoodsImgCount":"4","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787225013046","title":"黄埔军校百将传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.98,"price":4,"shippingFee":2.98,"differencePrice":-6.98,"GoodsUrl":"https://book.kongfz.com/840438/8881985399","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfedbef/5eadb46b1348058c_b.jpg","GoodsImgCount":"2","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539798387","title":"妄想银行星新一 李盈春安徽少年儿童出版社9787539798387","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.19,"price":5.19,"shippingFee":0,"differencePrice":-5.19,"GoodsUrl":"https://book.kongfz.com/366030/8864056391","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/b0cc76b216b8cb24_b.jpg","GoodsImgCount":"1","onSaleCount":103,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544323086","title":"张家界旅游导读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/778224/6948456565","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfebdfee/1911341d2cf4b3cd_b.jpg","GoodsImgCount":"1","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516922811","title":"集体的失忆 杨定一全部生命系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33.65,"price":30.65,"shippingFee":3,"differencePrice":-33.65,"GoodsUrl":"https://book.kongfz.com/762329/8780202649","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10564427/c571335c6e98d724_b.jpg","GoodsImgCount":"0","onSaleCount":97,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302249085","title":"国际物流:国际贸易中的运作管理(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":73.06,"price":61.06,"shippingFee":12,"differencePrice":-73.06,"GoodsUrl":"https://book.kongfz.com/795825/7334746188","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14523379/51ba99736a77252f_b.jpg","GoodsImgCount":"2","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810035750","title":"截拳道","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/233440/4385393174","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecbecbe/4a6d598b9537b021_b.jpg","GoodsImgCount":"4","onSaleCount":219,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807205913","title":"古玉收藏三百问 鉴宝 大众收藏3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":3,"shippingFee":2.4,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/561672/8415735311","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaccbcc/f11e6347fa684356_b.jpg","GoodsImgCount":"1","onSaleCount":128,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805747637","title":"西塘民间建筑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.1,"price":7.6,"shippingFee":5.5,"differencePrice":-13.1,"GoodsUrl":"https://book.kongfz.com/250120/8810679961","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edccedac/3fe60dbba98c7088_b.jpg","GoodsImgCount":"3","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100186506","title":"钱颖一对话录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":68,"price":58,"shippingFee":10,"differencePrice":-68,"GoodsUrl":"https://book.kongfz.com/17030/8830419237","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffceeede/2e8b3b3f24aa0fb7_b.jpg","GoodsImgCount":"7","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508673073","title":"茶当酒集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":4.5,"shippingFee":3.5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/401024/8872498867","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cacabaec/912f51c1b0fefcbd_b.jpg","GoodsImgCount":"2","onSaleCount":193,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801211453","title":"妇科病外治独特新疗法--内病外治·外病外治独特新疗法丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":15,"shippingFee":5,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/16472/6638610438","imgBigUrl":"https://www0.kfzimg.com/G06/M00/6D/DF/p4YBAFt2j6eAVdSMAAHEQyrZmzw541_b.jpg","GoodsImgCount":"2","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505438132","title":"探索·科学专题百科绘本 :植物的奥秘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":18,"shippingFee":10,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/427935/8151202484","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cffbddcd/b9350271a6c67aac_b.jpg","GoodsImgCount":"4","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113284220","title":"城市轨道交通信号技术(第二版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55.82,"price":49.82,"shippingFee":6,"differencePrice":-55.82,"GoodsUrl":"https://book.kongfz.com/533712/7445893108","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fffddefa/e3eecc18ea41d9a3_b.jpg","GoodsImgCount":"1","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560826462","title":"老上海名宅赏析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21,"price":12,"shippingFee":9,"differencePrice":-21,"GoodsUrl":"https://book.kongfz.com/366445/8584945980","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eabffdea/b445c31f3017c8ec_b.jpg","GoodsImgCount":"7","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805112329","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544786218","title":"小译林国际大奖童书:我的哥哥吹黑管","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.99,"price":4.99,"shippingFee":6,"differencePrice":-10.99,"GoodsUrl":"https://book.kongfz.com/273843/8153980235","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deffacda/736311caf50ede76_b.jpg","GoodsImgCount":"2","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504770356","title":"加盟连锁招商模式顶级设计思维 李松 李爽 9787504770356 中国财富出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.62,"price":5.12,"shippingFee":2.5,"differencePrice":-7.62,"GoodsUrl":"https://book.kongfz.com/237713/8695995574","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/940/a676d512dc1104ae_b.jpg","GoodsImgCount":"1","onSaleCount":165,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539168975","title":"胡平文集:百年误读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.46,"price":16.46,"shippingFee":2,"differencePrice":-18.46,"GoodsUrl":"https://book.kongfz.com/1214248/8872764563","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abbcffec/36a14534af372c1d_b.jpg","GoodsImgCount":"2","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534808944","title":"野叟曝言 下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.879999999999999,"price":4.88,"shippingFee":5,"differencePrice":-9.879999999999999,"GoodsUrl":"https://book.kongfz.com/750161/8080623189","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfbabfb/bd7efa40cb71d18c_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810367899","title":"杨桃文化·新手食谱系列 41~45","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1,"shippingFee":4,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/891293/8009230723","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbffdadd/2dc8960a8a687a9f_b.jpg","GoodsImgCount":"3","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569931549","title":"看见梵高:孤独与伟大(写给大家的360度艺术启蒙书)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":2,"shippingFee":10,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/453237/8801143694","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acddcacb/fd041a1fd8b81733_b.jpg","GoodsImgCount":"11","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800220272","title":"常见病简易中医疗法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/322775/7550848376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cddccbec/e7fbcfaad8043cd4_b.jpg","GoodsImgCount":"11","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533758684","title":"超级秀·小学英语随堂故事:三年级","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.470000000000002,"price":27.87,"shippingFee":1.6,"differencePrice":-29.470000000000002,"GoodsUrl":"https://book.kongfz.com/470338/8595088507","imgBigUrl":"https://www0.kfzimg.com/G06/M00/FB/9F/p4YBAFqh40GANBXkAADzfKO38vM478_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553122250","title":"中国雕塑史 梁思成 著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.8,"price":18.8,"shippingFee":4,"differencePrice":-22.8,"GoodsUrl":"https://book.kongfz.com/651345/8071240129","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4893319/632f3df473149970_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806890356","title":"金田一探案集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.9,"price":6,"shippingFee":4.9,"differencePrice":-10.9,"GoodsUrl":"https://book.kongfz.com/588886/8817249258","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fddedbab/536b81fb83ff03a4_b.jpg","GoodsImgCount":"6","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122112309","title":"典型液压气动回路600例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27,"price":22,"shippingFee":5,"differencePrice":-27,"GoodsUrl":"https://book.kongfz.com/891499/8842174912","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eefdafbb/afc934890793788e_b.jpg","GoodsImgCount":"6","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500625827","title":"马说陶瓷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.8,"price":32,"shippingFee":5.8,"differencePrice":-37.8,"GoodsUrl":"https://book.kongfz.com/681126/8811277816","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbbbdfeb/569966dc1788862d_b.jpg","GoodsImgCount":"2","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214254863","title":"诗意人生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35.8,"price":29,"shippingFee":6.8,"differencePrice":-35.8,"GoodsUrl":"https://book.kongfz.com/13883/8535361435","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdafdced/5137129530c3717e_b.jpg","GoodsImgCount":"2","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535548887","title":"玻璃城堡","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":5,"shippingFee":4,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/512101/5119116553","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14073610/877fc17482e5334d_b.jpg","GoodsImgCount":"4","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787112273393","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534253621","title":"世界少年文学经典文库 叶圣陶作品精选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.48,"price":0.48,"shippingFee":3,"differencePrice":-3.48,"GoodsUrl":"https://book.kongfz.com/791250/8878211228","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aebcbced/163c2c611b494d45_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810035927","title":"奇门护身暗器练法(一版一印)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":30,"shippingFee":8,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/137604/7693281367","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfafeaac/d69912592ceffad6_b.jpg","GoodsImgCount":"5","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565659676","title":"最新五年中考满分作文大全","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/911923/8806310513","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbadcca/b8961895538c4451_b.jpg","GoodsImgCount":"1","onSaleCount":120,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040519297","title":"中学语文教学设计 郑桂华 9787040519297 高等教育出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.99,"price":5.99,"shippingFee":3,"differencePrice":-8.99,"GoodsUrl":"https://book.kongfz.com/240018/8661063245","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/424/549f95263f2b8049_b.jpg","GoodsImgCount":"0","onSaleCount":137,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550243552","title":"中华国学经典精粹·历史地理必读本:三国志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.8899999999999997,"price":0.11,"shippingFee":2.78,"differencePrice":-2.8899999999999997,"GoodsUrl":"https://book.kongfz.com/785333/8761856529","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbbebddd/b733d5d903cb7b1d_b.jpg","GoodsImgCount":"1","onSaleCount":789,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571103408","title":"中国现当代作家作品专题研究/河南省高等教育自学考试汉语言文学专业本科教材","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":18,"shippingFee":6,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/778238/8492605781","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdfafbca/e1fb525eb35a401b_b.jpg","GoodsImgCount":"12","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532614813","title":"8848我为歌狂终结本漫画版·楚天歌篇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33,"price":25,"shippingFee":8,"differencePrice":-33,"GoodsUrl":"https://book.kongfz.com/778785/7495502311","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecedbdcd/21cedd66962c506c_b.jpg","GoodsImgCount":"5","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539443744","title":"历代书法名迹技法选讲(第1辑):王铎诗卷.","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/18033/8237184983","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdffaecd/9190e5260d56e5dc_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515360607","title":"念力的秘密:2:2","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.2,"price":3.2,"shippingFee":5,"differencePrice":-8.2,"GoodsUrl":"https://book.kongfz.com/180897/8428663147","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dddfcdbd/210a611eee19a8eb_b.jpg","GoodsImgCount":"1","onSaleCount":144,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539154541","title":"绿山墙的安妮","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":4,"shippingFee":4,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/413068/2855797793","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3373/02e31e12e618d9a492_b.jpg","GoodsImgCount":"3","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539731766","title":"虹猫蓝兔七侠传.2","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":1.5,"shippingFee":4,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/198833/8806246345","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5862318/af620f5bab4bd51e_b.jpg","GoodsImgCount":"1","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544131834","title":"郑振铎藏本红楼梦","quality":0,"qualityText":"","originalPrice":0,"totalPrice":73,"price":65,"shippingFee":8,"differencePrice":-73,"GoodsUrl":"https://book.kongfz.com/25093/8534180256","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feabbbed/4e83283b2d4203e9_b.jpg","GoodsImgCount":"9","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511828156","title":"法律方法论 (书面有划横伤)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.9,"price":1.9,"shippingFee":8,"differencePrice":-9.9,"GoodsUrl":"https://book.kongfz.com/271477/8201797030","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffebdafa/76c5fecaf81060f1_b.jpg","GoodsImgCount":"5","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806657607","title":"明清小品选评 高温消毒发货 杨义著 李玫著 岳麓书社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.89,"price":8.09,"shippingFee":1.8,"differencePrice":-9.89,"GoodsUrl":"https://book.kongfz.com/110/8696629154","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caebcddd/7a1589c89b1a04c4_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787523202487","title":"2024世图版第二版英语皮考研真题逐词逐句精讲册 基础试卷版2004-2010曾鸣 张剑 刘京霄世界图书出版公司9787523202487","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":6.9,"shippingFee":0,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/248516/8585451759","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/1b6430cf81a207af_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108043597","title":"坚忍与守望 近代韩江下游的福音姿娘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.05,"price":12.55,"shippingFee":5.5,"differencePrice":-18.05,"GoodsUrl":"https://book.kongfz.com/244432/8796690963","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffeefbad/6720ba4115d67751_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535436375","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787830054038","title":"男科疾病诊断治疗指南(2022 版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":30,"shippingFee":5,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/196496/7650931803","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdebcfdf/e3d909f5ed9a00c8_b.jpg","GoodsImgCount":"6","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111307921","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544714587","title":"猫和老鼠:浪漫的代价","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.5,"price":0.5,"shippingFee":6,"differencePrice":-6.5,"GoodsUrl":"https://book.kongfz.com/570846/8637927606","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbcddccc/42e5131764a6ee79_b.jpg","GoodsImgCount":"7","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111244813","title":"HyperWorks分析应用实例9787111244813李楚琳机械工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.2,"price":16.7,"shippingFee":2.5,"differencePrice":-19.2,"GoodsUrl":"https://book.kongfz.com/1092759/8781226015","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbdedaf/05761766ae23af61_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513352109","title":"早期中国的鬼","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.85,"price":19.85,"shippingFee":3,"differencePrice":-22.85,"GoodsUrl":"https://book.kongfz.com/791250/8897892698","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaceecf/57e4bbc2456853dd_b.jpg","GoodsImgCount":"1","onSaleCount":160,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121253799","title":"体验引擎:游戏设计全景探秘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.48,"price":24.48,"shippingFee":0,"differencePrice":-24.48,"GoodsUrl":"https://book.kongfz.com/492548/8866402714","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C5/31/p4YBAFqYOW-AMOJ-AADBpjNYdUU066_b.jpg","GoodsImgCount":"1","onSaleCount":183,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508396170","title":"国家电网公司生产技能人员职业能力培训通用教材 继电保护及自动","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.45,"price":12.95,"shippingFee":4.5,"differencePrice":-17.45,"GoodsUrl":"https://book.kongfz.com/654834/8738560594","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1C/8B/p4YBAFq7vXaAM8zEAADX1CViJh8024_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213086113","title":"【正版】创造自然9787213086113","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.86,"price":28.86,"shippingFee":0,"differencePrice":-28.86,"GoodsUrl":"https://book.kongfz.com/774490/8790671476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedbbfba/1175b5720aeccb00_b.jpg","GoodsImgCount":"1","onSaleCount":123,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535441058","title":"白色群像","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.2800000000000002,"price":0.28,"shippingFee":3,"differencePrice":-3.2800000000000002,"GoodsUrl":"https://book.kongfz.com/885099/8677269564","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfdeebbc/0c1b88098d1c3758_b.jpg","GoodsImgCount":"4","onSaleCount":513,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506026468","title":"斯大林的女儿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":9,"shippingFee":8,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/280648/7012552257","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeadaca/fc65bfaccdc26af3_b.jpg","GoodsImgCount":"10","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501948802","title":"高温消毒发货 100种天然食物营养治病全新彩装","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.18,"price":4.38,"shippingFee":1.8,"differencePrice":-6.18,"GoodsUrl":"https://book.kongfz.com/110/8853611246","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbcacbda/2b0d9fb3a6dffbdf_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503424182","title":"政协主席","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.5,"price":6.5,"shippingFee":5,"differencePrice":-11.5,"GoodsUrl":"https://book.kongfz.com/1207201/8642380606","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deffcaae/e40f087108ded6db_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208145405","title":"殷墟青铜器研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33,"price":27,"shippingFee":6,"differencePrice":-33,"GoodsUrl":"https://book.kongfz.com/592236/8433015685","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daafbefb/968585acf2692335_b.jpg","GoodsImgCount":"13","onSaleCount":74,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301244869","title":"俄罗斯文学史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.76,"price":3.26,"shippingFee":1.5,"differencePrice":-4.76,"GoodsUrl":"https://book.kongfz.com/774690/8696568956","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C7/FD/p4YBAFqYQpWAbJXyAAC4ESrSO-U746_b.jpg","GoodsImgCount":"1","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542844064","title":"隐喻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49.8,"price":39.8,"shippingFee":10,"differencePrice":-49.8,"GoodsUrl":"https://book.kongfz.com/302127/7140352552","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AB/1A/p4YBAFr8MQOAND_6AAC1fo4rTZA063_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787568287760","title":"梅兰妮·克莱因儿童心理学:嫉羡与感恩","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.2,"price":11.2,"shippingFee":5,"differencePrice":-16.2,"GoodsUrl":"https://book.kongfz.com/1155304/8779916761","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3038/02939e282aadcbb13b_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532740680","title":"还原论的局限 来自活细胞的训诫","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":26,"shippingFee":3.8,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/1937/8841925682","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccfcafba/14d8bbf616f6cca3_b.jpg","GoodsImgCount":"6","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501056361","title":"嘉德日历2019","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":6,"shippingFee":10,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/593645/7150712837","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eadecbcb/e27d123c6ae6f237_b.jpg","GoodsImgCount":"6","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502848378","title":"怎么选择成长股 美 菲利普 A 费舍 地震出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.75,"price":7.75,"shippingFee":5,"differencePrice":-12.75,"GoodsUrl":"https://book.kongfz.com/180897/8899731120","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecaaabee/4d03e36f79e8d89c_b.jpg","GoodsImgCount":"1","onSaleCount":313,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571404512","title":"真相只有一个","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1,"shippingFee":4,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/893934/8882047074","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbcdefeb/8e226b7ee365b547_b.jpg","GoodsImgCount":"3","onSaleCount":275,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302649847","title":"微积分","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.14,"price":37.34,"shippingFee":3.8,"differencePrice":-41.14,"GoodsUrl":"https://book.kongfz.com/717628/8773767244","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13270436/44c070d95076cb9a_b.jpg","GoodsImgCount":"1","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513662109","title":"年度经营计划制订与管理企业管理年度计划","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.62,"price":18.62,"shippingFee":6,"differencePrice":-24.62,"GoodsUrl":"https://book.kongfz.com/339693/8767370008","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2196/01b864aa0eea225d39_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101124163","title":"中国兵器史稿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/766211/7869531760","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdaaaae/1ae140e68d413e75_b.jpg","GoodsImgCount":"2","onSaleCount":126,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040212495","title":"肥胖症咨询","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.89,"price":15.89,"shippingFee":6,"differencePrice":-21.89,"GoodsUrl":"https://book.kongfz.com/903355/8146162281","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AB/70/p4YBAFqnmtuAcKiLAACq2BdpEts751_b.jpg","GoodsImgCount":"0","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111536659","title":"创业八讲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9000000000000004,"price":0.2,"shippingFee":3.7,"differencePrice":-3.9000000000000004,"GoodsUrl":"https://book.kongfz.com/682861/6931289851","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afffdaff/55c74a8b7dc93c83_b.jpg","GoodsImgCount":"3","onSaleCount":293,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532785049","title":"旅行的艺术(阿兰·德波顿作品集) [英]阿兰·德波顿 著,南治国 彭俊豪 何世原 译 上海译文出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.4,"price":13.4,"shippingFee":3,"differencePrice":-16.4,"GoodsUrl":"https://book.kongfz.com/521005/8637635084","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2926/0277dc937e68954c4f_b.jpg","GoodsImgCount":"1","onSaleCount":141,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532727308","title":"上尉的女儿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.5,"price":8,"shippingFee":4.5,"differencePrice":-12.5,"GoodsUrl":"https://book.kongfz.com/563726/4981987527","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbfdfcde/746d3d61e7061c4a_b.jpg","GoodsImgCount":"9","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787568028318","title":"说服力 如何讲好一个故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.99,"price":2.29,"shippingFee":3.7,"differencePrice":-5.99,"GoodsUrl":"https://book.kongfz.com/760748/8801361701","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcceffd/a729199af997ee71_b.jpg","GoodsImgCount":"3","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508679709","title":"汉字有意思(精装)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":23,"shippingFee":5,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/735780/8827432116","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accfbccf/622e02efc4893d76_b.jpg","GoodsImgCount":"4","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540479343","title":"聪明人的一张纸工作整理术:完美图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.279999999999999,"price":2.78,"shippingFee":1.5,"differencePrice":-4.279999999999999,"GoodsUrl":"https://book.kongfz.com/772556/7315801571","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D2/B7/p4YBAFqYsP6Abfz2AACosblIHW0452_b.jpg","GoodsImgCount":"1","onSaleCount":324,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546342399","title":"黑色记事本 二手书实拍图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.809999999999999,"price":5.21,"shippingFee":5.6,"differencePrice":-10.809999999999999,"GoodsUrl":"https://book.kongfz.com/899541/8721283986","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babdebfe/c531fae696961d1c_b.jpg","GoodsImgCount":"1","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121287183","title":"视觉型团队 应用可视化工具开创团队创新新模式双色","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.7,"price":25.7,"shippingFee":5,"differencePrice":-30.7,"GoodsUrl":"https://book.kongfz.com/666339/8521897933","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddddceac/3da6222201dfdb6b_b.jpg","GoodsImgCount":"1","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111134916","title":"4+2什么对企业真正有效","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/847200/8208211887","imgBigUrl":"https://www0.kfzimg.com/G06/M00/FF/A5/p4YBAFqh9_KAOFbPAACEsYfS-Qk627_b.jpg","GoodsImgCount":"1","onSaleCount":101,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030722485","title":"中药炮制学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33.3,"price":33.3,"shippingFee":0,"differencePrice":-33.3,"GoodsUrl":"https://book.kongfz.com/196857/8732055060","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/7445133/1aaae00ef9686a5d_b.jpg","GoodsImgCount":"1","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805236988","title":"红楼梦","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/256283/8754312169","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decabaff/80a154bafe4d9f70_b.jpg","GoodsImgCount":"9","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308080125","title":"文化产业概论(第二版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.01,"price":0.01,"shippingFee":4,"differencePrice":-4.01,"GoodsUrl":"https://book.kongfz.com/781353/7169578229","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baaefbfb/8732ca3425966bcc_b.jpg","GoodsImgCount":"1","onSaleCount":179,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549259618","title":"明朝市井周刊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":3.9,"shippingFee":3,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/783956/8836247359","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aebbfbcf/12ee2b7c2fb85771_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508098586","title":"太平洋地缘政治学:地理与历史之间关系的研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":44,"price":32,"shippingFee":12,"differencePrice":-44,"GoodsUrl":"https://book.kongfz.com/256234/7416926912","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecfdce/6940ef59d0e3093f_b.jpg","GoodsImgCount":"12","onSaleCount":99,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510711213","title":"平安中国年鉴 2023 碟子在","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":7,"shippingFee":5,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/878710/8454275891","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbfedcbc/950dd6c01187f526_b.jpg","GoodsImgCount":"1","onSaleCount":104,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559655479","title":"子不语:完全珍藏版.3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":10,"shippingFee":10,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/624390/6910763145","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eecfcffc/22d5dc8a606de24c_b.jpg","GoodsImgCount":"5","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787204044559","title":"中国偏方全书 肝病 肾病泌尿病","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.08,"price":0.08,"shippingFee":5,"differencePrice":-5.08,"GoodsUrl":"https://book.kongfz.com/716746/8631109464","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcafcfaa/4e57320326499aca_b.jpg","GoodsImgCount":"1","onSaleCount":286,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541445026","title":"魔法少女①——寻找百变裙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6,"price":6,"shippingFee":0,"differencePrice":-6,"GoodsUrl":"https://book.kongfz.com/461620/5735289715","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eefedaae/806a6210a4e2dfb3_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787228064564","title":"中国九十年代诗歌精选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.35,"price":6.35,"shippingFee":5,"differencePrice":-11.35,"GoodsUrl":"https://book.kongfz.com/820017/8795346716","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fffceade/974ba7bca5ddfc42_b.jpg","GoodsImgCount":"2","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224013887","title":"中国善恶报应习俗","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":3,"shippingFee":7,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/679518/7011532548","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddfebbdb/feef7a302dcd8e57_b.jpg","GoodsImgCount":"3","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115597533","title":"新潮职业","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/911923/8655383401","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cebcdddb/6e45ffcdec9a8925_b.jpg","GoodsImgCount":"1","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506073486","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541128509","title":"不会吟诗也会吟 诗词创作十日谈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.96,"price":8.96,"shippingFee":5,"differencePrice":-13.96,"GoodsUrl":"https://book.kongfz.com/798681/8340108119","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecdfddf/da80026a3f1892fe_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545303964","title":"副省长女秘书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2,"shippingFee":5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/1207077/8689348274","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcaebab/610f32d42234c9ec_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308030458","title":"大学写作陈建新 主编浙江大学出版社9787308030458","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.03,"price":4.03,"shippingFee":0,"differencePrice":-4.03,"GoodsUrl":"https://book.kongfz.com/366030/8589381214","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/093b49e8b778b4c2_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544707510","title":"林先生的小孙女","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34.7,"price":29.7,"shippingFee":5,"differencePrice":-34.7,"GoodsUrl":"https://book.kongfz.com/911923/8761066348","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbdfebfb/29358101e6344448_b.jpg","GoodsImgCount":"1","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500923909","title":"陈式太极拳五功八法十三势","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.7,"price":4.9,"shippingFee":5.8,"differencePrice":-10.7,"GoodsUrl":"https://book.kongfz.com/703680/8288986467","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecffcff/7ec83cb4d94bafd5_b.jpg","GoodsImgCount":"3","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506367608","title":"那个骑轮箱来的蜜儿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/788761/8822390367","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddecfeba/cdd744b263a7e6e1_b.jpg","GoodsImgCount":"1","onSaleCount":108,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505619050","title":"抵岸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":45,"shippingFee":4,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/585018/8894888641","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaafcdcb/89e23d1b5842789f_b.jpg","GoodsImgCount":"8","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522609096","title":"安顿自己 76岁日本女性专家真理子奶奶教你如何过好这一生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":3,"shippingFee":2.4,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/692223/8526088916","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcfbaad/756f18d7352b9e62_b.jpg","GoodsImgCount":"1","onSaleCount":170,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534190711","title":"补益中药实用技巧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.5,"price":3,"shippingFee":3.5,"differencePrice":-6.5,"GoodsUrl":"https://book.kongfz.com/884581/8442926178","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbdcebac/cef24561f15d8822_b.jpg","GoodsImgCount":"5","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500621775","title":"篆刻欣赏 9787500621775","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.65,"price":3.15,"shippingFee":3.5,"differencePrice":-6.65,"GoodsUrl":"https://book.kongfz.com/507381/7533225690","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13271240/a8653532485645de_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108003461","title":"红楼启示录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/398369/8193296634","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfdaabaf/892c48e88bbcdc59_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532139255","title":"考骨纪 北疆生死契 张硕 上海文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/398369/8420118970","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aafafbed/94ce7550b610293d_b.jpg","GoodsImgCount":"1","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519296544","title":"心理学考研重难点1200题","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/135543/8584685391","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbfbfcf/2462ed352d3f44f8_b.jpg","GoodsImgCount":"2","onSaleCount":56,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301279816","title":"贝壳博物馆 博物文库/自然博物馆丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":234,"price":230,"shippingFee":4,"differencePrice":-234,"GoodsUrl":"https://book.kongfz.com/884382/8100768943","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beeeccfa/6424ef37f54fd9bf_b.jpg","GoodsImgCount":"13","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302563273","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301326381","title":"股权、控制权与公司治理:120个实务问题解析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/11146/8755374340","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaaeebd/0672c84311716bdf_b.jpg","GoodsImgCount":"8","onSaleCount":113,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558609701","title":"中外经典故事连环画——中国古代神话故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":13,"shippingFee":0,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/622488/5080907449","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdaebdb/b76efed91207d395_b.jpg","GoodsImgCount":"2","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571400064","title":"说手—太极拳静思录(承道篇)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42,"price":34,"shippingFee":8,"differencePrice":-42,"GoodsUrl":"https://book.kongfz.com/597518/8053281899","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccecdcda/aeab93b2adf2a81c_b.jpg","GoodsImgCount":"7","onSaleCount":100,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540000103","title":"罗通扫北","quality":0,"qualityText":"","originalPrice":0,"totalPrice":46,"price":46,"shippingFee":0,"differencePrice":-46,"GoodsUrl":"https://book.kongfz.com/370626/7929080243","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aefbedbc/a4fc65d52116f37f_b.jpg","GoodsImgCount":"3","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511327925","title":"读史有智慧用史有学问","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":14,"shippingFee":3,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/268442/8600009342","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafbcbab/396f0e52bd7a25d9_b.jpg","GoodsImgCount":"9","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787226038857","title":"中国近代文物事业简史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":16,"shippingFee":10,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/15851/688431873","imgBigUrl":"https://www0.kfzimg.com/W03/14/12/141221cee4836b17ae8e215d8c10180e_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540421434","title":"跟我学手风琴弹唱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.8,"price":9.8,"shippingFee":6,"differencePrice":-15.8,"GoodsUrl":"https://book.kongfz.com/257028/1108204319","imgBigUrl":"https://www0.kfzimg.com/G07/M00/E0/92/qoYBAFwjPOCAZqP-AAGp7_le9_0427_b.jpg","GoodsImgCount":"3","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539317311","title":"福建印人传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36,"price":30,"shippingFee":6,"differencePrice":-36,"GoodsUrl":"https://book.kongfz.com/26986/8178082271","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcfccecd/014b311a1df3276d_b.jpg","GoodsImgCount":"4","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787114114298","title":"物流产业发展规划理论与实践","quality":0,"qualityText":"","originalPrice":0,"totalPrice":777780.3,"price":777780.3,"shippingFee":0,"differencePrice":-777780.3,"GoodsUrl":"https://book.kongfz.com/390985/8890465732","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C4/B6/p4YBAFq4r2iAEiqwAAC_IROI4fY072_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806227794","title":"揭开雍正皇帝隐秘的面纱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.5,"price":7.5,"shippingFee":10,"differencePrice":-17.5,"GoodsUrl":"https://book.kongfz.com/603552/7638624490","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcbdbda/df84853aea96acc6_b.jpg","GoodsImgCount":"1","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562050445","title":"程序即是惩罚:基层刑事法院的案件处理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.14,"price":9.14,"shippingFee":6,"differencePrice":-15.14,"GoodsUrl":"https://book.kongfz.com/560577/8422900551","imgBigUrl":"https://www0.kfzimg.com/G06/M00/63/D0/p4YBAFq-KauAZ5KrAACo4MqJ-oY907_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512721722","title":"不止文静","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.3500000000000005,"price":1.7,"shippingFee":5.65,"differencePrice":-7.3500000000000005,"GoodsUrl":"https://book.kongfz.com/743642/8767293788","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfeebade/d7b6b7c62b2a40e5_b.jpg","GoodsImgCount":"3","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535795168","title":"第一推动丛书 物理系列:完美理论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":6,"shippingFee":6,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/206084/8817868442","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6137288/629b1a53703318bb_b.jpg","GoodsImgCount":"6","onSaleCount":113,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559623102","title":"顶级销售的111条军规","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.57,"price":7.57,"shippingFee":4,"differencePrice":-11.57,"GoodsUrl":"https://book.kongfz.com/607359/8796692730","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E7/C4/p4YBAFt_h6uANn-6AADhap7U0Cs462_b.jpg","GoodsImgCount":"1","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531214151","title":"名家彩图鉴赏名杉崎由绮琉 琉璃色的天使","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":8,"shippingFee":0,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/208724/6365919000","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6206642/305ac1b89c25cda6_b.jpg","GoodsImgCount":"3","onSaleCount":208,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511883018","title":"中华人民共和国森林法 最新修订版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.54,"price":0.04,"shippingFee":4.5,"differencePrice":-4.54,"GoodsUrl":"https://book.kongfz.com/757209/8460373718","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaedbbba/b0b467ad7807e8c8_b.jpg","GoodsImgCount":"2","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510143618","title":"邦臣小红花 神奇洞洞书 这是什么颜色 北京小红花图书工作室 中国人口出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.73,"price":2.73,"shippingFee":5,"differencePrice":-7.73,"GoodsUrl":"https://book.kongfz.com/263231/8827442067","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daebfcdd/21853a8d3d6b6f4e_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108028310","title":"语文常谈:中学图书馆文库","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":3,"shippingFee":7,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/346280/8715238629","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebecffaa/c0082bbaa022388a_b.jpg","GoodsImgCount":"4","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539050904","title":"图解黄帝内经(中国养生第一书 经典图解畅销版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":10,"shippingFee":4,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/20902/8088357878","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beacfaae/051481bdbde5a4c7_b.jpg","GoodsImgCount":"3","onSaleCount":313,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111326236","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508095950","title":"我命在我也在天:道家筋经内传指略","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":20,"shippingFee":5,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/849894/8780983692","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccfbfbeb/c181eed498b667bd_b.jpg","GoodsImgCount":"6","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535971531","title":"潮式风味点心制作工艺(广东省“粤菜师傅”工程培训教材)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.89,"price":8.89,"shippingFee":5,"differencePrice":-13.89,"GoodsUrl":"https://book.kongfz.com/502929/8245471444","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdfddbb/7d433d18b88839e7_b.jpg","GoodsImgCount":"11","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501400881","title":"谍海沉浮三十年:休.汉布尔顿的双重生涯(//1988-07一版一印馆藏未翻阅自然旧近10品/见描述/2)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":10,"shippingFee":14,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/7229/644810045","imgBigUrl":"https://www0.kfzimg.com/G05/M00/05/41/p4YBAFjFSF2Ab6FaAAClse2zg6k836_b.jpg","GoodsImgCount":"3","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505920514","title":"中国神仙养生大全","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":28,"shippingFee":10,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/233973/8813481496","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafadabd/21780c3c3a50a749_b.jpg","GoodsImgCount":"5","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040433647","title":"环境工程原理第3版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.4699999999999998,"price":0.47,"shippingFee":3,"differencePrice":-3.4699999999999998,"GoodsUrl":"https://book.kongfz.com/830714/8836053658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faddeebf/73e1130a978eb2ab_b.jpg","GoodsImgCount":"1","onSaleCount":333,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562353416","title":"我们这样做生本教育·数学篇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.730000000000004,"price":26.73,"shippingFee":6,"differencePrice":-32.730000000000004,"GoodsUrl":"https://book.kongfz.com/701775/8673274568","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fddbbdea/243269b1eea9ec2d_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208093973","title":"忧伤的老板","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/284909/6860484341","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feeddceb/3070df6c3b2af8ed_b.jpg","GoodsImgCount":"7","onSaleCount":119,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507532890","title":"蒋经国传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.11,"price":15.11,"shippingFee":6,"differencePrice":-21.11,"GoodsUrl":"https://book.kongfz.com/845061/7763922871","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cebaaefb/007eff2770c0243f_b.jpg","GoodsImgCount":"9","onSaleCount":319,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111497929","title":"零基础学内部审计","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":36,"shippingFee":7,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/521179/7169944650","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbfcfaf/ec51ee601eb33d49_b.jpg","GoodsImgCount":"4","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511575678","title":"北京四中语文课:细说诗文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":15,"shippingFee":5,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/902933/8887092520","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edbebdaa/f72f2a49d8f650cd_b.jpg","GoodsImgCount":"4","onSaleCount":136,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559629906","title":"新书-- 后浪·因为我有生活:电影美术师杨占家从艺录(精装)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":7,"shippingFee":7,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/680109/8164552567","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/306/3af6ecaa708cfe4d_b.jpg","GoodsImgCount":"1","onSaleCount":160,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810035767","title":"三皇炮捶一北京镖局拳术功法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":78,"price":68,"shippingFee":10,"differencePrice":-78,"GoodsUrl":"https://book.kongfz.com/17030/7934731735","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faacbdfe/9dd500da308d84fb_b.jpg","GoodsImgCount":"6","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532256327","title":"中外设计艺术论著精读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.2,"price":7.2,"shippingFee":5,"differencePrice":-12.2,"GoodsUrl":"https://book.kongfz.com/180897/8429017414","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/affbbacd/c725a34076a44bc5_b.jpg","GoodsImgCount":"1","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787576406528","title":"环境法调整范围问题研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.72,"price":13.72,"shippingFee":7,"differencePrice":-20.72,"GoodsUrl":"https://book.kongfz.com/753811/8420113257","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14256494/0c2399ce4c56befd_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530522493","title":"棋魂·光之棋(15)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.8,"price":3.8,"shippingFee":12,"differencePrice":-15.8,"GoodsUrl":"https://book.kongfz.com/259232/3263082368","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efbaeadf/d6e0defb6c2112d3_b.jpg","GoodsImgCount":"3","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115455611","title":"股市T+0交易实战技法图解升级版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.45,"price":6.95,"shippingFee":5.5,"differencePrice":-12.45,"GoodsUrl":"https://book.kongfz.com/898097/8767386927","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/debffbda/75ccfb20d83a74a1_b.jpg","GoodsImgCount":"2","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547717455","title":"来点给力的正能量 让我更加积极向上的故事 做最好的自己","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.52,"price":1.12,"shippingFee":2.4,"differencePrice":-3.52,"GoodsUrl":"https://book.kongfz.com/561672/8424838977","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfafacec/f67f9a463082e593_b.jpg","GoodsImgCount":"1","onSaleCount":116,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303099771","title":"自信的提升","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":15,"shippingFee":0,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/783975/7001458250","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecbbaac/c1db02303b2b0bbc_b.jpg","GoodsImgCount":"5","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513318365","title":"二手昆虫漫话科普经典文库新星","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.49,"price":4.49,"shippingFee":2,"differencePrice":-6.49,"GoodsUrl":"https://book.kongfz.com/769044/7879074016","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caaeebac/90432555072321fe_b.jpg","GoodsImgCount":"3","onSaleCount":214,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117172028","title":"·医学影像学第7版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.88,"price":0.08,"shippingFee":3.8,"differencePrice":-3.88,"GoodsUrl":"https://book.kongfz.com/237705/8801387036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaddeaff/0a5c6cac3826b2fc_b.jpg","GoodsImgCount":"1","onSaleCount":325,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787312027079","title":"高等学校过渡教材读本 高中数学大学数学基本习题练习高三学生升大学大一新生数学过渡 谢盛刚 中国科学技术大学出版社图书籍","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.37,"price":7.37,"shippingFee":10,"differencePrice":-17.37,"GoodsUrl":"https://book.kongfz.com/374786/8679077396","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11488598/edc93870210278b7_b.jpg","GoodsImgCount":"1","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506731584","title":"孰能无错:创建更加安全的医疗卫生保健系统","quality":0,"qualityText":"","originalPrice":0,"totalPrice":119.47,"price":107.47,"shippingFee":12,"differencePrice":-119.47,"GoodsUrl":"https://book.kongfz.com/912097/8236582135","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23092773/64be6ccad3f4056e_b.jpg","GoodsImgCount":"2","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806325162","title":"股市预测方法大全","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":6.7,"shippingFee":5,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/911923/8760299166","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfafeeed/53759abb4d28ec0a_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501167326","title":"斯大林:鲜为人知的剖面","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.13,"price":19.13,"shippingFee":3,"differencePrice":-22.13,"GoodsUrl":"https://book.kongfz.com/566350/8837106767","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abcfdcca/3069be6490f47334_b.jpg","GoodsImgCount":"6","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544430548","title":"中国近现代学校音乐教育(1840-1949)(1949-1995)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":20,"shippingFee":6,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/27200/6963259840","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeaacada/c8352f4dd943f78f_b.jpg","GoodsImgCount":"5","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121281839","title":"内分泌决定女人健康","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.5,"price":7,"shippingFee":2.5,"differencePrice":-9.5,"GoodsUrl":"https://book.kongfz.com/361618/8008064383","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dccddaee/22195ad9be22f208_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506322751","title":"巴黎 艺术至上","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9399999999999995,"price":1.94,"shippingFee":5,"differencePrice":-6.9399999999999995,"GoodsUrl":"https://book.kongfz.com/820017/8872308665","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcaabdff/8609546f9f9d59d4_b.jpg","GoodsImgCount":"2","onSaleCount":110,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559437839","title":"遗忘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":8,"shippingFee":3,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/268442/8358622148","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dceaeeaf/d6f93765fd88c265_b.jpg","GoodsImgCount":"6","onSaleCount":143,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521740288","title":"华为组织力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":15,"shippingFee":9,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/762356/6953163766","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14883503/80b35d52657b3996_b.jpg","GoodsImgCount":"1","onSaleCount":135,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201161969","title":"地球上线.3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.779999999999999,"price":4.77,"shippingFee":0.01,"differencePrice":-4.779999999999999,"GoodsUrl":"https://book.kongfz.com/754078/8661022100","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbacffdf/639fc984f5b2e115_b.jpg","GoodsImgCount":"2","onSaleCount":515,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516116890","title":"美国研究十年回顾(2001-2010)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.1,"price":10.1,"shippingFee":5,"differencePrice":-15.1,"GoodsUrl":"https://book.kongfz.com/619532/7045149457","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdaacece/05f659a51981a4d6_b.jpg","GoodsImgCount":"4","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521715613","title":"航海少年团1·古灯塔的神秘之门","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.89,"price":0.09,"shippingFee":4.8,"differencePrice":-4.89,"GoodsUrl":"https://book.kongfz.com/780405/7827920500","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcabbed/2ac0d0a49357653f_b.jpg","GoodsImgCount":"4","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553734088","title":"神农本草经(精版) 9787553734088","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.86,"price":12.86,"shippingFee":2,"differencePrice":-14.86,"GoodsUrl":"https://book.kongfz.com/755561/8095945895","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cccaedbc/a2944602ab786932_b.jpg","GoodsImgCount":"2","onSaleCount":202,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533935085","title":"各自的朝圣路","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":4.5,"shippingFee":0,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/356195/8895884096","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/a1472ea00606d477_b.jpg","GoodsImgCount":"5","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802504004","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030080509","title":"接口电路入门","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":3,"shippingFee":8,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/737383/6250535451","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdaaaec/4255d8b549208d2b_b.jpg","GoodsImgCount":"6","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508056180","title":"内功是怎样炼成的","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":26.8,"shippingFee":3,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/1087817/8643065121","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adfaaafb/dc1ba998f7f55ecf_b.jpg","GoodsImgCount":"6","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300089089","title":"传播学专业英语教程(第四版) 巴兰 中国人民大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":4.9,"shippingFee":3,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/521005/8353652390","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C6/1B/p4YBAFqYPGyAGqpqAAC62maQM4A311_b.jpg","GoodsImgCount":"1","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787563399789","title":"诗歌读本(学前卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25.22,"price":14.22,"shippingFee":11,"differencePrice":-25.22,"GoodsUrl":"https://book.kongfz.com/832731/7502436066","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22203957/acb0519120203613_b.jpg","GoodsImgCount":"2","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508659121","title":"小熊很忙中英双语厚纸板游戏书:快乐的假期","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":1,"shippingFee":10,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/281327/8827437261","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddaafcaf/7c85a7abd7215d33_b.jpg","GoodsImgCount":"6","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516530399","title":"未来世界","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.690000000000001,"price":6.69,"shippingFee":5,"differencePrice":-11.690000000000001,"GoodsUrl":"https://book.kongfz.com/1212927/8625774682","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabfaeed/effb81294d8913ec_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507305227","title":"从宝塔山到中南海","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":20,"shippingFee":15,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/669739/8486939181","imgBigUrl":"https://www0.kfzimg.com/G07/M00/FA/0C/q4YBAFywU4aAImriAABJ4X3BxME372_b.jpg","GoodsImgCount":"1","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541018961","title":"【涵套装】中国西部太阳谷——得荣:[中英藏文本]","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":26,"shippingFee":9,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/439962/6640113502","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caddfaca/d7cc825d53483bca_b.jpg","GoodsImgCount":"30","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544774277","title":"远处的拉莫","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.93,"price":19.93,"shippingFee":5,"differencePrice":-24.93,"GoodsUrl":"https://book.kongfz.com/202798/8665745337","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcabcbac/c0577cb97558c6f2_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501048014","title":"大美之佛像:犍陀罗艺术(16开精装 全1册)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":104.88,"price":98.88,"shippingFee":6,"differencePrice":-104.88,"GoodsUrl":"https://book.kongfz.com/386071/8241300300","imgBigUrl":"https://www0.kfzimg.com/G06/M00/EB/82/p4YBAFqhN8yAXG-yAADLMdZzwV4982_b.jpg","GoodsImgCount":"1","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547259863","title":"回话的技术","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.7800000000000002,"price":0.78,"shippingFee":2,"differencePrice":-2.7800000000000002,"GoodsUrl":"https://book.kongfz.com/738826/8530510157","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdcadebc/80a28b6c4a823131_b.jpg","GoodsImgCount":"1","onSaleCount":1640,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519102586","title":"【正版二手书籍】 幼儿园科学领域教育精要:关键经验与活动指导 175-5-2-127","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.95,"price":8.95,"shippingFee":2,"differencePrice":-10.95,"GoodsUrl":"https://book.kongfz.com/826462/8673356833","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22052838/3f2484448a8e7784_b.jpg","GoodsImgCount":"3","onSaleCount":105,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533263423","title":"没有秘密长不大","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.01,"price":0.01,"shippingFee":3,"differencePrice":-3.01,"GoodsUrl":"https://book.kongfz.com/891713/7988364522","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdbefbe/fe803e1c2690f4d9_b.jpg","GoodsImgCount":"4","onSaleCount":830,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806598436","title":"佛教灵验记研究:以晋唐为中心","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":40,"shippingFee":8,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/23842/8011951958","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3149222/bc752f79a0734a0f_b.jpg","GoodsImgCount":"5","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564129255","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115352491","title":"Photoshop CS6实战从入门到精通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.5,"price":3.5,"shippingFee":0,"differencePrice":-3.5,"GoodsUrl":"https://book.kongfz.com/372285/8607946044","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbdafff/0e356f4ae5d6050d_b.jpg","GoodsImgCount":"4","onSaleCount":236,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506382298","title":"三重门-十五周年纪念版9787506382298","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.2,"price":3.6,"shippingFee":2.6,"differencePrice":-6.2,"GoodsUrl":"https://book.kongfz.com/20579/8888133382","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfcbdfb/c68163ee23660130_b.jpg","GoodsImgCount":"1","onSaleCount":53,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560381299","title":"拉马努金遗失笔记(第一卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":110,"price":105,"shippingFee":5,"differencePrice":-110,"GoodsUrl":"https://book.kongfz.com/319561/8249081973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcecbafe/c29d43db77317553_b.jpg","GoodsImgCount":"9","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500869016","title":"诡盗团","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.4,"price":10,"shippingFee":5.4,"differencePrice":-15.4,"GoodsUrl":"https://book.kongfz.com/7546/8297358995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abdbfdde/76f2d0edb31829de_b.jpg","GoodsImgCount":"2","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540343927","title":"中华成语全典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":90,"price":78,"shippingFee":12,"differencePrice":-90,"GoodsUrl":"https://book.kongfz.com/602730/8697095825","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbaccafa/924c480acee402ce_b.jpg","GoodsImgCount":"4","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553420394","title":"西方经典哲学之旅系列 荣格的性格哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.859999999999999,"price":0.06,"shippingFee":4.8,"differencePrice":-4.859999999999999,"GoodsUrl":"https://book.kongfz.com/245306/8510038095","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdeafdd/43d52666b500e80f_b.jpg","GoodsImgCount":"1","onSaleCount":188,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502541897","title":"润滑剂与润滑(有水印)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":39,"shippingFee":10,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/353752/8432573477","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deeecfdd/2761ee960fe2bd5b_b.jpg","GoodsImgCount":"6","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572617270","title":"《我准备好了,变老也没关系》","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.9,"price":11.9,"shippingFee":6,"differencePrice":-17.9,"GoodsUrl":"https://book.kongfz.com/901995/8697497893","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13196094/c59e3bd7277ec52d_b.jpg","GoodsImgCount":"1","onSaleCount":161,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508663920","title":"商业区块链 开启加密经济新时代威廉 穆贾雅 著 林华 等 译中信出版社9787508663920","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.01,"price":4.01,"shippingFee":0,"differencePrice":-4.01,"GoodsUrl":"https://book.kongfz.com/248516/8732168980","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/f4e2971f8af4ba85_b.jpg","GoodsImgCount":"1","onSaleCount":331,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308022279","title":"中央银行关金券·金圆券","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/364294/8442165598","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedfbadc/a39d3b2c67fb7320_b.jpg","GoodsImgCount":"4","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503883880","title":"IUCN自然保护地管理分类应用指南:纪念中国自然保护区建设60周年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/274216/8872061006","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adefaafa/ec00a58c55648b0d_b.jpg","GoodsImgCount":"4","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221041524","title":"大唐西域记全译","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":23,"shippingFee":5,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/1207201/8690378400","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abacbffd/2e48df6c99d72e02_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506748438","title":"国医大师颜德馨","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":36,"shippingFee":7,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/15548/6439625257","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceffcafa/676a35c42ee7db3f_b.jpg","GoodsImgCount":"3","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221158017","title":"我当心理咨询师遇到的那些怪诞事件3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.8,"price":8,"shippingFee":3.8,"differencePrice":-11.8,"GoodsUrl":"https://book.kongfz.com/198833/7419472199","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5862318/942b1c4a6bced624_b.jpg","GoodsImgCount":"1","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522604435","title":"安英的魅力口才","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.33,"price":7.33,"shippingFee":3,"differencePrice":-10.33,"GoodsUrl":"https://book.kongfz.com/566350/8859451482","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/15424286/0c9700a9eeda2a28_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787574204058","title":"新编医圣张仲景奇方妙治","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.24,"price":3.24,"shippingFee":5,"differencePrice":-8.24,"GoodsUrl":"https://book.kongfz.com/1154627/8795652570","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfacacce/1f4e1df9d8365907_b.jpg","GoodsImgCount":"2","onSaleCount":246,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547908051","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503232589","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549630356","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111674887","title":"Rhino7犀利建模","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.86,"price":7.86,"shippingFee":0,"differencePrice":-7.86,"GoodsUrl":"https://book.kongfz.com/638685/8631701848","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3656/0329a70d76c057ea6f_b.jpg","GoodsImgCount":"1","onSaleCount":143,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532924899","title":"请大家保护自己的腰/新活力作家文丛","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55.98,"price":45.98,"shippingFee":10,"differencePrice":-55.98,"GoodsUrl":"https://book.kongfz.com/832982/7495387597","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22231533/28e7f7f1bdb87c7f_b.jpg","GoodsImgCount":"2","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502419035","title":"重有色金属冶炼设计手册:冶炼烟气收尘·通用工程(常用数据卷)(藏书\\无笔记\\实物拍摄)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":228,"price":220,"shippingFee":8,"differencePrice":-228,"GoodsUrl":"https://book.kongfz.com/218311/7537560196","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/effdedef/6c145f37a0818a46_b.jpg","GoodsImgCount":"14","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787304093150","title":"DK玩出来的百科:棋子数学游戏(新版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/678667/7919607286","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bffefdbb/7bfd77f54abb77e1_b.jpg","GoodsImgCount":"4","onSaleCount":163,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500475965","title":"精英与资本:转型期中国乡村精英结构变迁的实证研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.4,"price":5,"shippingFee":4.4,"differencePrice":-9.4,"GoodsUrl":"https://book.kongfz.com/12041/8322135237","imgBigUrl":"https://www0.kfzimg.com/G06/M00/2E/97/p4YBAFs0qnmAL_i4AACf9Lup5DI641_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534059308","title":"排球少年!! 2:最高处的风景","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.5,"price":4.5,"shippingFee":6,"differencePrice":-10.5,"GoodsUrl":"https://book.kongfz.com/648064/8020657037","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbfddbcd/2983bfa0f566d3be_b.jpg","GoodsImgCount":"7","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787563392926","title":"浮生:清美凄凉的伶人传奇 馆藏无笔迹","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.2,"price":0.2,"shippingFee":6,"differencePrice":-6.2,"GoodsUrl":"https://book.kongfz.com/180265/5033827968","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feecdbac/ef77ae61ce991e03_b.jpg","GoodsImgCount":"2","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508682945","title":"我的世界就是一座花园","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.6,"price":17.6,"shippingFee":10,"differencePrice":-27.6,"GoodsUrl":"https://book.kongfz.com/901511/8212002579","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caddcbaf/376c04b8d6e29e64_b.jpg","GoodsImgCount":"4","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101040418","title":"三曹资料汇编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":54.42,"price":45.42,"shippingFee":9,"differencePrice":-54.42,"GoodsUrl":"https://book.kongfz.com/797172/8353517037","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21462970/467b1a4dcf01baf8_b.jpg","GoodsImgCount":"1","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530888469","title":"健康有捷径:气血旺 百病消","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/262475/4642903053","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfddfdfd/292f2b4eb304bb3e_b.jpg","GoodsImgCount":"9","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544789332","title":"人文与社会译丛:风险社会","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":12,"shippingFee":8,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/591983/8368601013","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baeafbdb/ba8a68ab686c5496_b.jpg","GoodsImgCount":"5","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201110066","title":"正版 小鹿斑比 费利克斯 萨尔腾一部关于爱 成长与生命的童话 迪士尼同名动画原著小说 儿童文学 迪士尼 果麦图书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":45.5,"price":33.5,"shippingFee":12,"differencePrice":-45.5,"GoodsUrl":"https://book.kongfz.com/765896/6847101073","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20763945/401ff2ad8d22b54c_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521702019","title":"地球","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.93,"price":18.93,"shippingFee":10,"differencePrice":-28.93,"GoodsUrl":"https://book.kongfz.com/791821/8547538750","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/564/6d855bb66320948e_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121288579","title":"高效运作项目管理办公室:PMO实践、案例和启示 张富民 著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.04,"price":12.04,"shippingFee":0,"differencePrice":-12.04,"GoodsUrl":"https://book.kongfz.com/169647/8662261121","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3674971/90a67a9cc84613ca_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511361547","title":"股市心理战:一位资深股民的投资哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":25,"shippingFee":10,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/356104/4811368206","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaefbafe/a5e0de1094aec3d8_b.jpg","GoodsImgCount":"3","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547239438","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800689659","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040274202","title":"设计原理彭澎编著高等教育出版社9787040274202","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.79,"price":4.79,"shippingFee":0,"differencePrice":-4.79,"GoodsUrl":"https://book.kongfz.com/366030/8354018430","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/03d8b190e2261d50_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542847621","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801786029","title":"【原版闪电发货】原《金口诀应用学》(各类实战例题解读)/张得计大小六壬入门四柱学盲派书籍图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":50.4,"price":40.4,"shippingFee":10,"differencePrice":-50.4,"GoodsUrl":"https://book.kongfz.com/274158/7360476472","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9625326/3ee67f794e6b1f58_b.jpg","GoodsImgCount":"2","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503400032","title":"忆往谈旧录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.1,"price":8.1,"shippingFee":3,"differencePrice":-11.1,"GoodsUrl":"https://book.kongfz.com/577988/7210036783","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdffcae/40a87de7683567d9_b.jpg","GoodsImgCount":"3","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559608710","title":"高敏感是种天赋 拯救全球15亿人的心灵之书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.55,"price":6.05,"shippingFee":1.5,"differencePrice":-7.55,"GoodsUrl":"https://book.kongfz.com/825417/8696502179","imgBigUrl":"https://www0.kfzimg.com/G06/M00/CB/77/p4YBAFqYl1eAXrB-AADwJUlM01E764_b.jpg","GoodsImgCount":"0","onSaleCount":467,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532264643","title":"铠甲勇士·刑天:对战大图鉴1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":20,"shippingFee":8,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/261367/8881674842","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dacfeccc/2c82927f965d5eea_b.jpg","GoodsImgCount":"11","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553443751","title":"菲尔博士率众前来","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":9,"shippingFee":8,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/188947/8481004836","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbdacdf/05ba38b868d0fca8_b.jpg","GoodsImgCount":"7","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305032974","title":"孟子评传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":148,"price":148,"shippingFee":0,"differencePrice":-148,"GoodsUrl":"https://book.kongfz.com/15335/8300858073","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baccaafc/a39615a199559525_b.jpg","GoodsImgCount":"8","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508678993","title":"我愿意等,熊猫先生(单册价格,套装咨询客服)(单册价格,套装咨询客服)(单册价格,套装咨询客服)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.91,"price":7.91,"shippingFee":2,"differencePrice":-9.91,"GoodsUrl":"https://book.kongfz.com/769044/8613050954","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdbfbdf/00d80d1cc0ca28cc_b.jpg","GoodsImgCount":"2","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538550368","title":"疯了!桂宝(第贰卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.09,"price":0.09,"shippingFee":5,"differencePrice":-5.09,"GoodsUrl":"https://book.kongfz.com/11912/5836900069","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbaecaeb/c5c246f371e9cc2a_b.jpg","GoodsImgCount":"4","onSaleCount":161,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532750108","title":"炎夏之都","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32,"price":23,"shippingFee":9,"differencePrice":-32,"GoodsUrl":"https://book.kongfz.com/810477/8511733932","imgBigUrl":"https://www0.kfzimg.com/G06/M00/DE/4B/p4YBAFrUlHCAH8skAAB13jNBPts242_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514302646","title":"素食达人","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.95,"price":4.95,"shippingFee":4,"differencePrice":-8.95,"GoodsUrl":"https://book.kongfz.com/1027325/8690643837","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccafdaaf/ecd79dc361fa7827_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500489559","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549559299","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115525932","title":"建筑施工会计真账实操全流程演练第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.82,"price":6.82,"shippingFee":0,"differencePrice":-6.82,"GoodsUrl":"https://book.kongfz.com/548348/8649348889","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/801/8da2143eeaea7a0b_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302165682","title":"清华大学化学类教材:简明物理化学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31.78,"price":24.78,"shippingFee":7,"differencePrice":-31.78,"GoodsUrl":"https://book.kongfz.com/722739/8596219163","imgBigUrl":"https://www0.kfzimg.com/G06/M00/42/8C/p4YBAFqbhNuARHsYAAB-WYFXRzQ862_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101100938","title":"宋词三百首","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.780000000000001,"price":4.78,"shippingFee":4,"differencePrice":-8.780000000000001,"GoodsUrl":"https://book.kongfz.com/330788/8429376914","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbaffcff/acaca30e37ab4659_b.jpg","GoodsImgCount":"1","onSaleCount":145,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800137495","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512679436","title":"原来化学可以这样学 化学奇谈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.25,"price":0.25,"shippingFee":5,"differencePrice":-5.25,"GoodsUrl":"https://book.kongfz.com/202798/8459717610","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcecdaaf/b6227047461d7a66_b.jpg","GoodsImgCount":"1","onSaleCount":237,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9780375813658","title":"Magic Tree House Books #1-4神奇树屋合辑(1-4)(缺3册)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":4,"shippingFee":8,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/5669/7756604676","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1278/ecde0a6674bba01f_b.jpg","GoodsImgCount":"3","onSaleCount":72,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556828623","title":"苍蝇和大象的足球赛米切尔 恩德20周年纪念版精装","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.86,"price":5.86,"shippingFee":5,"differencePrice":-10.86,"GoodsUrl":"https://book.kongfz.com/911923/8827352288","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dacdaecc/d202436c78aecf55_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300145365","title":"刑法各论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/265019/8666457069","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C7/25/p4YBAFqYP2SACg9mAACfG_cnNJI045_b.jpg","GoodsImgCount":"1","onSaleCount":86,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787551715843","title":"VI设计9787551715843","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.69,"price":0.19,"shippingFee":3.5,"differencePrice":-3.69,"GoodsUrl":"https://book.kongfz.com/1152148/8524904150","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/becaaeef/50d6f4ba2c5a29e3_b.jpg","GoodsImgCount":"3","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532793365","title":"安娜·卡列尼娜的真实故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":25,"shippingFee":4.8,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/567272/8398230717","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abcfbbca/a0f81346232c398b_b.jpg","GoodsImgCount":"1","onSaleCount":124,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556101429","title":"爸爸去哪儿(实用版)超级龙蛋王亲子互动漫画(未拆封)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.5,"price":15,"shippingFee":5.5,"differencePrice":-20.5,"GoodsUrl":"https://book.kongfz.com/346699/4684397376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6198840/45e55b1a2a1686ca_b.jpg","GoodsImgCount":"3","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511354785","title":"高效经营法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":7,"shippingFee":10,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/356060/8256005905","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcfceede/8183e6993263453c_b.jpg","GoodsImgCount":"3","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535692023","title":"浮世绘【浦睿文化出品】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.99,"price":22.99,"shippingFee":5,"differencePrice":-27.99,"GoodsUrl":"https://book.kongfz.com/914444/8566543484","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abccddda/84545b02d8c7d573_b.jpg","GoodsImgCount":"8","onSaleCount":151,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507737172","title":"神农本草经读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36.14,"price":24.14,"shippingFee":12,"differencePrice":-36.14,"GoodsUrl":"https://book.kongfz.com/795825/7321125946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14523379/60a9962271d44fca_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556240944","title":"儿童英语轻松学系列 儿童英语启蒙1000词","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.050000000000001,"price":2.16,"shippingFee":2.89,"differencePrice":-5.050000000000001,"GoodsUrl":"https://book.kongfz.com/785333/8282614242","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebbbeebb/ec1d8b32a5bea2e3_b.jpg","GoodsImgCount":"1","onSaleCount":121,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550042308","title":"丰子恺给孩子的阅读写作课 游记卷 丰子恺著绘 张伟锋点评 白马时光出品 百花洲文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":2.9,"shippingFee":5,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/398369/8726837081","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addfdfdc/53c3f12c6f960ff8_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111667278","title":"IT运维服务管理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.26,"price":16.26,"shippingFee":0,"differencePrice":-16.26,"GoodsUrl":"https://book.kongfz.com/196857/8731918717","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2750/02491aeaaef30c5f3b_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544490337","title":"白马湖书系 培养真正的阅读者 整本书阅读之理论基础 吴欣歆 上海教育出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.59,"price":7.59,"shippingFee":5,"differencePrice":-12.59,"GoodsUrl":"https://book.kongfz.com/903313/8744997561","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efeeabfe/6b03cfc027eedc60_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539554594","title":"云梦泽屠龙记鬼谷学校 第五卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.01,"price":4.01,"shippingFee":3,"differencePrice":-7.01,"GoodsUrl":"https://book.kongfz.com/1181761/8874528061","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daceffce/ebcdaf1d65f390fb_b.jpg","GoodsImgCount":"1","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309079418","title":"三十七道品偈诵释义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":6,"shippingFee":6,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/386898/7963978478","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daefeadc/063dce8cf89efcab_b.jpg","GoodsImgCount":"3","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535957450","title":"寻味广东丛书:百年老店·广州老食肆与老食语","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":10,"shippingFee":4,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/203004/8386290176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeebdfa/811d13534a3f61d4_b.jpg","GoodsImgCount":"1","onSaleCount":81,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305022906","title":"数学奥林匹克题典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":17,"shippingFee":7,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/188968/7578688674","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accadcff/4b343540fbb642e0_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546376806","title":"西游记 吴承恩著 9787546376806 吉林出版集团有限责任公司","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.48,"price":3.98,"shippingFee":2.5,"differencePrice":-6.48,"GoodsUrl":"https://book.kongfz.com/237713/8683926712","imgBigUrl":"https://www0.kfzimg.com/G06/M00/49/0D/p4YBAFqbt_2AQMoYAABFGK4V49k913_b.jpg","GoodsImgCount":"1","onSaleCount":145,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521714074","title":"外国摄影师镜头里的中国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":72,"price":65,"shippingFee":7,"differencePrice":-72,"GoodsUrl":"https://book.kongfz.com/281199/8410912596","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfffacae/d2279aa3b06bc73f_b.jpg","GoodsImgCount":"11","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531171423","title":"嘻哈小天才. 9","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":16,"shippingFee":10,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/497994/8873990567","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afaefffa/165fe0bdd58127cb_b.jpg","GoodsImgCount":"10","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530500606","title":"欧洲绘画简史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.5,"price":5,"shippingFee":6.5,"differencePrice":-11.5,"GoodsUrl":"https://book.kongfz.com/754002/7204027658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdddbbcd/56f24b5b0f8784bb_b.jpg","GoodsImgCount":"4","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510888489","title":"周易本义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":20,"shippingFee":8,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/228843/6865717081","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdfdfafb/dce8a087d28c2705_b.jpg","GoodsImgCount":"1","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213013386","title":"人生絮语","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":3,"shippingFee":4,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/727057/8432652339","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbacfccd/b9fed35ba00032e8_b.jpg","GoodsImgCount":"7","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506748544","title":"国医大师唐由之","quality":0,"qualityText":"","originalPrice":0,"totalPrice":99.09,"price":90.09,"shippingFee":9,"differencePrice":-99.09,"GoodsUrl":"https://book.kongfz.com/465465/7167355375","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E2/3C/p4YBAFqY552AUUL5AACreTJSD6s208_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501946983","title":"家庭治疗基础","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38.9,"price":33.9,"shippingFee":5,"differencePrice":-38.9,"GoodsUrl":"https://book.kongfz.com/911923/8779777083","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cadeeebc/3589bebebfa3f806_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520822022","title":"中国古琴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.51,"price":8.51,"shippingFee":3,"differencePrice":-11.51,"GoodsUrl":"https://book.kongfz.com/718844/7361733092","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/19134004/9c42134fc4f080b2_b.jpg","GoodsImgCount":"1","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530149188","title":"正版图书 蒲公英中国儿童文学名家精品丛书:小巫婆的大扫帚(注音版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/525155/8129835817","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfededad/b9702bb478982502_b.jpg","GoodsImgCount":"9","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309016987","title":"孟子旁通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":11,"shippingFee":2,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/624177/8000572501","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedefadf/97ba0db0d0c9eeef_b.jpg","GoodsImgCount":"3","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544428651","title":"华师大二附中","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.4,"price":5.9,"shippingFee":5.5,"differencePrice":-11.4,"GoodsUrl":"https://book.kongfz.com/1182056/8831011997","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1632/013b0116920fd5ef7a_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501986002","title":"家具专业英语实务(普通高等教育室内与家具设计专业十二五规划教材)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":47.1,"price":40.7,"shippingFee":6.4,"differencePrice":-47.1,"GoodsUrl":"https://book.kongfz.com/561989/8852981910","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbeebcf/437692bc37429777_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558606212","title":"正版二手书书画巨匠艺库:傅抱石·傅抱石中国画法要论(精装本)9787558606212","quality":0,"qualityText":"","originalPrice":0,"totalPrice":106,"price":106,"shippingFee":0,"differencePrice":-106,"GoodsUrl":"https://book.kongfz.com/765962/8143826136","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbefebd/2596c704c26b9418_b.jpg","GoodsImgCount":"1","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544878227","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506382014","title":"西班牙在心中:反法西斯诗选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":154,"price":145,"shippingFee":9,"differencePrice":-154,"GoodsUrl":"https://book.kongfz.com/758397/8540606900","imgBigUrl":"https://www0.kfzimg.com/G06/M00/A7/E1/p4YBAFqevjeAUjMWAABuc9xLDZQ430_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500112396","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787517147213","title":"铜雀锁金钗 民国虐心必看榜单神作 高温消毒发货 世味煮茶 中国言实出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.4,"price":18.4,"shippingFee":2,"differencePrice":-20.4,"GoodsUrl":"https://book.kongfz.com/1113/8677185936","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbbaede/051a0d80939bf3c7_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506086943","title":"噼里啪啦牙菌来啦","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.99,"price":4.99,"shippingFee":5,"differencePrice":-9.99,"GoodsUrl":"https://book.kongfz.com/375512/8829692617","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccfafccd/0e5374b790a97b04_b.jpg","GoodsImgCount":"4","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530640333","title":"李叔同影事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.35,"price":5.85,"shippingFee":5.5,"differencePrice":-11.35,"GoodsUrl":"https://book.kongfz.com/789796/8145140253","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaaeacdf/bc6e13229b611f82_b.jpg","GoodsImgCount":"14","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539958316","title":"能量场","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32,"price":26,"shippingFee":6,"differencePrice":-32,"GoodsUrl":"https://book.kongfz.com/398434/8881638801","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbaeabc/7827a2f39328e335_b.jpg","GoodsImgCount":"1","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540477240","title":"《发货快》留学口语从头学 赖世雄, 吴纪维 湖南文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.37,"price":6.87,"shippingFee":0.5,"differencePrice":-7.37,"GoodsUrl":"https://book.kongfz.com/156492/8283749461","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4362605/b9672e2119790224_b.jpg","GoodsImgCount":"1","onSaleCount":62,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509629727","title":"破解股市陷阱系列之二:技术指标虚假信号及破解方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.38,"price":22.38,"shippingFee":0,"differencePrice":-22.38,"GoodsUrl":"https://book.kongfz.com/792228/8894405073","imgBigUrl":"https://www0.kfzimg.com/G06/M00/27/6C/p4YBAFqaeZOARcnDAACg7i988Vw421_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807243991","title":"5分钟和陌生人成为朋友","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.57,"price":3.57,"shippingFee":0,"differencePrice":-3.57,"GoodsUrl":"https://book.kongfz.com/887808/8391689793","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bccbffae/f8debbec62ce7351_b.jpg","GoodsImgCount":"7","onSaleCount":685,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542644916","title":"诗人的迟缓【全新带塑封】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":21,"shippingFee":8,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/85357/7659329715","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2747720/00bc6133660a1e42_b.jpg","GoodsImgCount":"10","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300279107","title":"自媒体营销施薇 李灿辉 肖凭中国人民大学出版社9787300279107","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.97,"price":3.97,"shippingFee":0,"differencePrice":-3.97,"GoodsUrl":"https://book.kongfz.com/366030/8472562730","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/b8aec546a3b2d85b_b.jpg","GoodsImgCount":"1","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806749012","title":"中央美术学院教学素描典藏2:油画系1978级至2000级","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":39,"shippingFee":10,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/353476/8412551966","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdfbdcaf/03d7eb67b33a5434_b.jpg","GoodsImgCount":"8","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508612690","title":"美国怎么了?:一个自由主义者的良知","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":3.8,"shippingFee":0,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/356195/8832243949","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/39296172e9a70322_b.jpg","GoodsImgCount":"5","onSaleCount":688,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530914144","title":"外国文学小百科","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/266365/1600675441","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/459/5bec61e229676ba7_b.jpg","GoodsImgCount":"5","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218123943","title":"早起的奇迹:那些能够在早晨8:00前改变人生的秘密","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.6,"price":6.6,"shippingFee":4,"differencePrice":-10.6,"GoodsUrl":"https://book.kongfz.com/1210014/8818511610","imgBigUrl":"https://www0.kfzimg.com/G06/M00/BE/35/p4YBAFsjew-AZMa4AADQy1ZsI-E761_b.jpg","GoodsImgCount":"0","onSaleCount":800,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559468185","title":"今日喜你(2)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.18,"price":27.28,"shippingFee":2.9,"differencePrice":-30.18,"GoodsUrl":"https://book.kongfz.com/566350/8416910242","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfadadcb/ab01eb1968feebe1_b.jpg","GoodsImgCount":"2","onSaleCount":4,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806769300","title":"上海电影图史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.41,"price":11.41,"shippingFee":2,"differencePrice":-13.41,"GoodsUrl":"https://book.kongfz.com/769034/8690883878","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdebedb/8a4108e8115dcd59_b.jpg","GoodsImgCount":"3","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787517503569","title":"2019年政策粮食库存大清查培训教材 经济理论、法规 政策粮食库存数量和质量大清查部际协调机制办公室编 新华正版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.96,"price":0.06,"shippingFee":7.9,"differencePrice":-7.96,"GoodsUrl":"https://book.kongfz.com/266593/8181243192","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffeffcdf/08facbab7c467c40_b.jpg","GoodsImgCount":"3","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218112039","title":"走进客家历史田野","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.67,"price":13.67,"shippingFee":2,"differencePrice":-15.67,"GoodsUrl":"https://book.kongfz.com/877749/8552934938","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/dbe28f6f66ba679c_b.jpg","GoodsImgCount":"2","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806460733","title":"千古名赋 咬文嚼字书林 吟诵卷 高建中选注 上海文化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.280000000000001,"price":7.28,"shippingFee":5,"differencePrice":-12.280000000000001,"GoodsUrl":"https://book.kongfz.com/180897/8848284913","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feefcbda/544e560d07370a8f_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221126634","title":"在血与火中穿行","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.4399999999999995,"price":1.44,"shippingFee":3,"differencePrice":-4.4399999999999995,"GoodsUrl":"https://book.kongfz.com/371891/3670304267","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafcdcea/832f209afe7f1e48_b.jpg","GoodsImgCount":"7","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501035120","title":"吴门篆刻史研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.46,"price":28.96,"shippingFee":3.5,"differencePrice":-32.46,"GoodsUrl":"https://book.kongfz.com/904671/8420602978","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dedcceac/a3f246f9df94771a_b.jpg","GoodsImgCount":"1","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522901176","title":"烹饪原料学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":9,"shippingFee":7,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/791901/8236858701","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbaafabd/d14d90ded1b4853a_b.jpg","GoodsImgCount":"14","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515304786","title":"器材大师2佳能EOS60D数码单反摄影完全攻略","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.05,"price":7.55,"shippingFee":4.5,"differencePrice":-12.05,"GoodsUrl":"https://book.kongfz.com/531994/8713723345","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfaaedc/5774b1aee3694d8d_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535557865","title":"经济学大纲李达著湖南教育出版社正版马克思主义经济学教科书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":96.60000000000001,"price":86.7,"shippingFee":9.9,"differencePrice":-96.60000000000001,"GoodsUrl":"https://book.kongfz.com/498749/7330285594","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13768817/f620e30b590271c7_b.jpg","GoodsImgCount":"5","onSaleCount":4,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100007986","title":"外国地名译名手册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":10,"shippingFee":3,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/783956/8818059184","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddadbdae/0c467f31d5f788c4_b.jpg","GoodsImgCount":"1","onSaleCount":118,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807283690","title":"饭前好汤","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.49,"price":1.51,"shippingFee":2.98,"differencePrice":-4.49,"GoodsUrl":"https://book.kongfz.com/761854/8327314613","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbeddfff/771d2b0ef4627887_b.jpg","GoodsImgCount":"2","onSaleCount":50,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501946822","title":"发展心理学:心理学导读系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/619676/8100134597","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfebddff/67fab02ba70db394_b.jpg","GoodsImgCount":"10","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020152513","title":"哈利 波特与密室1 英 J K 罗琳著 马爱农 马爱新译 人民文学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.02,"price":2.02,"shippingFee":5,"differencePrice":-7.02,"GoodsUrl":"https://book.kongfz.com/180897/8899464885","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdaeaadb/03de942e85445e90_b.jpg","GoodsImgCount":"1","onSaleCount":192,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301138731","title":"经济发展与转型 思潮 战略与自生能力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.75,"price":1.75,"shippingFee":5,"differencePrice":-6.75,"GoodsUrl":"https://book.kongfz.com/263231/8460658424","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfcfefff/4a059682c31d1bf7_b.jpg","GoodsImgCount":"1","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122145031","title":"人生没有假如 一个 渐冻人 的悟与行 王甲著 化学工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/1146983/8773150111","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddecdabb/1a7c05d00ab28762_b.jpg","GoodsImgCount":"1","onSaleCount":200,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807657590","title":"楚留香新传4:新月传奇·午夜兰花","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":11,"shippingFee":8,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/623665/8695112105","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeaacdc/c5c542d15f9601b9_b.jpg","GoodsImgCount":"9","onSaleCount":81,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553443133","title":"星火英语·专4新题型标准阅读180篇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.86,"price":0.06,"shippingFee":3.8,"differencePrice":-3.86,"GoodsUrl":"https://book.kongfz.com/237705/8785081658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffdeffbe/1fadee5fe9aa9939_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020073948","title":"思无邪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.6,"price":0.6,"shippingFee":3,"differencePrice":-3.6,"GoodsUrl":"https://book.kongfz.com/903324/8684232524","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabbfacc/a28a9fc194d8bb7e_b.jpg","GoodsImgCount":"4","onSaleCount":552,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787554709719","title":"中国线描 钟馗迎祥纳福百图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":7,"shippingFee":5,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/735086/6940082430","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfdddfbc/d60edd964b638b70_b.jpg","GoodsImgCount":"5","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111527077","title":"质量总监成长记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":24.2,"shippingFee":3.8,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/237705/8642867339","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedfaddf/ef6b31285894943a_b.jpg","GoodsImgCount":"1","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521723311","title":"地球的故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":111.96,"price":102.96,"shippingFee":9,"differencePrice":-111.96,"GoodsUrl":"https://book.kongfz.com/518589/8629261141","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3457/02f88e006ed44dea44_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502850449","title":"十年三","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.21,"price":2.21,"shippingFee":5,"differencePrice":-7.21,"GoodsUrl":"https://book.kongfz.com/714758/7591149701","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/badfefcf/bfbebc21eedd5e0e_b.jpg","GoodsImgCount":"2","onSaleCount":221,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513256698","title":"中国孩子中医养:坐月子怎么吃(全彩)用适合中国人的方式让宝妈不落病奶水足,宝宝不生病长得壮!","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/462171/8660821950","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbebeecf/2f6e7e0bf01a00d5_b.jpg","GoodsImgCount":"2","onSaleCount":89,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542621641","title":"近代私法史下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":97,"price":93,"shippingFee":4,"differencePrice":-97,"GoodsUrl":"https://book.kongfz.com/330788/8423978555","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeffbcd/a893aaab265655e0_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542837875","title":"相对论的意义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/246207/8481578074","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfabecbe/a2e86389c5114683_b.jpg","GoodsImgCount":"6","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500421900","title":"佛陀和原始佛教思想","quality":0,"qualityText":"","originalPrice":0,"totalPrice":76.92,"price":71.42,"shippingFee":5.5,"differencePrice":-76.92,"GoodsUrl":"https://book.kongfz.com/250120/8708990278","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddddeaad/33b05c5af02f72b6_b.jpg","GoodsImgCount":"3","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532158263","title":"眼睛游戏 二手书实拍图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.719999999999999,"price":7.12,"shippingFee":5.6,"differencePrice":-12.719999999999999,"GoodsUrl":"https://book.kongfz.com/899541/8749220703","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecfdeda/8b6bf25d96064288_b.jpg","GoodsImgCount":"1","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111669531","title":"SiC/GaN功率半导体封装和可靠性评估技术","quality":0,"qualityText":"","originalPrice":0,"totalPrice":45.27,"price":38.27,"shippingFee":7,"differencePrice":-45.27,"GoodsUrl":"https://book.kongfz.com/162938/8886458225","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3374/02e33f6a36d6a2b377_b.jpg","GoodsImgCount":"1","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518033645","title":"为什么你说话别人不爱听张鸿9787518033645","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":0.5,"shippingFee":2.8,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/881983/7867281773","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaebadcb/3cd42d6ced8893f8_b.jpg","GoodsImgCount":"1","onSaleCount":550,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543981515","title":"从陪伴到放手:复旦五浦汇丛书-说李白黄玉峰","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":8,"shippingFee":5,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/15335/8689567387","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcbfadf/be78bc3cc126b571_b.jpg","GoodsImgCount":"4","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505740570","title":"七根凶简渔线人偶仙人指路 尾鱼 中国友谊出版公司","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.71,"price":10.71,"shippingFee":5,"differencePrice":-15.71,"GoodsUrl":"https://book.kongfz.com/903313/8601974525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaecddef/9c5814706496e1ad_b.jpg","GoodsImgCount":"1","onSaleCount":164,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111604518","title":"数据化运营:系统方法与实践案例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.61,"price":8.61,"shippingFee":0,"differencePrice":-8.61,"GoodsUrl":"https://book.kongfz.com/768603/8897179135","imgBigUrl":"https://www0.kfzimg.com/G06/M00/0A/A8/p4YBAFuMo-KAabDXAABizTiDPo4865_b.jpg","GoodsImgCount":"1","onSaleCount":136,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544733434","title":"战争临到美国:丘吉尔第二次世界大战回忆录06","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.83,"price":8.83,"shippingFee":2,"differencePrice":-10.83,"GoodsUrl":"https://book.kongfz.com/754405/8464078588","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AD/60/p4YBAFqfHMGAE36pAAEpfYi4KYI348_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802031623","title":"冯德全早教方案:三岁缔造一生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9,"price":0.9,"shippingFee":3,"differencePrice":-3.9,"GoodsUrl":"https://book.kongfz.com/832065/8677106895","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E4/42/p4YBAFqY74iAIP61AADPFXvXBAk285_b.jpg","GoodsImgCount":"1","onSaleCount":287,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787112243693","title":"自然与道德(古代永州地区城市规划设计研究)/人居环境科学丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":51.37,"price":49.37,"shippingFee":2,"differencePrice":-51.37,"GoodsUrl":"https://book.kongfz.com/476106/8289767243","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdfbdcfc/d5c28fc209e2480f_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504662774","title":"老科学家学术成长资料采集工程丛书国科学院院士传记丛书大音希声应崇福传 王传超著 国科学技术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.1,"price":6.1,"shippingFee":5,"differencePrice":-11.1,"GoodsUrl":"https://book.kongfz.com/911923/8642786730","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eedbfedb/0ee80689f3f1f141_b.jpg","GoodsImgCount":"1","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532763399","title":"第二性","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":39,"shippingFee":9,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/24286/8655519438","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdbbcff/11326043b66b78d8_b.jpg","GoodsImgCount":"8","onSaleCount":208,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221181442","title":"西游密档 死亡诅咒","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.190000000000001,"price":6.19,"shippingFee":3,"differencePrice":-9.190000000000001,"GoodsUrl":"https://book.kongfz.com/774181/8822974772","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/16365868/be960223de05f0da_b.jpg","GoodsImgCount":"1","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108056283","title":"窥视日本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.4,"price":14.4,"shippingFee":5,"differencePrice":-19.4,"GoodsUrl":"https://book.kongfz.com/640398/8325622171","imgBigUrl":"https://www0.kfzimg.com/G06/M00/61/9C/p4YBAFqctU6AC_foAAC3m52T-Pg635_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522510606","title":"别再说我恋爱脑 亲密关系 金钱与自我 孙能能 九州出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":2.9,"shippingFee":5,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/878060/8575274097","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeedfbcd/cf34c35618e4846a_b.jpg","GoodsImgCount":"1","onSaleCount":185,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010136479","title":"日本如何面对历史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.9,"price":4.9,"shippingFee":5,"differencePrice":-9.9,"GoodsUrl":"https://book.kongfz.com/398369/8886414153","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeabacd/414f2354130e7c2b_b.jpg","GoodsImgCount":"1","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537863407","title":"沈从文全集·补遗卷(历经十七年搜集、整理的遗落于《沈从文全集》之外的篇目)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":151.8,"price":151.8,"shippingFee":0,"differencePrice":-151.8,"GoodsUrl":"https://book.kongfz.com/506993/8197585884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddbdadc/863af2d42f64a712_b.jpg","GoodsImgCount":"4","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564365103","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512501010","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534069109","title":"画猫.雅宋:宋朝风情绘卷 16开 原价68元 ,画集以猫拟人,用千姿百态的猫咪演绎宋朝的绝代佳人、名士才子、休闲娱乐、生活习俗以及饮食文化等内容,收录五十张插画,分为【宋朝红颜谱】【宋朝才俊传】【宋朝闲乐篇】【宋朝百家事】【宋朝食事说】五大部分,展现出独特的宋朝风貌。","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":16,"shippingFee":0,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/22178/8842692481","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabfaccc/296ab20dabec1d3d_b.jpg","GoodsImgCount":"8","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787555102571","title":"你了解动物朋友吗/思考的魅力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.88,"price":0.08,"shippingFee":3.8,"differencePrice":-3.88,"GoodsUrl":"https://book.kongfz.com/237705/8818015350","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddbeada/454883a43146e865_b.jpg","GoodsImgCount":"1","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801273963","title":"心灵导师 情绪管理全书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.6,"price":0.6,"shippingFee":3,"differencePrice":-3.6,"GoodsUrl":"https://book.kongfz.com/791250/8376938616","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daafbaca/99cdf254dc0503cf_b.jpg","GoodsImgCount":"1","onSaleCount":328,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550285811","title":"很老很老的老偏方 :","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.06,"price":4.05,"shippingFee":0.01,"differencePrice":-4.06,"GoodsUrl":"https://book.kongfz.com/778027/8309893135","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eafeceea/577f1db4f57123fd_b.jpg","GoodsImgCount":"5","onSaleCount":622,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504468079","title":"煤矿 科学环境风水学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.8,"price":7.8,"shippingFee":5,"differencePrice":-12.8,"GoodsUrl":"https://book.kongfz.com/903313/8491513788","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23176617/284894c1eaa3b820_b.jpg","GoodsImgCount":"2","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787102080901","title":"中华砚文化汇典:砚谱卷:归云楼砚谱新编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":118.48,"price":114.08,"shippingFee":4.4,"differencePrice":-118.48,"GoodsUrl":"https://book.kongfz.com/27495/8065738536","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14256494/e9d0ec6a139e5a6d_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122387813","title":"变频器故障检修260例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":46.2,"price":40.2,"shippingFee":6,"differencePrice":-46.2,"GoodsUrl":"https://book.kongfz.com/1118298/8825504310","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/7445133/6b80c75aef1c1c8d_b.jpg","GoodsImgCount":"1","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530415702","title":"小学生作文大全 创新作文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.1,"price":0.1,"shippingFee":3,"differencePrice":-3.1,"GoodsUrl":"https://book.kongfz.com/371891/5644920378","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acedfbbf/2d736b34bda93f2c_b.jpg","GoodsImgCount":"3","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509141892","title":"30年临证实验录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55.92,"price":45.92,"shippingFee":10,"differencePrice":-55.92,"GoodsUrl":"https://book.kongfz.com/833207/7490953622","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22165297/2cd24e3e0d92cfc5_b.jpg","GoodsImgCount":"2","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201161693","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108009234","title":"大剖面:不可思议的剖面","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53,"price":45,"shippingFee":8,"differencePrice":-53,"GoodsUrl":"https://book.kongfz.com/310577/5906903518","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dedcfdcb/ee738917471fe03f_b.jpg","GoodsImgCount":"6","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515406466","title":"回忆萧华:纪念开国上将萧华诞辰100周年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":69,"price":60,"shippingFee":9,"differencePrice":-69,"GoodsUrl":"https://book.kongfz.com/634974/8146082829","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addeffcf/50b393dd54382db6_b.jpg","GoodsImgCount":"6","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505907294","title":"人类性爱史话","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.5,"price":1.5,"shippingFee":5,"differencePrice":-6.5,"GoodsUrl":"https://book.kongfz.com/890432/8719655764","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fddffafa/1b2b73ba2dc29f83_b.jpg","GoodsImgCount":"1","onSaleCount":177,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806155073","title":"金点子赚大钱赚钱点子 金 字系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/1207201/8801350603","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddccedcf/bc869c63b26b2662_b.jpg","GoodsImgCount":"1","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303119752","title":"20世纪西方文论新编 陈太胜 9787303119752 北京师范大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.53,"price":1.53,"shippingFee":3,"differencePrice":-4.53,"GoodsUrl":"https://book.kongfz.com/240018/8665248260","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C8/18/p4YBAFqotxaAffdjAADUpAcClLs234_b.jpg","GoodsImgCount":"1","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541126895","title":"三国演义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.29,"price":3.79,"shippingFee":2.5,"differencePrice":-6.29,"GoodsUrl":"https://book.kongfz.com/782278/8848213757","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afffccde/20b47fe8625e47a6_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500436867","title":"二手正版在下沉、下沉的世界里上升、上升9787500436867","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/765962/6746217821","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaeeefbd/ccebe6c255823c7a_b.jpg","GoodsImgCount":"1","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553313368","title":"不会说话,你就输了","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.9,"price":0.9,"shippingFee":2,"differencePrice":-2.9,"GoodsUrl":"https://book.kongfz.com/738826/8619357112","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adcaaddb/f1b58548dcfe64be_b.jpg","GoodsImgCount":"1","onSaleCount":1327,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787576007565","title":"从课本到奥数 7年级 第2学期 A版 第3版·视频讲解版 吴建平熊斌主编 华东师范大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.25,"price":14.75,"shippingFee":3.5,"differencePrice":-18.25,"GoodsUrl":"https://book.kongfz.com/610883/8510316729","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecfaafff/60aabde21e985ecd_b.jpg","GoodsImgCount":"5","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787557548193","title":"我叫丁 隐形的朋友 杨校艳 吉林美术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":4.8,"shippingFee":5,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/263231/8583717995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/befeffda/7748c91965d89732_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559620668","title":"你要如何衡量你的人生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.36,"price":9.36,"shippingFee":5,"differencePrice":-14.36,"GoodsUrl":"https://book.kongfz.com/750161/8749953015","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddafebab/9ee757288f1baef8_b.jpg","GoodsImgCount":"1","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532552726","title":"周易虞氏易象释易则","quality":0,"qualityText":"","originalPrice":0,"totalPrice":108,"price":90,"shippingFee":18,"differencePrice":-108,"GoodsUrl":"https://book.kongfz.com/476973/4795679344","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edafaabb/a4e9fc477f428e7d_b.jpg","GoodsImgCount":"5","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530220771","title":"绘本 三国志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37,"price":31,"shippingFee":6,"differencePrice":-37,"GoodsUrl":"https://book.kongfz.com/283241/8877731096","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbadebae/8da18a79e50e7791_b.jpg","GoodsImgCount":"9","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115449238","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535218292","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541151408","title":"昆仑.大结局","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":8,"shippingFee":7,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/624391/5408060815","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbfadbb/07c3be2711e5771a_b.jpg","GoodsImgCount":"12","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537728317","title":"梁秀清临床经验选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":108,"price":98,"shippingFee":10,"differencePrice":-108,"GoodsUrl":"https://book.kongfz.com/12117/8755654368","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eafaffdb/a731ef1a1cca7b58_b.jpg","GoodsImgCount":"2","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511536600","title":"人民日报记者说:典型人物采访与写作","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":7.2,"shippingFee":0,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/27736/8222096683","imgBigUrl":"https://www0.kfzimg.com/G06/M00/5F/DB/p4YBAFqlT3GAMPjmAACYZ6OExoQ676_b.jpg","GoodsImgCount":"1","onSaleCount":247,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801702715","title":"王树声传 王树声传 编写组编 当代中国出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33,"price":28,"shippingFee":5,"differencePrice":-33,"GoodsUrl":"https://book.kongfz.com/911923/8772814849","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeedcfa/bdd7e96d5ebd45fe_b.jpg","GoodsImgCount":"1","onSaleCount":90,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787219045039","title":"中国吴氏通书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":238,"price":228,"shippingFee":10,"differencePrice":-238,"GoodsUrl":"https://book.kongfz.com/388938/5635734530","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedacdfd/776fd9e3856a5399_b.jpg","GoodsImgCount":"4","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564061128","title":"聪明的女人不生气","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.48,"price":0.48,"shippingFee":3,"differencePrice":-3.48,"GoodsUrl":"https://book.kongfz.com/566350/8631713045","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcccbcda/e73ef67510e788b8_b.jpg","GoodsImgCount":"9","onSaleCount":175,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539272757","title":"货币哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.35,"price":32.35,"shippingFee":5,"differencePrice":-37.35,"GoodsUrl":"https://book.kongfz.com/403679/8309828791","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F8/D9/p4YBAFqZU3CAcNrGAACsHGgv654706_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532775903","title":"竞艳(永井荷风小说精选)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":18,"shippingFee":0,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/274136/6161792990","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdcbddc/2a54d839359d76b4_b.jpg","GoodsImgCount":"11","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117308953","title":"人卫版 考试达人 2021全国护师资格考试 随身记 2021新版 职称考试","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.57,"price":0.57,"shippingFee":4,"differencePrice":-4.57,"GoodsUrl":"https://book.kongfz.com/692632/8421322348","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcdfbba/af38ab15b897f2a2_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545206647","title":"狩魔手记 No. 3:在光与暗之间","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":6,"shippingFee":8,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/80269/8337622370","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3306/02d1a0dc6ad04aec0f_b.jpg","GoodsImgCount":"6","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513245272","title":"中草药的美丽传说 读故事知中医丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.31,"price":8.81,"shippingFee":4.5,"differencePrice":-13.31,"GoodsUrl":"https://book.kongfz.com/263924/8359098604","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accbccaa/71741a85ae819b1a_b.jpg","GoodsImgCount":"1","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787209091251","title":"明代朝鲜使臣胶东纪行诗探析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/27544/2973684514","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3630/0322c3fee2285943c6_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787204010592","title":"八仙醉行剑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":64.7,"price":54.7,"shippingFee":10,"differencePrice":-64.7,"GoodsUrl":"https://book.kongfz.com/832982/7421669386","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22231533/acc445679116fa70_b.jpg","GoodsImgCount":"2","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111611455","title":"体验式零售樊文花3000家连锁店的奥秘 刘琼雄著 机械工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":0.4,"shippingFee":5,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/910533/8534925404","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedfbefa/e9108bf55a3c5726_b.jpg","GoodsImgCount":"1","onSaleCount":165,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567529731","title":"美学是未来的教育学德育世界的探寻 檀传宝著 上海 华东师范大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":62,"price":57,"shippingFee":5,"differencePrice":-62,"GoodsUrl":"https://book.kongfz.com/910533/8594193674","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdfeffa/d771f7f1133412b9_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559840653","title":"法哲学沉思录(增订注释版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42.88,"price":32.88,"shippingFee":10,"differencePrice":-42.88,"GoodsUrl":"https://book.kongfz.com/795574/8482826703","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2498932/25a228594e7c8698_b.jpg","GoodsImgCount":"1","onSaleCount":86,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501209880","title":"信主独一 伊斯兰教","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.740000000000002,"price":14.74,"shippingFee":5,"differencePrice":-19.740000000000002,"GoodsUrl":"https://book.kongfz.com/802508/8561749878","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feedacfa/144d6e447f607a6f_b.jpg","GoodsImgCount":"1","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020064304","title":"刘白羽散文:插图珍藏版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/16713/7428025070","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1825943/089638a0dcdcc20c_b.jpg","GoodsImgCount":"3","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536030497","title":"非神化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.97,"price":13.97,"shippingFee":4,"differencePrice":-17.97,"GoodsUrl":"https://book.kongfz.com/797722/8362753281","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cadeaadd/b275ab6824ca0dc7_b.jpg","GoodsImgCount":"4","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562488002","title":"工程造价确定与控制 第7版吴学伟 谭德精 郑文建 主编重庆大学出版社9787562488002","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.7,"price":3.7,"shippingFee":0,"differencePrice":-3.7,"GoodsUrl":"https://book.kongfz.com/366030/8613584644","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/7028af8b53465ac6_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540783884","title":"溺水者","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.5,"price":8,"shippingFee":2.5,"differencePrice":-10.5,"GoodsUrl":"https://book.kongfz.com/361618/7588004292","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfcbcdb/d4f4881569709583_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040458749","title":"2017年 全国硕士研究生招生考试法律硕士","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":1,"shippingFee":3,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/684559/8441884801","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bacbeaac/97523a1d94c76d53_b.jpg","GoodsImgCount":"2","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214049544","title":"中华帝国的法律","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":16,"shippingFee":6,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/61222/8696597261","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceccaadf/3fa7aa8a06b334c7_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562440673","title":"会展项目策划与组织9787562440673","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":5.4,"shippingFee":0,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/797928/7133987476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21491677/092f9249b4885775_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807348566","title":"水利水电工程专业案例应试辅导与习题集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36.97,"price":33.17,"shippingFee":3.8,"differencePrice":-36.97,"GoodsUrl":"https://book.kongfz.com/717628/8773851320","imgBigUrl":"https://www0.kfzimg.com/G06/M00/91/5F/p4YBAFrJoHGALyMyAABxymwcVA4723_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560017181","title":"汉英口译入门","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.98,"price":5.48,"shippingFee":2.5,"differencePrice":-7.98,"GoodsUrl":"https://book.kongfz.com/749193/8497283264","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbbfadec/40d5813e2d448723_b.jpg","GoodsImgCount":"2","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508690469","title":"切尔诺贝利的祭祷 斯韦特兰娜 亚历山德罗夫娜 阿列克谢耶维著 孙 中信出版集团 中信出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.6,"price":5.6,"shippingFee":5,"differencePrice":-10.6,"GoodsUrl":"https://book.kongfz.com/398369/8732751738","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecaebbb/61df20b5adc43022_b.jpg","GoodsImgCount":"1","onSaleCount":343,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538465365","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122177568","title":"3天完成超人气简单钩针编织披肩 围巾 毛衣","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.73,"price":22.73,"shippingFee":5,"differencePrice":-27.73,"GoodsUrl":"https://book.kongfz.com/798596/8841462997","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecedfec/0acd92a7b4e82865_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802515062","title":"30天精通哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.65,"price":3.65,"shippingFee":4,"differencePrice":-7.65,"GoodsUrl":"https://book.kongfz.com/841736/7819318114","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbadeae/97389454709a0395_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531339038","title":"小阿卡那王国的十二天 塔罗牌的冒险游戏 3 李榕 春风文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41,"price":36,"shippingFee":5,"differencePrice":-41,"GoodsUrl":"https://book.kongfz.com/398369/8525948579","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdbdaaef/502feffcdc5a83f2_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802545137","title":"宗教团体教规制度汇编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.3,"price":3.5,"shippingFee":3.8,"differencePrice":-7.3,"GoodsUrl":"https://book.kongfz.com/570268/4507336198","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aebfbafd/f0e5c62ff57592db_b.jpg","GoodsImgCount":"3","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559830425","title":"致一百年以后的你:茨维塔耶娃诗选(布罗茨基和帕斯捷尔纳克推崇备至,虚伪年代里她发出了天上真理的声音)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.6,"price":37.6,"shippingFee":0,"differencePrice":-37.6,"GoodsUrl":"https://book.kongfz.com/464998/5836803688","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadefded/38fcb773d15f75f9_b.jpg","GoodsImgCount":"3","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513276764","title":"正版中医经典能力等级考试学习备要 一二级 大学教材 对一二级全部条文中的关键知识点进行规范解读 经典条文全解中国中医药出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":72,"price":64,"shippingFee":8,"differencePrice":-72,"GoodsUrl":"https://book.kongfz.com/667710/8264576689","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/17848986/06d71c99a14262d1_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020070985","title":"名著名译插图本:格林童话全集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.92,"price":4.92,"shippingFee":5,"differencePrice":-9.92,"GoodsUrl":"https://book.kongfz.com/481057/8714237544","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdeddecc/130f2902b9a8a4c3_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569901856","title":"论重要之事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":22,"shippingFee":8,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/665570/8689983587","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daaddebc/4d6909ac7a702e44_b.jpg","GoodsImgCount":"4","onSaleCount":56,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533073640","title":"中国石刻书法精粹冈山入楞伽经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":47.8,"price":42,"shippingFee":5.8,"differencePrice":-47.8,"GoodsUrl":"https://book.kongfz.com/1120159/8821041704","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdeccece/327c94577b5df77b_b.jpg","GoodsImgCount":"3","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562418863","title":"电脑中文五笔字型编码字典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6,"price":6,"shippingFee":0,"differencePrice":-6,"GoodsUrl":"https://book.kongfz.com/731554/6197072537","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdadbcae/8248e5748581be30_b.jpg","GoodsImgCount":"4","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530483565","title":"法式烘焙圣经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":18,"shippingFee":4,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/716704/8005098362","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E0/B8/p4YBAFqY5ImAP-xTAAD-aKAGaq0152_b.jpg","GoodsImgCount":"0","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111485681","title":"放空一下,大脑更有活力:发呆或深度睡眠的时间,正是大脑整理信息、巩固记忆的宝贵时刻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.58,"price":39.98,"shippingFee":1.6,"differencePrice":-41.58,"GoodsUrl":"https://book.kongfz.com/457799/8898556222","imgBigUrl":"https://www0.kfzimg.com/G06/M00/61/B6/p4YBAFqctaaAZShRAAB7qAPX2I4591_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511702463","title":"一个冬夜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.99,"price":1.01,"shippingFee":2.98,"differencePrice":-3.99,"GoodsUrl":"https://book.kongfz.com/761854/8282360559","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbefaaaa/bdd6bbbf29672624_b.jpg","GoodsImgCount":"2","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801305312","title":"图解住宅禁忌","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":4,"shippingFee":10,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/289461/8750166897","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbfeada/ff4d3e78ae4f33e4_b.jpg","GoodsImgCount":"4","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559052407","title":"儿童权利宣言","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/302893/3001668407","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/390/4cdb424a175a6bc1_b.jpg","GoodsImgCount":"1","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539967486","title":"波吉亚家族","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42,"price":34,"shippingFee":8,"differencePrice":-42,"GoodsUrl":"https://book.kongfz.com/316589/8786458274","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecefce/858ca722b85e3531_b.jpg","GoodsImgCount":"11","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115227409","title":"FPGA应用开发入门与典型实例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.9,"price":24.9,"shippingFee":0,"differencePrice":-24.9,"GoodsUrl":"https://book.kongfz.com/792228/8893341825","imgBigUrl":"https://www0.kfzimg.com/G06/M00/66/FF/p4YBAFql1cSAbYjSAABg-cl_KK8164_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559461674","title":"毛姆短篇小说全集江苏凤凰文艺出版社册第三册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.9,"price":13.9,"shippingFee":2,"differencePrice":-15.9,"GoodsUrl":"https://book.kongfz.com/769034/8877458642","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecaaea/595a1d153417c057_b.jpg","GoodsImgCount":"4","onSaleCount":147,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787563801084","title":"如何正确购买股票","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.39,"price":0.39,"shippingFee":6,"differencePrice":-6.39,"GoodsUrl":"https://book.kongfz.com/732025/7658617884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aafdfdfa/3a4f774764fbc683_b.jpg","GoodsImgCount":"14","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500303176","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560036908","title":"蓝宝伴侣:GRE词汇逆序突破肖静波 杨媚","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":10,"shippingFee":0,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/576646/8181293652","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeeefbdd/fc709d318be41ab9_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506313803","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544717991","title":"译林名著精选:童年《图片实拍》","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.49,"price":1.49,"shippingFee":2,"differencePrice":-3.49,"GoodsUrl":"https://book.kongfz.com/892872/8841398697","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eacfdfcc/665f0977eb140373_b.jpg","GoodsImgCount":"5","onSaleCount":344,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787811002201","title":"羽毛球教学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":75.72,"price":63.72,"shippingFee":12,"differencePrice":-75.72,"GoodsUrl":"https://book.kongfz.com/876767/7810979890","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22552668/642a62ea85b3b7ad_b.jpg","GoodsImgCount":"2","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533290221","title":"阳光姐姐小书房-补习班的毕业狗","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.59,"price":0.59,"shippingFee":3,"differencePrice":-3.59,"GoodsUrl":"https://book.kongfz.com/891713/7982111525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdcebace/2f1de291a31baeb2_b.jpg","GoodsImgCount":"4","onSaleCount":212,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553332925","title":"看晚风吹动香椿树","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":7,"shippingFee":7,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/906778/8175138950","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/17787432/b4ed61571e964018_b.jpg","GoodsImgCount":"4","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535715807","title":"时间之箭:揭开时间最大奥秘之科旅程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":3.8,"shippingFee":0,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/437976/8789758974","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdbbedba/b68db3d7454fdc01_b.jpg","GoodsImgCount":"4","onSaleCount":639,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518426096","title":"非瘦不可","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/191396/8547026612","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbadccb/53f868482c984b7e_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229011338","title":"夫妻按摩保健图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":10,"shippingFee":5,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/3092/8222548065","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dffedfea/afe59603b8ebe5ee_b.jpg","GoodsImgCount":"6","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113276508","title":"股市稳定盈利——寻找最小阻力位9787113276508毕文锋中国铁道出","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36.8,"price":34.3,"shippingFee":2.5,"differencePrice":-36.8,"GoodsUrl":"https://book.kongfz.com/1092759/8885035777","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebacebce/399a4692deda6697_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521719208","title":"通往衰败之路经济学如何掌控我们的生活","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/825106/7894333431","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcffaffb/546c29ed56f49d38_b.jpg","GoodsImgCount":"6","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122339980","title":"抗癌秘验方(第3版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.38,"price":8.38,"shippingFee":3,"differencePrice":-11.38,"GoodsUrl":"https://book.kongfz.com/902124/8346316359","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdbacbe/405f74ef1d91f332_b.jpg","GoodsImgCount":"8","onSaleCount":146,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300112275","title":"普通公司法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":160,"price":150,"shippingFee":10,"differencePrice":-160,"GoodsUrl":"https://book.kongfz.com/593645/8588413426","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deacbcff/f813861f1b55e16a_b.jpg","GoodsImgCount":"30","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787551101455","title":"幼儿衔接训练营数学 10以内数的加减法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.36,"price":0.36,"shippingFee":5,"differencePrice":-5.36,"GoodsUrl":"https://book.kongfz.com/805022/8818083745","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/effcbfda/26f92cfd9c8dd9a7_b.jpg","GoodsImgCount":"1","onSaleCount":150,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501965281","title":"透视课堂","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38.879999999999995,"price":28.88,"shippingFee":10,"differencePrice":-38.879999999999995,"GoodsUrl":"https://book.kongfz.com/795093/8817748428","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edbddced/3cc78a67adce3057_b.jpg","GoodsImgCount":"14","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522615448","title":"系统架构设计师考试32小时通关","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.18,"price":16.18,"shippingFee":5,"differencePrice":-21.18,"GoodsUrl":"https://book.kongfz.com/893135/8183887786","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdedeed/82c6861b1cb9f559_b.jpg","GoodsImgCount":"1","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535446732","title":"跟谁较劲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.24,"price":2.74,"shippingFee":1.5,"differencePrice":-4.24,"GoodsUrl":"https://book.kongfz.com/774690/8186965131","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D8/C3/p4YBAFqYxLeAD1cDAAC30cOaVPw558_b.jpg","GoodsImgCount":"1","onSaleCount":338,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224085945","title":"白纪年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":14,"shippingFee":8,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/608824/8429279676","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfbdebf/bee101b98e926b96_b.jpg","GoodsImgCount":"10","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521754247","title":"价值投费3.0","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/813529/7760121091","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9937843/6f65ca503c24bca1_b.jpg","GoodsImgCount":"1","onSaleCount":137,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115602602","title":"AI医学图像处理杨慧芳人民邮电出版社9787115602602","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.76,"price":29.76,"shippingFee":0,"differencePrice":-29.76,"GoodsUrl":"https://book.kongfz.com/248516/8801231646","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/000b6943df4e0b96_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534785375","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801716088","title":"中国现代小说经典文库:刘云若","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.01,"price":0.01,"shippingFee":3,"differencePrice":-3.01,"GoodsUrl":"https://book.kongfz.com/581989/6091380883","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddeadba/bad6dfa20af585fa_b.jpg","GoodsImgCount":"5","onSaleCount":727,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111673835","title":"汽车底盘振动与噪声控制","quality":0,"qualityText":"","originalPrice":0,"totalPrice":108,"price":96,"shippingFee":12,"differencePrice":-108,"GoodsUrl":"https://book.kongfz.com/594145/6738070561","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beffefff/1b999c09e1bbfc57_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020037155","title":"欧·亨利短篇小说选。","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.89,"price":0.09,"shippingFee":4.8,"differencePrice":-4.89,"GoodsUrl":"https://book.kongfz.com/780405/7571655710","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeebeccd/81c7e5db13f25a44_b.jpg","GoodsImgCount":"4","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561554272","title":"闽南话教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":6,"shippingFee":5,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/365590/6700057055","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbeedbc/ee350c61e535d96a_b.jpg","GoodsImgCount":"4","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559725943","title":"汤汤奇幻童年故事本 注音版:美人树","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.64,"price":10.14,"shippingFee":6.5,"differencePrice":-16.64,"GoodsUrl":"https://book.kongfz.com/758962/8723946119","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afadbfae/be23dd9f6ed74436_b.jpg","GoodsImgCount":"5","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509116418","title":"拔罐疗法治百病(第3版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":6,"shippingFee":8,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/667587/5549578255","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daccdbde/eec7103f90685857_b.jpg","GoodsImgCount":"5","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801797674","title":"周易正义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.9,"price":8.9,"shippingFee":5,"differencePrice":-13.9,"GoodsUrl":"https://book.kongfz.com/261116/8497958314","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcfebef/ed2a4baa1dece5f9_b.jpg","GoodsImgCount":"1","onSaleCount":158,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787555021933","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500423379","title":"米诺托之恋 32开","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":2,"shippingFee":8,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/2731/8305886847","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbecedaf/fd432f72526a0677_b.jpg","GoodsImgCount":"3","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506546294","title":"兵书与商战:《孙子兵法》在企业经营管理中的应用","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.11,"price":11.11,"shippingFee":3,"differencePrice":-14.11,"GoodsUrl":"https://book.kongfz.com/11070/5792723770","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfcafefb/4267f82702444e97_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802568228","title":"正版 {塑封}凤舞未央:吕雉传.壹[社版] 大爱无痕 9787802568228","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.439999999999998,"price":11.94,"shippingFee":4.5,"differencePrice":-16.439999999999998,"GoodsUrl":"https://book.kongfz.com/8094/8801323849","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceeeeafe/219b26a6d6d8fcd7_b.jpg","GoodsImgCount":"10","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521424812","title":"《药性歌括四百味》详解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/260959/8653606389","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efddfbea/26a0c67edea8a345_b.jpg","GoodsImgCount":"3","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200026429","title":"佛学精华 下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53.9,"price":45,"shippingFee":8.9,"differencePrice":-53.9,"GoodsUrl":"https://book.kongfz.com/303525/7008507926","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddbacda/577a88c16787e620_b.jpg","GoodsImgCount":"15","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559665218","title":"深话浅说,把话说到点子上的超级沟通术!","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.3,"price":15.5,"shippingFee":2.8,"differencePrice":-18.3,"GoodsUrl":"https://book.kongfz.com/41819/8874019077","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1578691/618e7aa77d18b321_b.jpg","GoodsImgCount":"4","onSaleCount":120,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787551144636","title":"这不是一本科学书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.78,"price":1.78,"shippingFee":5,"differencePrice":-6.78,"GoodsUrl":"https://book.kongfz.com/202798/8898900360","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbabbbe/11e45c6436a68d08_b.jpg","GoodsImgCount":"1","onSaleCount":97,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201131634","title":"精简 日式精要主义生活法则","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":3.1,"shippingFee":5,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/1207201/8801526319","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfcdbfe/9c2b3e7d1e41114a_b.jpg","GoodsImgCount":"1","onSaleCount":94,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201198910","title":"【未翻阅】吕著中国通史:中国政治史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":6,"shippingFee":4,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/578827/8429230684","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecbfcf/e01cd053daf6e07a_b.jpg","GoodsImgCount":"2","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539617473","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108032577","title":"仙骨佛心:家具、紫砂与明清文人","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.4,"price":4.4,"shippingFee":10,"differencePrice":-14.4,"GoodsUrl":"https://book.kongfz.com/683738/7098697332","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeceefcb/027ba9058aa5f099_b.jpg","GoodsImgCount":"4","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530948460","title":"西风独自凉","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.99,"price":0.99,"shippingFee":3,"differencePrice":-3.99,"GoodsUrl":"https://book.kongfz.com/903324/8732698209","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdecacaa/5829bc5de36da17a_b.jpg","GoodsImgCount":"5","onSaleCount":256,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308133326","title":"一本书读懂财报 肖星著 浙江大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.73,"price":7.73,"shippingFee":5,"differencePrice":-12.73,"GoodsUrl":"https://book.kongfz.com/180897/8899723904","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faebfade/22273c2907c42499_b.jpg","GoodsImgCount":"1","onSaleCount":193,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565422034","title":"传媒经济","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":22,"shippingFee":7,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/793471/8403961276","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedabeae/107e1049b5db2e80_b.jpg","GoodsImgCount":"4","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509664728","title":"大学二级学院院长的角色认知与管理之道","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40.21,"price":36.21,"shippingFee":4,"differencePrice":-40.21,"GoodsUrl":"https://book.kongfz.com/502990/8262079169","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aacadfdd/74291c5b7c3535d5_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518059195","title":"提高抗挫力培养内心强大的孩子","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":2,"shippingFee":8,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/642191/8020261360","imgBigUrl":"https://www0.kfzimg.com/G07/M00/F3/41/qoYBAFx_IDKAZ76lAAI2qNaQMek283_b.jpg","GoodsImgCount":"1","onSaleCount":56,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305198632","title":"陶艺设计 陈卢鹏 南京大学出版社 9787305198632","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.98,"price":3.98,"shippingFee":0,"differencePrice":-3.98,"GoodsUrl":"https://book.kongfz.com/2845/8726272938","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcacebde/e3d61e23ccebbfc2_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564800994","title":"学校艺术教育60年(1949-2009)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":23,"shippingFee":0,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/544739/4134318917","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbebddbc/11ba1c8ac23ca92d_b.jpg","GoodsImgCount":"9","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561457207","title":"隐形的尾巴系列:梦中的巨叶 彩图版中英对照","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":25,"shippingFee":0,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/545819/8248024889","imgBigUrl":"https://www0.kfzimg.com/G06/M00/CF/70/p4YBAFqo5jaAXl6NAABP0PiNKsA890_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520202091","title":"儿童职业启蒙百科长大后我要做什么 陈昕编著 中国大百科全书出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.82,"price":9.82,"shippingFee":5,"differencePrice":-14.82,"GoodsUrl":"https://book.kongfz.com/398369/8780865875","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deaebdef/cf5e69203d43afc8_b.jpg","GoodsImgCount":"1","onSaleCount":188,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534951978","title":"烘焙新手必备的第一本书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5600000000000005,"price":0.56,"shippingFee":4,"differencePrice":-4.5600000000000005,"GoodsUrl":"https://book.kongfz.com/660948/8726976124","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebcbcfbd/d44f0b660d82a285_b.jpg","GoodsImgCount":"2","onSaleCount":304,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500410898","title":"社科学术文库:中国革命法制史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.07,"price":13.07,"shippingFee":6,"differencePrice":-19.07,"GoodsUrl":"https://book.kongfz.com/792848/8126466099","imgBigUrl":"https://www0.kfzimg.com/G06/M00/87/CE/p4YBAFrJd_eAVtUOAACH4Dc3UTs299_b.jpg","GoodsImgCount":"1","onSaleCount":74,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214222213","title":"西顿动物故事集/统编语文教材必读名著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.43,"price":2.43,"shippingFee":3,"differencePrice":-5.43,"GoodsUrl":"https://book.kongfz.com/774181/8781126790","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabdeeeb/4c70980aa56a6179_b.jpg","GoodsImgCount":"4","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108028167","title":"西班牙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.1,"price":7.1,"shippingFee":5,"differencePrice":-12.1,"GoodsUrl":"https://book.kongfz.com/802508/8630726160","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dafcfebf/38916c84832bb9e5_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516764589","title":"整理收纳师培训实用教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42.68,"price":34.68,"shippingFee":8,"differencePrice":-42.68,"GoodsUrl":"https://book.kongfz.com/158878/8133003913","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4893319/0fc6cd33a6998f78_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535460783","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515509433","title":"实体店这样做绝不输电商:实体店+互联网,这样运营更有效","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.21,"price":4.2,"shippingFee":0.01,"differencePrice":-4.21,"GoodsUrl":"https://book.kongfz.com/171447/8557690684","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efafdcda/e5451ef584b5dac0_b.jpg","GoodsImgCount":"1","onSaleCount":200,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508644660","title":"数据之巅:大数据革命,历史、现实与未来","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":0.8,"shippingFee":3,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/880498/8863679996","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F0/78/p4YBAFqZNLWAH1kmAAGLQlVha0I822_b.jpg","GoodsImgCount":"1","onSaleCount":1923,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108035455","title":"游观美国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":4.2,"shippingFee":3,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/566350/8848525346","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcfdeeae/d8e0990506ae25ee_b.jpg","GoodsImgCount":"5","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515517018","title":"达·芬奇笔记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.9,"price":25,"shippingFee":3.9,"differencePrice":-28.9,"GoodsUrl":"https://book.kongfz.com/293289/8863618280","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdaabce/99e10484c9bb4d68_b.jpg","GoodsImgCount":"1","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538290554","title":"高中必备古诗文 第4次修订","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.54,"price":0.54,"shippingFee":3,"differencePrice":-3.54,"GoodsUrl":"https://book.kongfz.com/371891/8511078129","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbadebaa/e65202c29d831318_b.jpg","GoodsImgCount":"3","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208141384","title":"告别霸权 全球体系中的权力与影响力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.73,"price":10.73,"shippingFee":5,"differencePrice":-15.73,"GoodsUrl":"https://book.kongfz.com/907853/8590170185","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adbbedeb/74860687d74261cc_b.jpg","GoodsImgCount":"1","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030520784","title":"内页干净 数字电子技术基础 第二版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/186710/8891553985","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceacecbf/5dc142c596b99bb7_b.jpg","GoodsImgCount":"5","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550017719","title":"答案之书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.32,"price":1.32,"shippingFee":3,"differencePrice":-4.32,"GoodsUrl":"https://book.kongfz.com/566350/8837190195","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aadedfee/a9c15bdf17802e77_b.jpg","GoodsImgCount":"5","onSaleCount":586,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544282437","title":"点与线【正版书籍,实拍图发货,16点前订单当天发出-1112】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":2,"shippingFee":10,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/1208551/8761113973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceefdffa/fee05513763e9ffb_b.jpg","GoodsImgCount":"4","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550106383","title":"卖故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.38,"price":4.37,"shippingFee":0.01,"differencePrice":-4.38,"GoodsUrl":"https://book.kongfz.com/877749/8772134551","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/56f2b8bf0930afe3_b.jpg","GoodsImgCount":"3","onSaleCount":242,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508652801","title":"救命饮食Ⅱ:反思营养学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":13,"shippingFee":6,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/302512/8854227529","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daefedee/aa1240d7fc51d6dc_b.jpg","GoodsImgCount":"9","onSaleCount":105,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530838846","title":"长效针灸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":92.62,"price":81.12,"shippingFee":11.5,"differencePrice":-92.62,"GoodsUrl":"https://book.kongfz.com/1121862/8620201407","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23602004/bc1be7f1013d5f16_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547400289","title":"恐龙宝贝 18失踪的公主.","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/240738/6964968829","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/49/01c16a6e44d6eefc_b.jpg","GoodsImgCount":"5","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504936004","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787566422859","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802255913","title":"第十二张牌 林肯 莱姆系列之六","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":2.9,"shippingFee":5,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/261116/8727732660","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbffccc/dfc8550b211d9e53_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111331834","title":"(二手书)离散数学 冯伟森栾新成石兵 机械工业出版社 2011年03月01日 9787111331834","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.4,"price":9.4,"shippingFee":4,"differencePrice":-13.4,"GoodsUrl":"https://book.kongfz.com/704408/6180539887","imgBigUrl":"https://www0.kfzimg.com/G06/M00/91/AE/p4YBAFqeLhKAW5d5AADl92ZwcOg893_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300096728","title":"民法典体系研究 王利明著 16开 中国人民大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.610000000000001,"price":8.21,"shippingFee":2.4,"differencePrice":-10.610000000000001,"GoodsUrl":"https://book.kongfz.com/691158/8420929169","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbdcbac/d39298c4ffe420f0_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534487484","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514857719","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787517057314","title":"中文版AutoCAD 2018从入门到精通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.04,"price":3.04,"shippingFee":2,"differencePrice":-5.04,"GoodsUrl":"https://book.kongfz.com/624177/8858791962","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeabffeb/61322e6d9183c96c_b.jpg","GoodsImgCount":"2","onSaleCount":174,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559662897","title":"你可以链接任何人","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/718390/8279878590","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cebadccd/f3d70455d1372df0_b.jpg","GoodsImgCount":"9","onSaleCount":214,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539861753","title":"经典碑帖笔法临析大全:汉 张迁碑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":25,"shippingFee":5,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/626307/8191067601","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceecbcfd/5a4122d8aacde8e1_b.jpg","GoodsImgCount":"3","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214022448","title":"走出蒙昧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.09,"price":2.09,"shippingFee":3,"differencePrice":-5.09,"GoodsUrl":"https://book.kongfz.com/880498/8552588955","imgBigUrl":"https://www0.kfzimg.com/G06/M00/4C/C2/p4YBAFqbzkiANU8yAABXKCNtm0I243_b.jpg","GoodsImgCount":"1","onSaleCount":100,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801820716","title":"034-最高人民法院关于审理未成年人刑事案件的若干规定——司法解释配套规定(30)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/773547/8882061995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abcbedbe/3f86089883b36df9_b.jpg","GoodsImgCount":"3","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565603785","title":"高中地理知识清单第七次修订","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9099999999999997,"price":0.11,"shippingFee":3.8,"differencePrice":-3.9099999999999997,"GoodsUrl":"https://book.kongfz.com/237705/8296401548","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/becedeca/85f3d8d0cf0507fc_b.jpg","GoodsImgCount":"1","onSaleCount":312,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300227931","title":"摇滚狂人:奥兹·奥斯本自传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":357.93,"price":347.93,"shippingFee":10,"differencePrice":-357.93,"GoodsUrl":"https://book.kongfz.com/885269/8721211625","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C6/CD/p4YBAFqYPm6AA58NAADmk-bczug630_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040165333","title":"服装缝制工艺","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.030000000000001,"price":4.03,"shippingFee":5,"differencePrice":-9.030000000000001,"GoodsUrl":"https://book.kongfz.com/234408/8617852599","imgBigUrl":"https://www0.kfzimg.com/G06/M00/49/E5/p4YBAFqklnyAOs0PAADPm0kfy34750_b.jpg","GoodsImgCount":"1","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805260341","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540756369","title":"我的教育思考:李镇西30年教育感悟精华","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/244916/7101323168","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbddcdee/0b130d050743b880_b.jpg","GoodsImgCount":"3","onSaleCount":85,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506318037","title":"庞中华书法百日通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.8,"price":1.8,"shippingFee":5,"differencePrice":-6.8,"GoodsUrl":"https://book.kongfz.com/1207201/8872215438","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acadcfea/50504c6043d60888_b.jpg","GoodsImgCount":"1","onSaleCount":118,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534865725","title":"【正版库存书,无写划,当天发货】候气术-古人观念中天地人之纽带","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":39,"shippingFee":10,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/792783/8292451687","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdffeffa/1d238d1e8b570fc8_b.jpg","GoodsImgCount":"2","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309141238","title":"媒介考古学:方法、路径和意涵","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.3,"price":37.8,"shippingFee":1.5,"differencePrice":-39.3,"GoodsUrl":"https://book.kongfz.com/772556/8643035154","imgBigUrl":"https://www0.kfzimg.com/G07/M00/74/9F/q4YBAFy9za6APejXAACbgxAfVOA618_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807492078","title":"中国油灯","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":19,"shippingFee":5,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/3092/8404148550","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abdafddd/ae84e3b815c551f1_b.jpg","GoodsImgCount":"5","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535558121","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100047944","title":"现代汉语词典 大字本【第5版】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":46.2,"price":43.2,"shippingFee":3,"differencePrice":-46.2,"GoodsUrl":"https://book.kongfz.com/567465/8684141730","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afeacdfc/27dbc7df6e4790d0_b.jpg","GoodsImgCount":"11","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214061652","title":"[正版现货实拍]左与右","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":25,"shippingFee":5,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/593972/8831688302","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabcbffc/6acb11c332afb1ac_b.jpg","GoodsImgCount":"2","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565645136","title":"理想树2019新版 高考必刷题 化学合订本 67高考总复?习辅导用书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.23,"price":0.23,"shippingFee":4,"differencePrice":-4.23,"GoodsUrl":"https://book.kongfz.com/841736/7806737988","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eacfdcfc/d53e57da439477b1_b.jpg","GoodsImgCount":"1","onSaleCount":170,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301327678","title":"手机摄影从入门到精通(视频教程版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.96,"price":4.96,"shippingFee":3,"differencePrice":-7.96,"GoodsUrl":"https://book.kongfz.com/814259/7155878213","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11956018/23ecdf560f51fc15_b.jpg","GoodsImgCount":"0","onSaleCount":151,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501242757","title":"稳行高处","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.29,"price":11.29,"shippingFee":5,"differencePrice":-16.29,"GoodsUrl":"https://book.kongfz.com/202798/8790783794","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdeeabf/f0e02fb82665f1a7_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516147948","title":"雷州文化概论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.85,"price":5.35,"shippingFee":5.5,"differencePrice":-10.85,"GoodsUrl":"https://book.kongfz.com/673095/8836493176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eadccdee/b6cdf1498eaa5a5d_b.jpg","GoodsImgCount":"1","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787307196872","title":"西线空战:二战德国空军第26战斗机联队战史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34,"price":28,"shippingFee":6,"differencePrice":-34,"GoodsUrl":"https://book.kongfz.com/255987/6951927055","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcffded/00890ff233c0e961_b.jpg","GoodsImgCount":"8","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535729309","title":"中国湘菜湘点.地方菜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":6,"shippingFee":10,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/794521/8854071538","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbfdcdd/ce5af34277bfbf6d_b.jpg","GoodsImgCount":"15","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787103027660","title":"音乐学:历史、文献与写作","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.97,"price":17.97,"shippingFee":2,"differencePrice":-19.97,"GoodsUrl":"https://book.kongfz.com/877749/8009479476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccadfcdd/59e0599bef87bcc2_b.jpg","GoodsImgCount":"2","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537402484","title":"枭雄百传第三部12世界政坛枭雄之一","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":1.5,"shippingFee":3,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/500139/6001151895","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffddfbcc/623f0323273297b1_b.jpg","GoodsImgCount":"4","onSaleCount":217,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514803723","title":"幼儿文学百年经典:科学 和风卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.1,"price":6.6,"shippingFee":2.5,"differencePrice":-9.1,"GoodsUrl":"https://book.kongfz.com/836247/7706451696","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcfebeb/2055a85b2f62f6cc_b.jpg","GoodsImgCount":"2","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505135482","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010223445","title":"共产党执政规律研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.09,"price":0.09,"shippingFee":5,"differencePrice":-5.09,"GoodsUrl":"https://book.kongfz.com/23607/8529134364","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddcececa/931db1e7f06bbbb1_b.jpg","GoodsImgCount":"1","onSaleCount":324,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506085892","title":"指月录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":24,"shippingFee":6,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/715232/8775324286","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efffcbfb/ac5bb42fd1eb8cfd_b.jpg","GoodsImgCount":"8","onSaleCount":174,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535457646","title":"蒙曼说隋(下):隋炀帝杨广","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.4,"price":11.5,"shippingFee":2.9,"differencePrice":-14.4,"GoodsUrl":"https://book.kongfz.com/566350/8780637754","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfaffafa/7c735695c0ad2658_b.jpg","GoodsImgCount":"8","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508617930","title":"一分钟百万富翁","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.5,"price":5,"shippingFee":5.5,"differencePrice":-10.5,"GoodsUrl":"https://book.kongfz.com/78763/8656091664","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdeffaeb/f97188c16b7bdf05_b.jpg","GoodsImgCount":"4","onSaleCount":100,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301317273","title":"中华茶文化概论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.58,"price":9.58,"shippingFee":0,"differencePrice":-9.58,"GoodsUrl":"https://book.kongfz.com/22758/8269768638","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3159/02b0e79a478be0806a_b.jpg","GoodsImgCount":"1","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802011540","title":"书法碑帖 墨迹精印 隋 智永真草千字文 姚建杭 中国和平出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.9,"price":5.9,"shippingFee":5,"differencePrice":-10.9,"GoodsUrl":"https://book.kongfz.com/910533/8841066585","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decdeecf/5b9eb240e4cf2f07_b.jpg","GoodsImgCount":"1","onSaleCount":156,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516927304","title":"传奇如谜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.29,"price":25.29,"shippingFee":7,"differencePrice":-32.29,"GoodsUrl":"https://book.kongfz.com/238778/8228231786","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/16915416/c05e7a1b0d97ccac_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208018907","title":"中国的奇迹:发展战略与经济改革","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.72,"price":1.72,"shippingFee":5,"differencePrice":-6.72,"GoodsUrl":"https://book.kongfz.com/890432/8720058621","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddecacc/fa7dcc44fce0b0a5_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787110059753","title":"海洋","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":6,"shippingFee":3,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/838443/8896001587","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbbbbded/5ca2371ad0f6c234_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531358305","title":"萧军萧红交游考释","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":9.6,"shippingFee":4.4,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/321650/8279664994","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3974/037bf1538f5fc99ac7_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513335157","title":"最后的守护者","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.5,"price":32,"shippingFee":7.5,"differencePrice":-39.5,"GoodsUrl":"https://book.kongfz.com/161407/7322660044","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbfcceb/aaaede1c711ebe7a_b.jpg","GoodsImgCount":"5","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802257313","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801410016","title":"台湾史志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.73,"price":1.73,"shippingFee":5,"differencePrice":-6.73,"GoodsUrl":"https://book.kongfz.com/798675/8040942996","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaaefed/232c9fe6560dc0d3_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572606052","title":"拉塞-玛娅侦探所 第三辑 自行车迷案","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.890000000000001,"price":2.89,"shippingFee":2,"differencePrice":-4.890000000000001,"GoodsUrl":"https://book.kongfz.com/769044/8524727079","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faafecfc/2145ab50be5e1ccf_b.jpg","GoodsImgCount":"2","onSaleCount":229,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572231353","title":"咖啡帝国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":51,"price":36,"shippingFee":15,"differencePrice":-51,"GoodsUrl":"https://book.kongfz.com/649298/8649997321","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbaefcf/9704f4aa5c669110_b.jpg","GoodsImgCount":"7","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515807263","title":"茶铎八音","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2,"shippingFee":5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/261116/8559980205","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addcaffe/b756d1e8b0eeafb9_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562010326","title":"公司法论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.9,"price":27.9,"shippingFee":2,"differencePrice":-29.9,"GoodsUrl":"https://book.kongfz.com/241290/8326980017","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcfccbf/eed05bc7c12dd20f_b.jpg","GoodsImgCount":"4","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787554513514","title":"记忆传授人:“记忆传授人”四部曲 1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":5,"shippingFee":10,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/661692/8614596277","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcabcada/0013bde7267e5d37_b.jpg","GoodsImgCount":"3","onSaleCount":94,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309168846","title":"婴幼儿保教综合实训","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.24,"price":24.24,"shippingFee":2,"differencePrice":-26.24,"GoodsUrl":"https://book.kongfz.com/472611/8823269026","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fadceaad/f662f7d243246515_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531825494","title":"乌龙院大长篇漫画系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/410862/8714471607","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaafbdbb/2b9d0462e1b8b767_b.jpg","GoodsImgCount":"3","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807408550","title":"正版实拍 下厨记 III","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.13,"price":0.13,"shippingFee":5,"differencePrice":-5.13,"GoodsUrl":"https://book.kongfz.com/400965/8873428467","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efdcafef/08f462f18045e276_b.jpg","GoodsImgCount":"1","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787209126441","title":"不购买的习惯 日 金子由纪子著 山东人民出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.2,"price":6.2,"shippingFee":5,"differencePrice":-11.2,"GoodsUrl":"https://book.kongfz.com/910533/8800769752","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdaadad/ce4e50b49763be2f_b.jpg","GoodsImgCount":"1","onSaleCount":105,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501172740","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530652817","title":"小说月报:412期","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":5.8,"shippingFee":2.3,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/364403/4247581312","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3367/02e16f42ee18f1dbd6_b.jpg","GoodsImgCount":"4","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218120232","title":"梁冬说庄子 养生主","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":3.8,"shippingFee":6,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/914189/8243318884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abefeddf/2c6a08c3f4dc1ba2_b.jpg","GoodsImgCount":"9","onSaleCount":185,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111439066","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213112072","title":"财之道丛书·奥地利学派经济学简史:米塞斯的视角","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.4,"price":8,"shippingFee":10.4,"differencePrice":-18.4,"GoodsUrl":"https://book.kongfz.com/668091/8661535563","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbbfadfd/b4493c0b0d8ea96a_b.jpg","GoodsImgCount":"10","onSaleCount":121,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522500522","title":"正版现货桑梓誉重归名宗陈新森主编9787522500522新华仓库多仓直发","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.16,"price":9.16,"shippingFee":4,"differencePrice":-13.16,"GoodsUrl":"https://book.kongfz.com/170527/8156889048","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cddfebdd/32e201fc94025693_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020017232","title":"《发货快》忏悔录 [法]卢梭 著,范希衡 译 人民文学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.07,"price":7.57,"shippingFee":0.5,"differencePrice":-8.07,"GoodsUrl":"https://book.kongfz.com/156492/8384830037","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4362605/38ec4061f3fe6f66_b.jpg","GoodsImgCount":"1","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229081799","title":"生态文明:人类历史发展的必然选择(32开平装 全1册)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.41,"price":12.41,"shippingFee":6,"differencePrice":-18.41,"GoodsUrl":"https://book.kongfz.com/669893/8313786940","imgBigUrl":"https://www0.kfzimg.com/G06/M00/25/C9/p4YBAFsMoJSAPkWRAABSFJoSyoY034_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500872535","title":"我们的青春","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.39,"price":6.4,"shippingFee":5.99,"differencePrice":-12.39,"GoodsUrl":"https://book.kongfz.com/468773/6807539323","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedbcadb/3b900667369fa822_b.jpg","GoodsImgCount":"3","onSaleCount":62,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519445454","title":"2020年山西省普通高校专升本考试专用教材英语山西省在校专升本研究组/光明日报出版社9787519445454","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.9,"price":10.9,"shippingFee":0,"differencePrice":-10.9,"GoodsUrl":"https://book.kongfz.com/248516/8585444909","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/a64c0e9c50f98710_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559801791","title":"汉文佛教文献研究 佛教文献研究译丛","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55,"price":45,"shippingFee":10,"differencePrice":-55,"GoodsUrl":"https://book.kongfz.com/403/8540586001","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbfdeaa/d8216b91b56cedb8_b.jpg","GoodsImgCount":"2","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302476160","title":"系统规划与管理师教程(全国计算机技术与软件专业技术资格(水平)考试指定用书)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":2.2,"shippingFee":5,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/398369/8197191369","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baccedbc/5d9742e389b4a01e_b.jpg","GoodsImgCount":"1","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516810637","title":"儿童的人格教育","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.75,"price":1.75,"shippingFee":3,"differencePrice":-4.75,"GoodsUrl":"https://book.kongfz.com/783956/8696984436","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faeadeea/927cdef692f8076a_b.jpg","GoodsImgCount":"1","onSaleCount":210,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513930970","title":"特殊罪案调查组2","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.82,"price":5.82,"shippingFee":5,"differencePrice":-10.82,"GoodsUrl":"https://book.kongfz.com/1092446/8817399954","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbdaffb/eda37e39d3acd1ba_b.jpg","GoodsImgCount":"1","onSaleCount":156,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547405826","title":"金刚经 心经 国学经典读本丛书 金刚经心经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.65,"price":4.25,"shippingFee":2.4,"differencePrice":-6.65,"GoodsUrl":"https://book.kongfz.com/561672/8830865409","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfcdaca/dc3cf0b7d7e039d5_b.jpg","GoodsImgCount":"1","onSaleCount":86,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010218908","title":"夏商西周散文传播研究:基于先秦文献的考察","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.8,"price":16.8,"shippingFee":5,"differencePrice":-21.8,"GoodsUrl":"https://book.kongfz.com/475714/8882481687","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2344/01db6e7c5a748513a1_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560070216","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108047052","title":"陈寅恪的最后二十年(修订本)(精装)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40,"price":35,"shippingFee":5,"differencePrice":-40,"GoodsUrl":"https://book.kongfz.com/626307/8183197623","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdbbbfc/492dfd0042fef08c_b.jpg","GoodsImgCount":"3","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101140521","title":"造物记云南古茶园的秘密","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.7,"price":37.7,"shippingFee":2,"differencePrice":-39.7,"GoodsUrl":"https://book.kongfz.com/1214248/8773603177","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecbdbfd/384816fe4b359bb4_b.jpg","GoodsImgCount":"4","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505204324","title":"正方.反方.评方--历届大学生辩论会","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":2,"shippingFee":3,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/839152/8830821017","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcfefbed/6df83dc8f9f4eb3e_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787107174261","title":"滥觞与辉煌:朱永新教育文集(卷二)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.92,"price":3.92,"shippingFee":3,"differencePrice":-6.92,"GoodsUrl":"https://book.kongfz.com/566350/8848531607","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efededba/8793fe0e5f859d15_b.jpg","GoodsImgCount":"7","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300085425","title":"经验与理论:中国社会、经济与法律的实践历史研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":91,"price":85,"shippingFee":6,"differencePrice":-91,"GoodsUrl":"https://book.kongfz.com/26986/8505318233","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffebaceb/5e665fe35d11e0d6_b.jpg","GoodsImgCount":"4","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553743356","title":"跟着大厨学做宴客菜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.99,"price":2.99,"shippingFee":2,"differencePrice":-4.99,"GoodsUrl":"https://book.kongfz.com/779125/8445844689","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edecdbcb/1f663356d75b3fc1_b.jpg","GoodsImgCount":"1","onSaleCount":227,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500925774","title":"陈式太极拳精义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/204681/8857864879","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccecdacf/a4fbff5bf6a42616_b.jpg","GoodsImgCount":"7","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553924571","title":"20世纪中国科学口述史·走自己的路——吴文俊口述自传(正版\\内页干净\\实物拍摄)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":51,"price":45,"shippingFee":6,"differencePrice":-51,"GoodsUrl":"https://book.kongfz.com/218311/8625508085","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acddbbcb/1d9a5ae19c383ddb_b.jpg","GoodsImgCount":"4","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534501043","title":"实用武当气功","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":9,"shippingFee":7,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/14581/8817086084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbccbcbe/ead694ffe452f428_b.jpg","GoodsImgCount":"8","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509138052","title":"周耀庭讲小儿温病","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":17,"shippingFee":6,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/270515/8661563982","imgBigUrl":"https://www0.kfzimg.com/G07/M00/75/F2/q4YBAFvlRaeAYNaJAABkY-JAiVw250_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519122263","title":"【正版二手】大学素养语文第三版金振邦第3版9787519122263教育科学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.29,"price":3.29,"shippingFee":0,"differencePrice":-3.29,"GoodsUrl":"https://book.kongfz.com/783101/8471284217","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abdbfefa/6189125599d2f3e6_b.jpg","GoodsImgCount":"6","onSaleCount":216,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0}],"condition":85,"imageSelect":1,"userId":"1967112570379649025","taskId":"中心书库发布VB_0;BS_0;OMS_0;IllP_0;IA_0;BCS_2,999999;SCS_5,999999;userId_1967112570379649025;rand_1759227336656-3","way":"0"} +【2025-09-30 18:25:05】【返回参数】{"code":"200","success":true,"message":"执行成功"} +【2025-09-30 18:25:05】【日志结束,方法名称:centerBooks】【centerBooksAdd】中心书库发布商品 +【2025-09-30 18:27:05】【日志开始,方法名称:centerBooks】【centerBooksAdd】中心书库发布商品 +【2025-09-30 18:27:05】【执行参数】{"result":[{"isbn":"9787568918695","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572019722","title":"中学生思辨日知录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.41,"price":22.41,"shippingFee":1,"differencePrice":-23.41,"GoodsUrl":"https://book.kongfz.com/250369/7507863640","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4986191/4593582d712cdd2c_b.jpg","GoodsImgCount":"1","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518418466","title":"萨巴厨房 粗粮细做","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.3,"price":3.3,"shippingFee":5,"differencePrice":-8.3,"GoodsUrl":"https://book.kongfz.com/802508/8631264293","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dffbcfeb/6b008f588aa38d92_b.jpg","GoodsImgCount":"1","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514810813","title":"植物大战僵尸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":8,"shippingFee":3,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/566350/8842775522","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bebcbeee/b169dfd45b2c6889_b.jpg","GoodsImgCount":"5","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535688316","title":"(未拆封)小王子(唯美绘本典藏版,凯特·格林威大奖提名曼纽拉·阿德雷亚尼全新绘制)【浦睿文化出品】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2,"shippingFee":5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/695844/8215712304","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaddfcfe/5f734b0719ebcbe7_b.jpg","GoodsImgCount":"6","onSaleCount":99,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501559565","title":"诗词格律手册,,","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":4,"shippingFee":8,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/241320/6143640925","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbfdfacc/9361917dd464d637_b.jpg","GoodsImgCount":"4","onSaleCount":50,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100023085","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020157563","title":"西藏天空(茅盾文学奖得主、《尘埃落定》作者阿来作品。人如何才能成为真正的人?平等的爱才能铸就幸福)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/9617/8175403971","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1149758/0861d76b41b79344_b.jpg","GoodsImgCount":"3","onSaleCount":129,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521729405","title":"长期有耐心美团的成长与进化逻辑 丁西坡 中信出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.3,"price":15.3,"shippingFee":5,"differencePrice":-20.3,"GoodsUrl":"https://book.kongfz.com/910533/8776640084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdfcbfce/dc3b3f0f770b2564_b.jpg","GoodsImgCount":"1","onSaleCount":141,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559607577","title":"正版书籍命运:掌控你人生的命脉玄机 重塑人生主宰命运改变人生成功与运气","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.98,"price":8.98,"shippingFee":5,"differencePrice":-13.98,"GoodsUrl":"https://book.kongfz.com/442545/7044016865","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/12608860/b7aaf035a46742d8_b.jpg","GoodsImgCount":"1","onSaleCount":195,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546347110","title":"国学典藏 偏方秘方","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":0.5,"shippingFee":5,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/820017/8708620849","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daeddaef/0236a2498e1ea631_b.jpg","GoodsImgCount":"3","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522201573","title":"影子老师实战指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.15,"price":24.15,"shippingFee":2,"differencePrice":-26.15,"GoodsUrl":"https://book.kongfz.com/476106/8289838819","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaffcfff/5b82a2549640e185_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503322457","title":"实拍图 雄师劲旅 中国人民解放军第十一军征战纪实","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.689999999999998,"price":15.69,"shippingFee":4,"differencePrice":-19.689999999999998,"GoodsUrl":"https://book.kongfz.com/330788/8779037628","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddaadcd/354fcf459e2bc020_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508228327","title":"异国主食美味30种","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.9,"price":5.4,"shippingFee":3.5,"differencePrice":-8.9,"GoodsUrl":"https://book.kongfz.com/719470/7147511958","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/18693003/824e38ad750a4f7c_b.jpg","GoodsImgCount":"4","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506503945","title":"黄石公三略浅说","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":5,"shippingFee":9,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/16576/8322316451","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adcbcefe/735dcc4a5c9de005_b.jpg","GoodsImgCount":"4","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510408366","title":"实拍图 百弊放言","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.77,"price":5.77,"shippingFee":4,"differencePrice":-9.77,"GoodsUrl":"https://book.kongfz.com/330788/8655240012","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbabdeaa/d18897da754846a8_b.jpg","GoodsImgCount":"1","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122197689","title":"化工分离过程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.2,"price":1.2,"shippingFee":3,"differencePrice":-4.2,"GoodsUrl":"https://book.kongfz.com/774181/8784846555","imgBigUrl":"httpstotalPrice://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeccdcc/b03249bc4a0bff33_b.jpg","GoodsImgCount":"10","onSaleCount":145,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508649986","title":"正版二手书光荣与梦想(4)9787508649986","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.89,"price":6.89,"shippingFee":0,"differencePrice":-6.89,"GoodsUrl":"https://book.kongfz.com/765962/8807354840","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/facebfde/3179c1dbe9a1a3e1_b.jpg","GoodsImgCount":"1","onSaleCount":607,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787306038234","title":"新媒渠:中国营销实践版1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.98,"price":6.98,"shippingFee":0,"differencePrice":-6.98,"GoodsUrl":"https://book.kongfz.com/356195/8831898825","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/80acda36e6792b24_b.jpg","GoodsImgCount":"7","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550831971","title":"琴道(论古琴的思想体系)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":44,"price":34,"shippingFee":10,"differencePrice":-44,"GoodsUrl":"https://book.kongfz.com/471874/8103918813","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbcefca/3eaa20070e97dc68_b.jpg","GoodsImgCount":"10","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511517661","title":"中国梦 中国的奋斗与复兴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.199999999999999,"price":4.8,"shippingFee":2.4,"differencePrice":-7.199999999999999,"GoodsUrl":"https://book.kongfz.com/13534/8836412957","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdaaecc/f6e075e551b87645_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538731293","title":"本草纲目","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.35,"price":6.35,"shippingFee":5,"differencePrice":-11.35,"GoodsUrl":"https://book.kongfz.com/798675/8753394509","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afeedaca/c47788d5f78c4552_b.jpg","GoodsImgCount":"1","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805532752","title":"世界名曲欣赏·2·俄罗斯部分","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.5,"price":2.5,"shippingFee":5,"differencePrice":-7.5,"GoodsUrl":"https://book.kongfz.com/469122/8625940704","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feddbdba/17478803856c6a77_b.jpg","GoodsImgCount":"9","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787566801715","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117237321","title":"英汉对照护理英语会话(第2版 英汉对照)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/508346/8881986880","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfdacfb/eecb8ef0a9eceff3_b.jpg","GoodsImgCount":"9","onSaleCount":104,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807058953","title":"景丽瑜伽:瑜伽初级入门(升级版)附光盘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":3.3,"shippingFee":0,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/840504/8228479927","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adfedacd/19bfd9488c0fbb11_b.jpg","GoodsImgCount":"7","onSaleCount":448,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122270795","title":"新SAT阅读长难句精讲30天第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.559999999999999,"price":4.06,"shippingFee":4.5,"differencePrice":-8.559999999999999,"GoodsUrl":"https://book.kongfz.com/877194/8511050402","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fafafbfd/6b7b13835b41f7ec_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508224664","title":"英语语法表解手册 (修订版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":38,"shippingFee":10,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/269417/5120887447","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faecbabe/9519270017db1bd6_b.jpg","GoodsImgCount":"2","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534736025","title":"中国国家地理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.9399999999999995,"price":4.93,"shippingFee":0.01,"differencePrice":-4.9399999999999995,"GoodsUrl":"https://book.kongfz.com/545601/8761272941","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14322431/d91e5ce59a592a24_b.jpg","GoodsImgCount":"2","onSaleCount":151,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787107346361","title":"普通高中教科书教师教学用书生物学选择性必修2生物与环境 人民教育出版社课程教材研究所生物课程教材研究开发中心编著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.5,"price":10.5,"shippingFee":3,"differencePrice":-13.5,"GoodsUrl":"https://book.kongfz.com/681595/8811715235","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdefffb/0fbe52d7dda4ef04_b.jpg","GoodsImgCount":"3","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030207500","title":"大学应用物理 蒲利春 张雪峰 科学出版社 9787030207500","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.87,"price":1.87,"shippingFee":3,"differencePrice":-4.87,"GoodsUrl":"https://book.kongfz.com/195620/8312037668","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5749161/6e89f9d1af7e7989_b.jpg","GoodsImgCount":"1","onSaleCount":72,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213104589","title":"颠覆:马斯克的商业逻辑和创新法则(九品)9787213104589","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.9,"price":9.3,"shippingFee":2.6,"differencePrice":-11.9,"GoodsUrl":"https://book.kongfz.com/20579/8802296569","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbadefca/15c37dc77ff955cf_b.jpg","GoodsImgCount":"1","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535364456","title":"古代传说中的怪物【正版 塑封 发货快】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/891652/8853257427","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acceceed/610520b76a3ebe80_b.jpg","GoodsImgCount":"5","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560417035","title":"对农民让利:一个乡镇党委书记的工作笔记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.8,"price":2.8,"shippingFee":10,"differencePrice":-12.8,"GoodsUrl":"https://book.kongfz.com/20238/6553568561","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2388552/6b834f981ec7e865_b.jpg","GoodsImgCount":"7","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545560978","title":"邓小平","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.18,"price":9.18,"shippingFee":5,"differencePrice":-14.18,"GoodsUrl":"https://book.kongfz.com/805022/8530275546","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21340856/36aaf5bffbf85d8c_b.jpg","GoodsImgCount":"1","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569506563","title":"活着,就该尽点儿兴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":8,"shippingFee":5,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/364917/8345040086","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecccebaa/eae7ce24870491e4_b.jpg","GoodsImgCount":"3","onSaleCount":139,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534338755","title":"中国文化史教程第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.49,"price":1.49,"shippingFee":4,"differencePrice":-5.49,"GoodsUrl":"https://book.kongfz.com/878042/8490636209","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaadffef/7807b51707816c48_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500319368","title":"历代画谱类编:山水(12)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":52,"price":40,"shippingFee":12,"differencePrice":-52,"GoodsUrl":"https://book.kongfz.com/25728/8440709404","imgBigUrl":"https://www0.kfzimg.com/G06/M00/14/79/p4YBAFqisNaAIasgAABrIQx-ikM832_b.jpg","GoodsImgCount":"1","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533258030","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802257481","title":"希腊棺材之谜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.73,"price":12.73,"shippingFee":5,"differencePrice":-17.73,"GoodsUrl":"https://book.kongfz.com/202798/8894676974","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccccbdec/2343a3c4f807db86_b.jpg","GoodsImgCount":"1","onSaleCount":85,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117055352","title":"妇产科手术学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":28,"shippingFee":10,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/760393/8899580666","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffaecbce/b54811d7b2204a06_b.jpg","GoodsImgCount":"3","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532522453","title":"韩愈散文选集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":6,"shippingFee":6,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/263916/8292153110","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abacbbfc/82ed778ad7f2030c_b.jpg","GoodsImgCount":"7","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301347775","title":"中国现代文学三十年(第三版)北京大学钱理群、温儒敏、吴福辉教授著 现当代文学书及中文系考研重要参考书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":13,"shippingFee":10,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/574881/7680988794","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deffdbae/bb726b02bcf65138_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500166207","title":"疫情后中国经济新发展格局","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":1.5,"shippingFee":3,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/838443/8749381946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebecdcad/222250eecf4e488c_b.jpg","GoodsImgCount":"1","onSaleCount":323,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546420950","title":"7岁对了,一辈子就对了","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/712812/7340204569","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbffeec/79cd4560b8c5de05_b.jpg","GoodsImgCount":"4","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807676447","title":"云冈石窟","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.5,"price":8,"shippingFee":4.5,"differencePrice":-12.5,"GoodsUrl":"https://book.kongfz.com/81946/6302388964","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baeaffef/65208eca36d1432c_b.jpg","GoodsImgCount":"4","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305120305","title":"正版新书现货 文学理论读本/IAS励学文丛 9787305120305 阎嘉|主编:周宪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.66,"price":32.66,"shippingFee":5,"differencePrice":-37.66,"GoodsUrl":"https://book.kongfz.com/311632/8812587135","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babdccad/2ba0f4a400d24004_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540485818","title":"散落星河的记忆4:璀璨","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":12,"shippingFee":8,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/639697/5243750723","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfecffea/f776a0acf017e68f_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559652737","title":"看国宝 和爸妈游博物馆","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.9,"price":1.8,"shippingFee":3.1,"differencePrice":-4.9,"GoodsUrl":"https://book.kongfz.com/894143/8701969746","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaabafee/f2595c7b2fd4a550_b.jpg","GoodsImgCount":"6","onSaleCount":261,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503943348","title":"献给阿尔吉侬的花束","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":10,"shippingFee":10,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/498915/7429202611","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbebfaec/d6256a6ee6537fa6_b.jpg","GoodsImgCount":"10","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301085493","title":"简单机械(中文翻译版)——国家地理阅读与写作训练丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/395221/5519963069","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1098/c6f60cc2ccbee2bb_b.jpg","GoodsImgCount":"2","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543211018","title":"寺庙自助游完全手册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":15,"shippingFee":0,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/700859/7742663957","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acecbabc/2d6e70c49c17570e_b.jpg","GoodsImgCount":"3","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801491589","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561327265","title":"正版二手书二手正版重返普罗旺斯97875613272659787561327265","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/765962/8631594226","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babdaece/b00ebe69df5166ff_b.jpg","GoodsImgCount":"1","onSaleCount":341,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543225589","title":"信用评级理论与实务 第二版叶伟春 编格致出版社9787543225589","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.17,"price":4.17,"shippingFee":0,"differencePrice":-4.17,"GoodsUrl":"https://book.kongfz.com/443530/8601138144","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11958278/4e1eb16e9d1c0462_b.jpg","GoodsImgCount":"1","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507547092","title":"我们生命里的“七七”(许倬云、郝柏村、齐邦媛、星云大师等用生命记录一篇篇撼动心灵的故事)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":35,"shippingFee":8,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/274410/7932527162","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddedaaac/5cabe80609502ec1_b.jpg","GoodsImgCount":"7","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787555373070","title":"2023秋状元导学案名师教学设计数学三年级上册样书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":5,"shippingFee":9,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/381029/8749671888","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcedeaf/6bf3c05878ca8f83_b.jpg","GoodsImgCount":"3","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540206956","title":"中国谋略宝鉴第十六卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.01,"price":0.01,"shippingFee":3,"differencePrice":-3.01,"GoodsUrl":"https://book.kongfz.com/360813/5966263658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdbfdfa/62959300371438f8_b.jpg","GoodsImgCount":"2","onSaleCount":330,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518051625","title":"肿瘤医院营养师的防癌抗癌吃法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.790000000000001,"price":5.19,"shippingFee":1.6,"differencePrice":-6.790000000000001,"GoodsUrl":"https://book.kongfz.com/457799/7915187178","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C3/5E/p4YBAFuRCEOAGxQ5AAC90eEIDkQ669_b.jpg","GoodsImgCount":"0","onSaleCount":220,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508079165","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787102041223","title":"物色黑白","quality":0,"qualityText":"","originalPrice":0,"totalPrice":66,"price":66,"shippingFee":0,"differencePrice":-66,"GoodsUrl":"https://book.kongfz.com/319064/8795448603","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbeefaca/c584b2d59a425bfc_b.jpg","GoodsImgCount":"8","onSaleCount":76,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787220108211","title":"瑜伽文库〔5〕:阿育吠陀瑜伽","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.8,"price":19.8,"shippingFee":13,"differencePrice":-32.8,"GoodsUrl":"https://book.kongfz.com/402676/8643741176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeaabefd/2a392099ec628856_b.jpg","GoodsImgCount":"9","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810103855","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806498439","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545435702","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539186887","title":"我的第一本科学漫画书寻宝记系列:巴西寻宝记11","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.51,"price":0.01,"shippingFee":4.5,"differencePrice":-4.51,"GoodsUrl":"https://book.kongfz.com/825588/8886241126","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccedcffa/61ddbfc1f57a12af_b.jpg","GoodsImgCount":"5","onSaleCount":248,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537144704","title":"写给小读者之快乐精灵","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":2,"shippingFee":3,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/774181/8597113775","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfcffafb/d701ee2510c5ed23_b.jpg","GoodsImgCount":"5","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115106124","title":"WindowsAPI函数参考手册 WindowsAPI函数参考手册 编写组编 人民邮电出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.37,"price":24.37,"shippingFee":4,"differencePrice":-28.37,"GoodsUrl":"https://book.kongfz.com/878042/8495444282","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfbeabaa/96a386fdb8bce4df_b.jpg","GoodsImgCount":"1","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535612793","title":"论摄影","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":12,"shippingFee":0,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/26771/8136858550","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eabfccee/3ca1daf23bce666c_b.jpg","GoodsImgCount":"4","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532785445","title":"近代文学批评史(全八卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":411.88,"price":401.88,"shippingFee":10,"differencePrice":-411.88,"GoodsUrl":"https://book.kongfz.com/471874/8695951046","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdabfceb/3089afd17e730b90_b.jpg","GoodsImgCount":"5","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504758415","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500311133","title":"徽派与徽州篆刻研究专辑:西泠印社(总第21辑)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.11,"price":16.11,"shippingFee":0,"differencePrice":-16.11,"GoodsUrl":"https://book.kongfz.com/897296/8237009972","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23068564/6d816b75de4e44ee_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111180623","title":"物业管理沟通艺术","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31,"price":24,"shippingFee":7,"differencePrice":-31,"GoodsUrl":"https://book.kongfz.com/912353/8289311525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdfcefa/39fd857445991f96_b.jpg","GoodsImgCount":"6","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532520756","title":"天涯侠侣册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.26,"price":4.26,"shippingFee":2,"differencePrice":-6.26,"GoodsUrl":"https://book.kongfz.com/1214361/8873449966","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbbddcb/8610a576eb08226a_b.jpg","GoodsImgCount":"4","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787109200845","title":"榨汁机美味食谱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.5,"price":20,"shippingFee":3.5,"differencePrice":-23.5,"GoodsUrl":"https://book.kongfz.com/719470/8585565450","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/18693003/0bfa2608b791ef68_b.jpg","GoodsImgCount":"3","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544763035","title":"三个女人 罗伯特 穆齐尔 译林出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.69,"price":9.69,"shippingFee":4,"differencePrice":-13.69,"GoodsUrl":"https://book.kongfz.com/766912/8858942814","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdefddae/bfa6459d0d82fb08_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541736247","title":"2007年最佳小故事排行榜TOP100感动卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/1207077/8702929036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efcbbdfa/2d9763b9c691fc8d_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507838336","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556021703","title":"女儿的故事 梅子涵 9787556021703 长江少年儿童出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.18,"price":1.68,"shippingFee":2.5,"differencePrice":-4.18,"GoodsUrl":"https://book.kongfz.com/237713/8792049160","imgBigUrl":"https://www0.kfzimg.com/G06/M00/38/4F/p4YBAFqjzVGAQ2WRAABJeXbuA7o046_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533937928","title":"迷狂 精装32开一版一印","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/696299/5906512396","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afabbcbb/9090a343c388e169_b.jpg","GoodsImgCount":"5","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565513671","title":"普通土壤学(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/506902/4876475660","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abbefebc/96f603e5373aadfd_b.jpg","GoodsImgCount":"2","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805646862","title":"野性的证明","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.98,"price":1.98,"shippingFee":3,"differencePrice":-4.98,"GoodsUrl":"https://book.kongfz.com/557002/5846843192","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbaeffbf/4b2a328969a84da5_b.jpg","GoodsImgCount":"6","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501767939","title":"期货-财富永动机","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":2,"shippingFee":4.9,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/26937/3839324520","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbfccfbb/f0d427a5206db5af_b.jpg","GoodsImgCount":"4","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787204009978","title":"红砂勾魂手 品好","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":19,"shippingFee":9,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/303616/8201886650","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafbbaba/e4d9bb837f6179d2_b.jpg","GoodsImgCount":"13","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020165650","title":"岁月静好:蒋勋的日常功课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.46,"price":18.46,"shippingFee":0,"differencePrice":-18.46,"GoodsUrl":"https://book.kongfz.com/792408/8898218361","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2790/02552e196a86ee0f77_b.jpg","GoodsImgCount":"1","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509823743","title":"红色之路烽火","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/730214/8858116427","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbeeebe/f500632e8ecee420_b.jpg","GoodsImgCount":"4","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536472129","title":"拉玛迷境","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34,"price":22,"shippingFee":12,"differencePrice":-34,"GoodsUrl":"https://book.kongfz.com/151474/8535484987","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbddebe/867cffc401ca09c4_b.jpg","GoodsImgCount":"7","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121211515","title":"学而思 培优辅导:初二物理跟踪练习(上下)附答案","quality":0,"qualityText":"","originalPrice":0,"totalPrice":120,"price":110,"shippingFee":10,"differencePrice":-120,"GoodsUrl":"https://book.kongfz.com/23910/8754936757","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3161432/7d4639abda234b4e_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224054538","title":"心血运动论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.67,"price":3.77,"shippingFee":3.9,"differencePrice":-7.67,"GoodsUrl":"https://book.kongfz.com/261575/7984459895","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecfcdcfa/b3872a57908ad1e8_b.jpg","GoodsImgCount":"5","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020081776","title":"芥川龙之介读本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":12,"shippingFee":8,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/689520/8843157283","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babacfce/8db8bcfa2d41f417_b.jpg","GoodsImgCount":"7","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532603763","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510430008","title":"新青瓷之窑变","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.06,"price":3.06,"shippingFee":5,"differencePrice":-8.06,"GoodsUrl":"https://book.kongfz.com/1207077/8886789761","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfdabcaa/1796162e1d9f2e4b_b.jpg","GoodsImgCount":"1","onSaleCount":251,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536564343","title":"夜翼天使","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/470358/4339829959","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfdffca/d07df374b3e13496_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550708471","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507850642","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544624770","title":"新编高级英语语法:A New Advanced English Grammar","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32,"price":20,"shippingFee":12,"differencePrice":-32,"GoodsUrl":"https://book.kongfz.com/830099/8882431094","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbaccbf/781a6310a0eb776e_b.jpg","GoodsImgCount":"9","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115495372","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506290227","title":"墓志书法百品","quality":0,"qualityText":"","originalPrice":0,"totalPrice":57.82,"price":46.82,"shippingFee":11,"differencePrice":-57.82,"GoodsUrl":"https://book.kongfz.com/509141/8585650720","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14014041/28964975e7dc309e_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559634351","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303135660","title":"顾明远教育口述史(增订)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/17747/5768445516","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1970964/2e94e4bdc50d3792_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800880452","title":"龙虎群英 中","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":1.5,"shippingFee":4,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/203004/8899012503","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdabaaea/64e07e07529c21b6_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538290622","title":"PASS初中英语巧记2000词","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":2,"shippingFee":3,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/841015/8684297376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcfffbab/4b67a6d547944648_b.jpg","GoodsImgCount":"4","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101084894","title":"中华经典精粹解读:史记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/702814/8179518138","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/defadbfe/4eea5c6a4809568e_b.jpg","GoodsImgCount":"4","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301270189","title":"文本的隐与显 中国现代文学文献校读论稿 解志熙著 北京大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.8,"price":25.8,"shippingFee":5,"differencePrice":-30.8,"GoodsUrl":"https://book.kongfz.com/903313/8547742130","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfeacbae/ddfb49783c133365_b.jpg","GoodsImgCount":"1","onSaleCount":85,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787552569421","title":"阅读理解超快提分公式","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":10,"shippingFee":0,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/34480/7649697434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/15505652/d3d2322c7ec0cb86_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511717306","title":"中央编译局文库 中国的民主治理 理论与实践 效率政府","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.059999999999999,"price":5.06,"shippingFee":3,"differencePrice":-8.059999999999999,"GoodsUrl":"https://book.kongfz.com/783956/8891177168","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acacbaae/5200429427f763ac_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571209483","title":"墨点字帖:2025秋英语写字同步练习册·必修第三册(新教材)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.01,"price":4.51,"shippingFee":4.5,"differencePrice":-9.01,"GoodsUrl":"https://book.kongfz.com/757284/8792634933","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbefcfaa/0cffeeed9f3fd774_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539448374","title":"历代书法名碑名帖精选:隶书(2)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/27190/365578569","imgBigUrl":"https://www0.kfzimg.com/G03/M01/70/45/pYYBAFWvkZeAZ3boAADmaxNa8ss048_b.jpg","GoodsImgCount":"3","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544246255","title":"星期三的战争 美 加里 施密特著 高雪莲译 南海出版公司","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.3,"price":1.3,"shippingFee":5,"differencePrice":-6.3,"GoodsUrl":"https://book.kongfz.com/672601/8709251624","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfddfcdd/b6b4d1110bf4f714_b.jpg","GoodsImgCount":"1","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787205094157","title":"红楼人物家庭角色论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":81,"price":71,"shippingFee":10,"differencePrice":-81,"GoodsUrl":"https://book.kongfz.com/20509/2274876206","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1930/017c3cfaea4867b6f6_b.jpg","GoodsImgCount":"1","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569912647","title":"美在举手投足间 一个人若举止优雅 心灵也会变得更坚强","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.7,"price":12.7,"shippingFee":5,"differencePrice":-17.7,"GoodsUrl":"https://book.kongfz.com/398369/8265506509","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/debccfdc/6d2d3253fb537795_b.jpg","GoodsImgCount":"1","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538724554","title":"毕淑敏作品2·话说孩子毕淑敏时代文艺出版社9787538724554","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.64,"price":4.64,"shippingFee":0,"differencePrice":-4.64,"GoodsUrl":"https://book.kongfz.com/366030/8301042871","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/29e82405eff322db_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534759819","title":"理学古文史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":5,"shippingFee":10,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/233973/8223713174","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbfabab/c49dd1ce62c4a5fb_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787307043114","title":"数字测图原理与方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/603269/8864023084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aacfabef/22ba103e580191bb_b.jpg","GoodsImgCount":"7","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801516091","title":"我信我能我要","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43.21,"price":32.21,"shippingFee":11,"differencePrice":-43.21,"GoodsUrl":"https://book.kongfz.com/878875/8142977482","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22516043/bd4ef387b1384988_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020161638","title":"袁枚诗选(中国古典文学读本丛书典藏)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.36,"price":21.36,"shippingFee":2,"differencePrice":-23.36,"GoodsUrl":"https://book.kongfz.com/476106/8283375310","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebcdbcdd/18643d009e705fdc_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787220040528","title":"历代笔记小说精华 第四卷 清","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.3,"price":23.3,"shippingFee":5,"differencePrice":-28.3,"GoodsUrl":"https://book.kongfz.com/261116/8560390036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceceadad/4cef7455f3e00ef9_b.jpg","GoodsImgCount":"1","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537733373","title":"少林拳术图说","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/210450/4528748517","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D7/AB/p4YBAFqYwJuAJtQPAACd0cT9L9o331_b.jpg","GoodsImgCount":"1","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800063107","title":"汉语方言词汇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":66.5,"price":61,"shippingFee":5.5,"differencePrice":-66.5,"GoodsUrl":"https://book.kongfz.com/405080/7310375008","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daeceecf/30475e68c2096095_b.jpg","GoodsImgCount":"1","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020075782","title":"唐宋词简释","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.2,"price":7.7,"shippingFee":3.5,"differencePrice":-11.2,"GoodsUrl":"https://book.kongfz.com/206421/8501383468","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6147505/9dea4fd349d3d63a_b.jpg","GoodsImgCount":"2","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531855354","title":"东汉演义之二十八《武瘟神下山》","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":25,"shippingFee":0,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/712837/6676396249","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbfaaede/5fd873f0845c0e19_b.jpg","GoodsImgCount":"6","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516100516","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806683200","title":"上海探戈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.79,"price":1.59,"shippingFee":3.2,"differencePrice":-4.79,"GoodsUrl":"https://book.kongfz.com/739740/7152710203","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbacecee/cac0ec945280e864_b.jpg","GoodsImgCount":"4","onSaleCount":228,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502705329","title":"正版 (同系3本包邮)中国古代航海 中国传统民俗文化政治经济制度系列古代航海活动 海上丝绸之路 郑和下西洋指南针的发明与航海等古代航海事业 9787502705329","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.3,"price":14.3,"shippingFee":6,"differencePrice":-20.3,"GoodsUrl":"https://book.kongfz.com/14409/8719267733","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1570906/9b5183c8dd9004c0_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300305042","title":"小学儿童心理学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":5.5,"shippingFee":1.5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/774690/8698078134","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/12774130/3dec28e005f0c72f_b.jpg","GoodsImgCount":"1","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543579217","title":"少年时飞机大解剖","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6,"price":3,"shippingFee":3,"differencePrice":-6,"GoodsUrl":"https://book.kongfz.com/838443/8811129821","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffaeffad/54baa2c8e92b3e4a_b.jpg","GoodsImgCount":"1","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802128125","title":"中国分省系列地图集 河北省地图集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":7,"shippingFee":5,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/911327/8701948242","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdccbec/8f996e037aa30df2_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101015485","title":"祥云县志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":126,"price":120,"shippingFee":6,"differencePrice":-126,"GoodsUrl":"https://book.kongfz.com/409331/3661003725","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eccfbcdd/733430ba3bdecdfb_b.jpg","GoodsImgCount":"6","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117267304","title":"正版二手 变态心理学(第3版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.69,"price":16.69,"shippingFee":0,"differencePrice":-16.69,"GoodsUrl":"https://book.kongfz.com/549116/8830860499","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D4/28/p4YBAFt-5veAPPw7AABq9rtHFGs112_b.jpg","GoodsImgCount":"1","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218045627","title":"现象学的始基","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.16,"price":32.16,"shippingFee":0,"differencePrice":-32.16,"GoodsUrl":"https://book.kongfz.com/792228/8885481303","imgBigUrl":"https://www0.kfzimg.com/G06/M00/62/A7/p4YBAFuCZAWAOEfaAAA_Rk5xTx8034_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513312097","title":"人骨拼图:林肯·莱姆系列之一","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.27,"price":13.27,"shippingFee":10,"differencePrice":-23.27,"GoodsUrl":"https://book.kongfz.com/915406/8415906199","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecfbead/4d4a0685889879f4_b.jpg","GoodsImgCount":"3","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513653343","title":"商社就是天网","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.94,"price":16.94,"shippingFee":5,"differencePrice":-21.94,"GoodsUrl":"https://book.kongfz.com/202798/8568284655","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfafbfc/c08df37a7d16dd93_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040079869","title":"电子技术基础数字部分第4版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":0.5,"shippingFee":5,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/820017/8732562193","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaecdacd/e70eef6ce74fdfbe_b.jpg","GoodsImgCount":"2","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505725508","title":"盗墓笔记5 谜海归巢","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.92,"price":4.12,"shippingFee":2.8,"differencePrice":-6.92,"GoodsUrl":"https://book.kongfz.com/1093663/8899378239","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daffabac/fe727b4b941bbc33_b.jpg","GoodsImgCount":"1","onSaleCount":362,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509155189","title":"颈腰关节疼痛及注射疗法 第5版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":184,"price":168,"shippingFee":16,"differencePrice":-184,"GoodsUrl":"https://book.kongfz.com/165055/8254619732","imgBigUrl":"https://www0.kfzimg.com/G05/M00/F1/D0/p4YBAFmNI22AdqQ1AAT058m6zlw056_b.jpg","GoodsImgCount":"9","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509641651","title":"实拍图 文化的逻辑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.74,"price":4.74,"shippingFee":5,"differencePrice":-9.74,"GoodsUrl":"https://book.kongfz.com/802501/8561762805","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbabfcdc/6980f786578b04a8_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200044867","title":"梦断紫禁城","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.08,"price":2.08,"shippingFee":3,"differencePrice":-5.08,"GoodsUrl":"https://book.kongfz.com/832065/8677126488","imgBigUrl":"https://www0.kfzimg.com/G06/M00/B0/84/p4YBAFrBjlSAJZRXAADDlnNLY8U712_b.jpg","GoodsImgCount":"1","onSaleCount":162,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801123596","title":"中国民主建国会史稿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":2.2,"shippingFee":3.3,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/912942/8547857084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcefdeae/6c07c7d88214a065_b.jpg","GoodsImgCount":"2","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301139899","title":"地质学原理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":29,"shippingFee":9,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/521012/8429778365","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfbbdbcd/7e66c3c7cba28ccd_b.jpg","GoodsImgCount":"4","onSaleCount":150,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787104019404","title":"中国现代话剧教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":2,"shippingFee":8,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/23363/8631048802","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3089567/3d8d13eefa1391ea_b.jpg","GoodsImgCount":"3","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506671965","title":"温室气体核算体系:企业价值链(范围三)核算与报告标准","quality":0,"qualityText":"","originalPrice":0,"totalPrice":88,"price":78,"shippingFee":10,"differencePrice":-88,"GoodsUrl":"https://book.kongfz.com/12885/7710497039","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aeaedccf/213af3af7a5412cd_b.jpg","GoodsImgCount":"3","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108016850","title":"人·兽·鬼","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.779999999999999,"price":5.77,"shippingFee":0.01,"differencePrice":-5.779999999999999,"GoodsUrl":"https://book.kongfz.com/877749/8801481679","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/421097e73bed945d_b.jpg","GoodsImgCount":"3","onSaleCount":382,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111350118","title":"材料力学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":14,"shippingFee":8,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/190848/8546617490","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebfbffac/bbc9b45a3879d75e_b.jpg","GoodsImgCount":"1","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539996301","title":"纳粹医生:医学屠杀与种族灭绝心理学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":22,"shippingFee":7,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/677955/8132923615","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efaecfbb/b6bb3ab2cfa17bb1_b.jpg","GoodsImgCount":"10","onSaleCount":171,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117141598","title":"实地解剖学(本科创新教材)(第2版)羊惠君9787117141598人民卫生出版社羊惠君 编人民卫生出版社9787117141598","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":10,"shippingFee":0,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/810267/8649014717","imgBigUrl":"https://www0.kfzimg.com/G06/M00/20/51/p4YBAFqaTeyAWKo9AAB4_CSZkNs668_b.jpg","GoodsImgCount":"2","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532785230","title":"彩虹几度","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.5,"price":10,"shippingFee":7.5,"differencePrice":-17.5,"GoodsUrl":"https://book.kongfz.com/274142/6240614349","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbfddad/7d7cfe731f17e04d_b.jpg","GoodsImgCount":"4","onSaleCount":103,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801456915","title":"世界艳史 彩图版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.36,"price":1.36,"shippingFee":3,"differencePrice":-4.36,"GoodsUrl":"https://book.kongfz.com/791250/8511647318","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babfecff/e3ea21a762374dc7_b.jpg","GoodsImgCount":"1","onSaleCount":285,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805202174","title":"白话尚书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.2,"price":8.2,"shippingFee":4,"differencePrice":-12.2,"GoodsUrl":"https://book.kongfz.com/203004/8424128025","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdebccad/0b4a13e8667c9f38_b.jpg","GoodsImgCount":"1","onSaleCount":50,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100240147","title":"回望;西南联大沉思录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":44.9,"price":42.9,"shippingFee":2,"differencePrice":-44.9,"GoodsUrl":"https://book.kongfz.com/531424/8836849831","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfecbfde/300a0427a530a221_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556841233","title":"我的第一本科学漫画书 世界寻宝记26 意大利1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.53,"price":1.03,"shippingFee":4.5,"differencePrice":-5.53,"GoodsUrl":"https://book.kongfz.com/1148054/8608793479","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddaabcec/c7db2f605b3fe3d5_b.jpg","GoodsImgCount":"1","onSaleCount":136,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521728057","title":"薛暮桥年谱 1904-1952","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":24.8,"shippingFee":5,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/180897/8428895461","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceceafce/caceb3157ab2e82e_b.jpg","GoodsImgCount":"1","onSaleCount":128,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547258569","title":"你若不勇敢谁替你坚强思履编9787547258569","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":0.5,"shippingFee":2.8,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/783757/8331651577","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdeddde/efd4c2250ad6a94d_b.jpg","GoodsImgCount":"1","onSaleCount":337,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547122990","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560082073","title":"剑桥雅思听力精练","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.03,"price":9.03,"shippingFee":4,"differencePrice":-13.03,"GoodsUrl":"https://book.kongfz.com/884251/8122170338","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaeeafee/47b06a1e8e364586_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550605015","title":"高盛在中国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3,"price":4.29,"shippingFee":0.01,"differencePrice":-4.3,"GoodsUrl":"https://book.kongfz.com/836621/8847676368","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeccebf/0ebeedb9d50da249_b.jpg","GoodsImgCount":"4","onSaleCount":263,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559639769","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302112785","title":"第三次改革:中国非营利部门战略研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.89,"price":6.39,"shippingFee":1.5,"differencePrice":-7.89,"GoodsUrl":"https://book.kongfz.com/774690/8186180572","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AB/04/p4YBAFr8MJuAGAghAAA1z6WS3zI917_b.jpg","GoodsImgCount":"1","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530771389","title":"35公斤的希望","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.84,"price":8.04,"shippingFee":3.8,"differencePrice":-11.84,"GoodsUrl":"https://book.kongfz.com/1213190/8836708018","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dafaafec/7cf7665548548831_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533937102","title":"名家散文典藏·平凹散文:丑石","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.9,"price":5.9,"shippingFee":3,"differencePrice":-8.9,"GoodsUrl":"https://book.kongfz.com/681595/8690093248","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddbdffb/4f941801eb25debf_b.jpg","GoodsImgCount":"3","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536015920","title":"周易八卦实解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34,"price":28,"shippingFee":6,"differencePrice":-34,"GoodsUrl":"https://book.kongfz.com/907443/8170308109","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafeecaf/897ff4b8c0710df5_b.jpg","GoodsImgCount":"7","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516606476","title":"实干成就梦想","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":4.8,"shippingFee":5,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/350027/5033853984","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcacdab/2a63dd061ea42499_b.jpg","GoodsImgCount":"7","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301354377","title":"你写的论文,为什么老师总看不上?","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.58,"price":26.58,"shippingFee":3,"differencePrice":-29.58,"GoodsUrl":"https://book.kongfz.com/787155/8780056007","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13196094/1eec498b7026e22c_b.jpg","GoodsImgCount":"1","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122223289","title":"【正版二手】建筑结构与选型崔钦淑9787122223289化学工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.78,"price":3.78,"shippingFee":0,"differencePrice":-3.78,"GoodsUrl":"https://book.kongfz.com/805904/7166459946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/febaefaf/7e1ada906fcd9fe5_b.jpg","GoodsImgCount":"6","onSaleCount":101,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530215982","title":"风声","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.4,"price":7.4,"shippingFee":4,"differencePrice":-11.4,"GoodsUrl":"https://book.kongfz.com/203004/8422969956","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcaedba/f9c5e1712684ca6f_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511273048","title":"麻省理工商学院最具影响力的商业哲学课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.66,"price":12.66,"shippingFee":0,"differencePrice":-12.66,"GoodsUrl":"https://book.kongfz.com/792228/8901674659","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E2/0D/p4YBAFqY5zyAO8BbAADniLoteH8960_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502844684","title":"主力行为盘口解密二 随机发","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":6,"shippingFee":2,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/755561/8872649902","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbcffdcc/041163d5f287171b_b.jpg","GoodsImgCount":"3","onSaleCount":152,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504486004","title":"中国传统民俗文化 中国古代城墙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.8100000000000005,"price":1.81,"shippingFee":5,"differencePrice":-6.8100000000000005,"GoodsUrl":"https://book.kongfz.com/23607/8261593719","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deacabba/95b12624c888dc2c_b.jpg","GoodsImgCount":"1","onSaleCount":147,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507753936","title":"环喜马拉雅区域研究编译文集二——佐米亚、边疆与跨界","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33.3,"price":27.3,"shippingFee":6,"differencePrice":-33.3,"GoodsUrl":"https://book.kongfz.com/522587/8886443261","imgBigUrl":"https://www0.kfzimg.com/G06/M00/37/D8/p4YBAFsnavWAAHndAABM74pZ9cE770_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504691422","title":"百年耕耘 金善宝传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.58,"price":24.58,"shippingFee":5,"differencePrice":-29.58,"GoodsUrl":"https://book.kongfz.com/716746/8485861144","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddccfdfa/320fa35108c02c52_b.jpg","GoodsImgCount":"2","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121350894","title":"服装设计效果图手绘教程 全彩","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.6899999999999995,"price":0.69,"shippingFee":5,"differencePrice":-5.6899999999999995,"GoodsUrl":"https://book.kongfz.com/1215524/8813604508","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decedfeb/df55bfbeacd0bdc0_b.jpg","GoodsImgCount":"2","onSaleCount":110,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530858394","title":"最具人气的110篇微型小说","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":2.2,"shippingFee":5,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/820017/8708554212","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dedacdcd/5f5491cc457f068e_b.jpg","GoodsImgCount":"2","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509130520","title":"吕仁和临床经验集(第二辑)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":38,"shippingFee":10,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/273906/7915510103","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afaccaba/e01e4552aa321dbb_b.jpg","GoodsImgCount":"5","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101021264","title":"启功丛稿 论文卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/15897/8530660645","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebfcbfae/f929a4dd9ca3e4b8_b.jpg","GoodsImgCount":"6","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541126628","title":"和气生财","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.39,"price":0.89,"shippingFee":4.5,"differencePrice":-5.39,"GoodsUrl":"https://book.kongfz.com/898393/8830817137","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedbcfde/d399a83aa69886b0_b.jpg","GoodsImgCount":"3","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561716977","title":"天然美容法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.98,"price":6.98,"shippingFee":4,"differencePrice":-10.98,"GoodsUrl":"https://book.kongfz.com/787407/7457083905","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beedbcfc/e65d9aa20e1a0495_b.jpg","GoodsImgCount":"5","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513177245","title":"原生家庭创伤和疗愈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.49,"price":3.49,"shippingFee":5,"differencePrice":-8.49,"GoodsUrl":"https://book.kongfz.com/716746/8530263030","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccaeaddb/d3877c98415ad8ec_b.jpg","GoodsImgCount":"1","onSaleCount":94,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549622993","title":"七种武器 2 碧玉九 多情环 古龙 文汇出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.65,"price":8.65,"shippingFee":4,"differencePrice":-12.65,"GoodsUrl":"https://book.kongfz.com/878042/8892052988","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebfebeff/ee8c98cacf018c9f_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516123911","title":"正学 第1辑 程水金 主编中国社会科学出版社9787516123911","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.3,"price":6.3,"shippingFee":0,"differencePrice":-6.3,"GoodsUrl":"https://book.kongfz.com/248516/8445608487","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/5695f680954765b6_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541541247","title":"白话资治通鉴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.08,"price":4.48,"shippingFee":1.6,"differencePrice":-6.08,"GoodsUrl":"https://book.kongfz.com/457799/8458628865","imgBigUrl":"https://www0.kfzimg.com/G06/M00/DB/5D/p4YBAFqYz9yAHTnOAADftrtdLbw543_b.jpg","GoodsImgCount":"1","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547908471","title":"《增广贤文》行楷硬笔字帖","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.19,"price":18.19,"shippingFee":0,"differencePrice":-18.19,"GoodsUrl":"https://book.kongfz.com/792228/8894526011","imgBigUrl":"https://www0.kfzimg.com/G06/M00/5B/8A/p4YBAFqcjB6AXbWlAACxpMJRAxM805_b.jpg","GoodsImgCount":"1","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806051467","title":"中国当代散文精品大观","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.7,"price":5.7,"shippingFee":5,"differencePrice":-10.7,"GoodsUrl":"https://book.kongfz.com/1207201/8732056718","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fadbdafc/d7ca7a014dc6ecd4_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229011628","title":"数字X线成像技术操作规范与剂量优化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.5,"price":14.5,"shippingFee":2,"differencePrice":-16.5,"GoodsUrl":"https://book.kongfz.com/181222/7301030202","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21084698/936f69f883c7f63f_b.jpg","GoodsImgCount":"1","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030438393","title":"原子物理与量子力学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":19,"shippingFee":6,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/219170/8854670030","imgBigUrl":"https://www0.kfzimg.com/G06/M00/0B/61/p4YBAFqZ--OAGdjqAACto8Azpr0414_b.jpg","GoodsImgCount":"1","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535110008","title":"楚辞文化背景研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/257645/8385818159","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eecbadab/53120eaadf8ddada_b.jpg","GoodsImgCount":"13","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559632340","title":"火:鲁米抒情诗","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.8,"price":14,"shippingFee":5.8,"differencePrice":-19.8,"GoodsUrl":"https://book.kongfz.com/1184610/8732818645","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fefffcdc/ef95dd5ef39a5110_b.jpg","GoodsImgCount":"1","onSaleCount":155,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807592501","title":"孔子家语插图本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.859999999999999,"price":0.06,"shippingFee":4.8,"differencePrice":-4.859999999999999,"GoodsUrl":"https://book.kongfz.com/245306/8519611266","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fedfadef/9ceb5bc75d4c177d_b.jpg","GoodsImgCount":"1","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020131617","title":"弹吧 莫扎特 弹吧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":6.1,"shippingFee":5.6,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/1151143/8891642184","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/debdabbc/1d8c6f57855cbebb_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567530416","title":"大夏书系·我的教育信条","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":3,"shippingFee":7,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/251066/6314429244","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dddbfebd/e08eb5004a5a2688_b.jpg","GoodsImgCount":"6","onSaleCount":149,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508698144","title":"认知尺度","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.14,"price":6.54,"shippingFee":1.6,"differencePrice":-8.14,"GoodsUrl":"https://book.kongfz.com/457799/8340498745","imgBigUrl":"https://www0.kfzimg.com/G07/M00/5D/39/qoYBAFxtK26AJQSTAAEIhLXCEPk917_b.jpg","GoodsImgCount":"1","onSaleCount":168,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108056115","title":"蔡澜作品自选集9:一缕余香","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.76,"price":17.76,"shippingFee":5,"differencePrice":-22.76,"GoodsUrl":"https://book.kongfz.com/640398/8325606114","imgBigUrl":"https://www0.kfzimg.com/G06/M00/92/9B/p4YBAFqeNLeATHCWAACUTSWV7sA518_b.jpg","GoodsImgCount":"1","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534084669","title":"自怡书迹(篆书卷)/黄宾虹书法集粹","quality":0,"qualityText":"","originalPrice":0,"totalPrice":300,"price":290,"shippingFee":10,"differencePrice":-300,"GoodsUrl":"https://book.kongfz.com/668742/7408798391","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eccfdcab/c60bd3db8bb088c3_b.jpg","GoodsImgCount":"1","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500083498","title":"亚洲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.58,"price":23.58,"shippingFee":0,"differencePrice":-23.58,"GoodsUrl":"https://book.kongfz.com/492548/8866390914","imgBigUrl":"https://www0.kfzimg.com/G06/M00/83/39/p4YBAFsp0mWAAVA_AAF056wk3DA841_b.jpg","GoodsImgCount":"1","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787210115472","title":"锁定高端:中小企业的出路【正版 塑封 发货快】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":62.8,"price":52.8,"shippingFee":10,"differencePrice":-62.8,"GoodsUrl":"https://book.kongfz.com/891652/8701830203","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebbfacbc/3f994e3345e47706_b.jpg","GoodsImgCount":"5","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301188378","title":"我要做个好家长:家庭教育的核心理念和操作方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.68,"price":4.68,"shippingFee":0,"differencePrice":-4.68,"GoodsUrl":"https://book.kongfz.com/840504/8515494439","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfdbaebd/c66372e6c229f47e_b.jpg","GoodsImgCount":"8","onSaleCount":101,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550623736","title":"子海精华编:四存编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":11,"shippingFee":5,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/737771/8807102818","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F6/AD/p4YBAFqyPJaAVf3fAABnbpaPYeo653_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539670140","title":"一念永恒6 耳根 安徽文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35.67,"price":30.67,"shippingFee":5,"differencePrice":-35.67,"GoodsUrl":"https://book.kongfz.com/878060/8899600389","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbabfcbb/b37d38ca1a66ebf0_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509716229","title":"社会学之思","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.5,"price":12.5,"shippingFee":6,"differencePrice":-18.5,"GoodsUrl":"https://book.kongfz.com/770286/8333236126","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeefbcb/2d1619b6ae1c99c7_b.jpg","GoodsImgCount":"10","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800735912","title":"最大化你的自尊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.88,"price":4.38,"shippingFee":3.5,"differencePrice":-7.88,"GoodsUrl":"https://book.kongfz.com/819139/8780150484","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbcbafcf/16ff682d72d85325_b.jpg","GoodsImgCount":"5","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117117968","title":"一病一页速成系列·症状与体征(翻译版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":30,"shippingFee":5,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/244916/7672342792","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcbafce/36e348e3b2781add_b.jpg","GoodsImgCount":"5","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503419843","title":"国民党将领谈国共大决战:战场较量","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.16,"price":8.66,"shippingFee":1.5,"differencePrice":-10.16,"GoodsUrl":"https://book.kongfz.com/774690/8698048698","imgBigUrl":"https://www0.kfzimg.com/G06/M00/90/C0/p4YBAFqnIWGAZPmWAACgYFH2BdA325_b.jpg","GoodsImgCount":"1","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535437822","title":"谈美书简:大家文论经典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.89,"price":0.09,"shippingFee":4.8,"differencePrice":-4.89,"GoodsUrl":"https://book.kongfz.com/780405/7794576703","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bebffdbd/621954b1d9ca687b_b.jpg","GoodsImgCount":"4","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511708991","title":"光明大手印:实修心髓(下卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/271386/8128810121","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdeefdfc/812225588f075059_b.jpg","GoodsImgCount":"6","onSaleCount":172,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512516236","title":"等我·遇繁","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.2,"price":8.2,"shippingFee":2,"differencePrice":-10.2,"GoodsUrl":"https://book.kongfz.com/545601/8868078177","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdedecc/1f05c7eabb2dae12_b.jpg","GoodsImgCount":"2","onSaleCount":255,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501255726","title":"与爱有关 1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.779999999999999,"price":3.28,"shippingFee":1.5,"differencePrice":-4.779999999999999,"GoodsUrl":"https://book.kongfz.com/772556/8042035571","imgBigUrl":"https://www0.kfzimg.com/G06/M00/37/61/p4YBAFqbSJeAI6TRAAC8PL7kUTA655_b.jpg","GoodsImgCount":"1","onSaleCount":125,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806845394","title":"第三届全国会计知识大赛法规汇编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2.5,"shippingFee":4.5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/285622/5472130653","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfaccbbc/877daef6e53689dc_b.jpg","GoodsImgCount":"3","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545823349","title":"中国城市轨道交通年鉴2023","quality":0,"qualityText":"","originalPrice":0,"totalPrice":88,"price":80,"shippingFee":8,"differencePrice":-88,"GoodsUrl":"https://book.kongfz.com/15878/8635018981","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdbbefdf/7203761aa85bddbe_b.jpg","GoodsImgCount":"7","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520206716","title":"故宫里的大怪兽 木之精灵","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":0.5,"shippingFee":4.5,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/531994/8811950065","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daddabbc/19753635be32a51a_b.jpg","GoodsImgCount":"1","onSaleCount":176,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806960325","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515307497","title":"结构与明暗 素描几何形体单体训练","quality":0,"qualityText":"","originalPrice":0,"totalPrice":60,"price":50,"shippingFee":10,"differencePrice":-60,"GoodsUrl":"https://book.kongfz.com/28297/8404195016","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aacefaab/a69030f0b920a813_b.jpg","GoodsImgCount":"4","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113253271","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539169903","title":"怪杰佐罗力之魔法师的弟子","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":4.4,"shippingFee":2.5,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/782278/8853393863","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdcecfc/7a4f8f77be4872f0_b.jpg","GoodsImgCount":"4","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505411937","title":"东风破","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.65,"price":2.25,"shippingFee":2.4,"differencePrice":-4.65,"GoodsUrl":"https://book.kongfz.com/692223/8848001982","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeabbada/18d4a6e00b5282e5_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540776886","title":"极简黄河史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.899999999999999,"price":5.3,"shippingFee":5.6,"differencePrice":-10.899999999999999,"GoodsUrl":"https://book.kongfz.com/1151143/8749172406","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbfaddcc/1c4188e8273e071e_b.jpg","GoodsImgCount":"2","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801432322","title":"中国的危机 下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.7,"price":0.7,"shippingFee":5,"differencePrice":-5.7,"GoodsUrl":"https://book.kongfz.com/1207201/8732160973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bffaacfd/55b5e6a712210d46_b.jpg","GoodsImgCount":"1","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522511986","title":"心知肚明9787522511986","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.32,"price":26.32,"shippingFee":4,"differencePrice":-30.32,"GoodsUrl":"https://book.kongfz.com/655396/8896033621","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9868355/0c51063e3a790f70_b.jpg","GoodsImgCount":"1","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508668680","title":"理性的非理性:人人都需要的十堂营销心理课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":10.2,"shippingFee":4.8,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/22176/8708259911","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F1/A6/p4YBAFqZN7eAT8t7AADm2HMJsK8866_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545428117","title":"《市场赢家生存智慧》丛书·高级波段交易:预期、确认、交易期货市场波段的交易策略","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40,"price":35,"shippingFee":5,"differencePrice":-40,"GoodsUrl":"https://book.kongfz.com/806881/8791937670","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdeafbbd/4a7a74100aaf4936_b.jpg","GoodsImgCount":"9","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532757060","title":"培根随笔全集培根","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":7,"shippingFee":0,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/576646/8248968682","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faeebaaf/5aedb15807c176ce_b.jpg","GoodsImgCount":"1","onSaleCount":89,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507322910","title":"中国“三农”问题研究(下)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.9,"price":14,"shippingFee":7.9,"differencePrice":-21.9,"GoodsUrl":"https://book.kongfz.com/266593/8514771412","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edefdaad/eefd5c7965a65e96_b.jpg","GoodsImgCount":"1","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806456095","title":"旋风再起林志颖","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.990000000000002,"price":13.99,"shippingFee":3,"differencePrice":-16.990000000000002,"GoodsUrl":"https://book.kongfz.com/525062/7952933376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffccdbfb/d89b4ebf5e73be91_b.jpg","GoodsImgCount":"4","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519882723","title":"综合能源服务百家实践案例集(2023年版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":95,"price":88,"shippingFee":7,"differencePrice":-95,"GoodsUrl":"https://book.kongfz.com/363535/8017764796","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efbbfadc/fb12de80869054a3_b.jpg","GoodsImgCount":"3","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514367324","title":"【正版二手,当日发货,所见即所得】直指生命的真相","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25.5,"price":15.5,"shippingFee":10,"differencePrice":-25.5,"GoodsUrl":"https://book.kongfz.com/314591/8873898618","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbaeadba/ce7c89c2b3d883b0_b.jpg","GoodsImgCount":"2","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561367186","title":"道德经的奥秘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/327097/8898096706","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daededeb/4052728ffcad3402_b.jpg","GoodsImgCount":"11","onSaleCount":261,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020033232","title":"人有病 :一九四九年后中国文坛纪实","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":2,"shippingFee":15,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/702376/8574002491","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdcbfbed/8f994a0ce4511fd7_b.jpg","GoodsImgCount":"9","onSaleCount":146,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546343815","title":"鲁迅经典文集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":1,"shippingFee":3,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/832065/8677403155","imgBigUrl":"https://www0.kfzimg.com/G06/M00/8F/2B/p4YBAFrJk8GAcBv1AAD2D_aSEjw105_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302611257","title":"趣味数学300题","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.34,"price":23.14,"shippingFee":3.2,"differencePrice":-26.34,"GoodsUrl":"https://book.kongfz.com/739740/8455964241","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabaadee/c56a8a360873d9bf_b.jpg","GoodsImgCount":"4","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515341132","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556073115","title":"李毓佩数学故事智斗系列·数学小子杜鲁克","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.54,"price":6.54,"shippingFee":0,"differencePrice":-6.54,"GoodsUrl":"https://book.kongfz.com/196857/8660963953","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E2/9B/p4YBAFskolqAGC7PAAD-YhhDpOQ512_b.jpg","GoodsImgCount":"1","onSaleCount":99,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805926230","title":"心香泪酒祭吴宓","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.4,"price":2.4,"shippingFee":5,"differencePrice":-7.4,"GoodsUrl":"https://book.kongfz.com/1207077/8774008733","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bceafceb/e6e84c0a6968bedb_b.jpg","GoodsImgCount":"1","onSaleCount":167,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513919159","title":"万物简史 布森特 民主与建设出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.1,"price":2.1,"shippingFee":5,"differencePrice":-7.1,"GoodsUrl":"https://book.kongfz.com/180897/8769178321","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdabbaee/25c282fef18ab380_b.jpg","GoodsImgCount":"1","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787107274169","title":"数学 八年级下 教师教学用书 9787107274169","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.8,"price":6.3,"shippingFee":4.5,"differencePrice":-10.8,"GoodsUrl":"https://book.kongfz.com/1121890/8881703556","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcabafca/a28f75df568c2578_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534607820","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534237003","title":"童年的云彩——冰心儿童文学新作奖获奖作者丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3100000000000005,"price":1.42,"shippingFee":2.89,"differencePrice":-4.3100000000000005,"GoodsUrl":"https://book.kongfz.com/826403/8655659602","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fefdbaec/0ac8ce22befd9b77_b.jpg","GoodsImgCount":"2","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807256465","title":"交通银行史画 中英文本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36,"price":31,"shippingFee":5,"differencePrice":-36,"GoodsUrl":"https://book.kongfz.com/766980/8311121800","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eecbbcfc/36be02eef1c632ec_b.jpg","GoodsImgCount":"1","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546122649","title":"中国文化源与流X-GM","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":7.2,"shippingFee":4.5,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/473622/8709248209","imgBigUrl":"https://www0.kfzimg.com/G06/M00/17/08/p4YBAFsYv3KASa21AAB3m2dwVTA494_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535657886","title":"绯弹的亚里亚.3.蜂蜜色陷阱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.5,"price":12.9,"shippingFee":1.6,"differencePrice":-14.5,"GoodsUrl":"https://book.kongfz.com/464363/8082360131","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1303/f3ae13fed07610a2_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516100158","title":"当代中国简帛学研究:1949-2009","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.6,"price":13.6,"shippingFee":5,"differencePrice":-18.6,"GoodsUrl":"https://book.kongfz.com/285265/8420474812","imgBigUrl":"https://www0.kfzimg.com/G06/M00/09/94/p4YBAFqiQTqAfU-fAAB8biLxNVg251_b.jpg","GoodsImgCount":"0","onSaleCount":89,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562153719","title":"数字媒体艺术设计概论谢成开西南师范大学出版社9787562153719","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.98,"price":3.98,"shippingFee":0,"differencePrice":-3.98,"GoodsUrl":"https://book.kongfz.com/366030/8389757114","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/ab8853cb8613e942_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507744088","title":"中医儿科杂病调治 临床验案心得","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.4,"price":8.4,"shippingFee":5,"differencePrice":-13.4,"GoodsUrl":"https://book.kongfz.com/1146983/8731284798","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccabaeea/bec4a3f3ca202604_b.jpg","GoodsImgCount":"1","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562491927","title":"焦虑症和恐惧症:一种认知的观点","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/722553/8053935000","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbbbefb/06a98a8307a77647_b.jpg","GoodsImgCount":"10","onSaleCount":113,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787215063983","title":"人学的科学之路","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":38,"shippingFee":10,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/677747/5525845992","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebefffaa/2aae35f9a9c3c119_b.jpg","GoodsImgCount":"3","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540736590","title":"《发货快》冰心作品精编 冰心 著,卓如 选编 漓江出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.29,"price":4.29,"shippingFee":0,"differencePrice":-4.29,"GoodsUrl":"https://book.kongfz.com/156492/8477626078","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4362605/2b017963221ae54e_b.jpg","GoodsImgCount":"1","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559602589","title":"*超脑/团灭","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.8,"price":11.9,"shippingFee":3.9,"differencePrice":-15.8,"GoodsUrl":"https://book.kongfz.com/622913/8781293258","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1C/A7/p4YBAFqaPyaASO8OAADjaotTI2g047_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509209028","title":"节能技术(一)(二)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.04,"price":3.04,"shippingFee":5,"differencePrice":-8.04,"GoodsUrl":"https://book.kongfz.com/821188/8009266743","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcbddaa/4441735d2fc83d12_b.jpg","GoodsImgCount":"4","onSaleCount":53,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787557614034","title":"糖尿病调养三部曲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.93,"price":5.93,"shippingFee":3,"differencePrice":-8.93,"GoodsUrl":"https://book.kongfz.com/364423/8154767176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11281955/b1d32f99f88a512f_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807429777","title":"黄庭禅","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40,"price":33,"shippingFee":7,"differencePrice":-40,"GoodsUrl":"https://book.kongfz.com/251066/8876471272","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbbcafe/cc28a29941eab7d3_b.jpg","GoodsImgCount":"8","onSaleCount":74,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111385479","title":"管理者每天读点韩非子","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.4,"price":14.4,"shippingFee":5,"differencePrice":-19.4,"GoodsUrl":"https://book.kongfz.com/1207201/8642575748","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edfbaeff/3799b38ac41be0c2_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787313270368","title":"初中英语语法专练 大字版 知识点梳理 全国 中学英语专练百分百","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.11,"price":12.61,"shippingFee":1.5,"differencePrice":-14.11,"GoodsUrl":"https://book.kongfz.com/772556/7933482079","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10317333/28422663cee46d73_b.jpg","GoodsImgCount":"1","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121357961","title":"HTML+CSS+JavaScript编程从入门到精通 html5+css3基础自学教程web前端开发 网站网页前端设计制作建设","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":3.8,"shippingFee":0,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/590687/8602236711","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/578/6f71cebe6e2fe3c2_b.jpg","GoodsImgCount":"1","onSaleCount":149,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553646091","title":"新东方 直通托福基础教程 写作教育科技集团美国本科考试研究院浙江教育出版社9787553646091","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3,"price":4.3,"shippingFee":0,"differencePrice":-4.3,"GoodsUrl":"https://book.kongfz.com/248516/8440860798","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/7c0909d9fac80f7c_b.jpg","GoodsImgCount":"1","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519777418","title":"国家公诉人出庭指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":107.9,"price":99.9,"shippingFee":8,"differencePrice":-107.9,"GoodsUrl":"https://book.kongfz.com/218476/8455920813","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcbfaae/2f5ea8d721d8f099_b.jpg","GoodsImgCount":"8","onSaleCount":97,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535396464","title":"赛尔号精灵传说第二季5女神的愤怒","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.2,"price":1.2,"shippingFee":3,"differencePrice":-4.2,"GoodsUrl":"https://book.kongfz.com/902124/8232461903","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abacdfca/24cae20760f51e8c_b.jpg","GoodsImgCount":"4","onSaleCount":128,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508251738","title":"跌打损伤偏方验方疗法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":11,"shippingFee":9,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/879205/8386867884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadcbdeb/d46616aff116f328_b.jpg","GoodsImgCount":"4","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810971843","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539673882","title":"诡秘之主 10","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36,"price":30,"shippingFee":6,"differencePrice":-36,"GoodsUrl":"https://book.kongfz.com/738944/8666813116","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebebefcf/5b8c2f0af154a990_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550217454","title":"上帝掷骰子吗?:量子物理史话","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/522252/8881101832","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcedbffe/3bc31a21a55e85fe_b.jpg","GoodsImgCount":"10","onSaleCount":535,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533196677","title":"颞下颌关节外科手术图谱【未开封】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":40,"shippingFee":8,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/20113/8708722394","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2368075/5cc59fca61418e15_b.jpg","GoodsImgCount":"6","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545581447","title":"特工小品 小品绘著 天地出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.6,"price":3.6,"shippingFee":4,"differencePrice":-7.6,"GoodsUrl":"https://book.kongfz.com/878042/8780122369","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aabdbfaf/4c6e809d5f8ac283_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520717281","title":"基层中国:国家治理的基石","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":8,"shippingFee":8,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/836297/8270087899","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecbffbbb/e7eba40da48936ea_b.jpg","GoodsImgCount":"5","onSaleCount":221,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503971549","title":"流动的博物馆李德庚9787503971549文化艺术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.6,"price":34.1,"shippingFee":5.5,"differencePrice":-39.6,"GoodsUrl":"https://book.kongfz.com/405080/7310559973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddbfdca/ddfaa51954478712_b.jpg","GoodsImgCount":"1","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301233009","title":"中外物理学精品书系·前沿系列:从抛物线谈起(混沌动力学引论)(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/785604/8009702581","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eefaffee/c4ebf23f89793c3e_b.jpg","GoodsImgCount":"9","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040150780","title":"高中新课程老师教育系列教材:高中音乐新课程教学论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39,"price":30,"shippingFee":9,"differencePrice":-39,"GoodsUrl":"https://book.kongfz.com/233641/6012616143","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdcedcd/c986845d3a146f0c_b.jpg","GoodsImgCount":"18","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508229942","title":"偏方验方治病丛书:胃病偏方验方疗法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/10563/4619429987","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbebdbef/fde06ecabc17f303_b.jpg","GoodsImgCount":"4","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802282452","title":"寒武纪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.4,"price":0.4,"shippingFee":3,"differencePrice":-3.4,"GoodsUrl":"https://book.kongfz.com/884527/8123402741","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfcebaeb/45e505eaf81204fa_b.jpg","GoodsImgCount":"4","onSaleCount":295,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501170388","title":"42部文学名著导读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":3.1,"shippingFee":5,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/700512/8535927223","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbcfbba/7b00d27ca9cbaa29_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516641590","title":"电信诈骗话语模式解读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":12,"shippingFee":5,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/758933/8311513802","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbdaabbc/85b378309fc2d5cf_b.jpg","GoodsImgCount":"2","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508679327","title":"会动的立体小汽车 超级工程车","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.03,"price":15.23,"shippingFee":2.8,"differencePrice":-18.03,"GoodsUrl":"https://book.kongfz.com/1093663/8881837238","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aedffeab/2fc4c6c70426a7cc_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302451402","title":"四川重庆古建筑地图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":132,"price":124,"shippingFee":8,"differencePrice":-132,"GoodsUrl":"https://book.kongfz.com/750186/6510117695","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accbaafc/7966d331b607474d_b.jpg","GoodsImgCount":"2","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560078403","title":"韩国语基础教程4 学生用书韩国西江大学韩国语教育院 著外语教学与研究出版社9787560078403","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.88,"price":4.88,"shippingFee":0,"differencePrice":-4.88,"GoodsUrl":"https://book.kongfz.com/366030/8432554732","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/8c0716368a76c0e7_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802551268","title":"财务报表就像一本故事书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/3092/8441875353","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbafffed/53bad65e508c1600_b.jpg","GoodsImgCount":"5","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564345402","title":"铁路线路与站场","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.9,"price":20.9,"shippingFee":9,"differencePrice":-29.9,"GoodsUrl":"https://book.kongfz.com/900492/8399542894","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23095665/8f6596c31f51ae90_b.jpg","GoodsImgCount":"1","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802543416","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562476443","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513330251","title":"变色龙马克斯","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.52,"price":3.52,"shippingFee":5,"differencePrice":-8.52,"GoodsUrl":"https://book.kongfz.com/716746/8573685578","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efcbddac/009ecce6718456e3_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101115253","title":"古钱极品/中国钱币丛书乙种本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":32,"shippingFee":11,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/23380/8891015518","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaadefed/cc33c8659337be72_b.jpg","GoodsImgCount":"6","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531327493","title":"我恋爱 我容易吗 二手书实拍图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.27,"price":1.77,"shippingFee":5.5,"differencePrice":-7.27,"GoodsUrl":"https://book.kongfz.com/898097/8767090319","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcafceed/ae1ea8b5b115d524_b.jpg","GoodsImgCount":"2","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539198675","title":"我要炼出黄金","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.61,"price":0.11,"shippingFee":2.5,"differencePrice":-2.61,"GoodsUrl":"https://book.kongfz.com/903233/8497337794","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbaedeaf/04d5fa349cc307a6_b.jpg","GoodsImgCount":"7","onSaleCount":405,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117333016","title":"颞下颌关节紊乱病临床诊疗解析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":86.4,"price":77,"shippingFee":9.4,"differencePrice":-86.4,"GoodsUrl":"https://book.kongfz.com/755104/8486452382","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdbcdef/cd8b52f5f18d0870_b.jpg","GoodsImgCount":"11","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533547981","title":"传世中医秘方","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":9,"shippingFee":3,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/566350/8858398045","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edcddbdb/e499acd32b9e1737_b.jpg","GoodsImgCount":"12","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547277898","title":"谭延闿临麻姑仙坛记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":47.35,"price":41.35,"shippingFee":6,"differencePrice":-47.35,"GoodsUrl":"https://book.kongfz.com/533712/7445542462","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdacdfcc/747808d442d68dbd_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122168108","title":"伟大的声音 演讲的力量 高温消毒发货 俞敏洪编 化学工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.199999999999996,"price":35.4,"shippingFee":1.8,"differencePrice":-37.199999999999996,"GoodsUrl":"https://book.kongfz.com/110/8696450340","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffdfacdf/23cd709fa1189c02_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565834691","title":"做最好的自己【全新】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.5,"price":0.5,"shippingFee":3,"differencePrice":-3.5,"GoodsUrl":"https://book.kongfz.com/241879/8585409526","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9187761/e00b22696eefd681_b.jpg","GoodsImgCount":"1","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115558534","title":"我的世界 年鉴2021","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":10,"shippingFee":7,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/696405/6634553010","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afccacdb/d9bfc72e1eb7dc88_b.jpg","GoodsImgCount":"10","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122185471","title":"电子电工技术全图解全集:PLC技术·变频技术速成全图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/760233/6672966429","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfcccaa/b1d730a43c135807_b.jpg","GoodsImgCount":"5","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800471193","title":"紫禁城的黄昏","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":10,"shippingFee":9,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/17163/6977347845","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afedfdcf/0e2cef314cfd9a14_b.jpg","GoodsImgCount":"3","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787574108943","title":"中国古代服饰结构图集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.5,"price":34.5,"shippingFee":7,"differencePrice":-41.5,"GoodsUrl":"https://book.kongfz.com/633822/8836490919","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5126996/a3aa257bc59f9af3_b.jpg","GoodsImgCount":"1","onSaleCount":168,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531004691","title":"邓散木印集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/189253/924912293","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1E/7D/p4YBAFsmYxmAEyJlAAKI5tlWFsM222_b.jpg","GoodsImgCount":"6","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500060833","title":"华罗庚学校初中物理试题解析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/690706/8016636203","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfcaabfb/9f3293f6168eadfd_b.jpg","GoodsImgCount":"10","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539753775","title":"北极熊王:中外动物小说精品","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/437976/8801246014","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbbdecbc/3ca925e159754de4_b.jpg","GoodsImgCount":"2","onSaleCount":140,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547722091","title":"地道英文写作进阶:外刊实用短语句型精选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":57,"price":57,"shippingFee":0,"differencePrice":-57,"GoodsUrl":"https://book.kongfz.com/356195/8896018285","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/c3ee7195f7455908_b.jpg","GoodsImgCount":"6","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302165309","title":"电子商务网站建设实验指导","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.93,"price":13.93,"shippingFee":10,"differencePrice":-23.93,"GoodsUrl":"https://book.kongfz.com/885269/8596565983","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D6/B2/p4YBAFqYvI-ADYiFAAC7RDvbnYE984_b.jpg","GoodsImgCount":"1","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538899429","title":"家有小学生的营养早餐","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.28,"price":0.5,"shippingFee":2.78,"differencePrice":-3.28,"GoodsUrl":"https://book.kongfz.com/785333/8671961291","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdacedec/7f7eb8b6035a3c34_b.jpg","GoodsImgCount":"1","onSaleCount":439,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010086798","title":"家庭文化学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/462357/8563912467","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbebcedf/9544c30b47cda303_b.jpg","GoodsImgCount":"11","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806862339","title":"大画幅摄影","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.85,"price":7.35,"shippingFee":1.5,"differencePrice":-8.85,"GoodsUrl":"https://book.kongfz.com/701775/8774482003","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfdbeabb/07a9faf8ce7aaefc_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572501159","title":"儿童和青少年普拉提 英 切莱斯特 科里 索菲奇 Celeste Corey Zopich 布雷特 霍华德 Brett Howard 道恩玛丽 伊克斯 Dawn Marie Ickes 主编 河南科学技术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.65,"price":15.65,"shippingFee":5,"differencePrice":-20.65,"GoodsUrl":"https://book.kongfz.com/903313/8867129101","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbaecdae/9a66480f20211491_b.jpg","GoodsImgCount":"1","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514222944","title":"洞见 赵昂 文化发展出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.4,"price":1.4,"shippingFee":5,"differencePrice":-6.4,"GoodsUrl":"https://book.kongfz.com/398369/8756316997","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abebbffb/38c9650f51d3487e_b.jpg","GoodsImgCount":"1","onSaleCount":146,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117263764","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787119079493","title":"吃喝玩乐超实用英语会话一本通 希伯伦股份有限公司编 外文出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":4.8,"shippingFee":5,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/180897/8441994084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afffeeaa/477bc761e5ae81c2_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502615178","title":"百战狐狸:职业机构实战操盘讲义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.77,"price":1.27,"shippingFee":5.5,"differencePrice":-6.77,"GoodsUrl":"https://book.kongfz.com/250120/8708646976","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dabebaeb/c9eea535bcbe11db_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561126028","title":"高等学校理工科物理类规划教材:量子力学(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":13,"shippingFee":7,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/217161/6851259518","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbceffdb/21857aa37ee9847a_b.jpg","GoodsImgCount":"4","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787554174623","title":"初一预习视频课英语","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9799999999999995,"price":4.18,"shippingFee":3.8,"differencePrice":-7.9799999999999995,"GoodsUrl":"https://book.kongfz.com/237705/8613570433","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafdfaeb/241850ced0e78c1a_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513533140","title":"英语. 二年级. 上册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.9899999999999998,"price":0.01,"shippingFee":2.98,"differencePrice":-2.9899999999999998,"GoodsUrl":"https://book.kongfz.com/840438/8166411046","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfafdbea/d633d70cee3e5f71_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121436604","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518440917","title":"读醉:宁夏酒庄指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":20,"shippingFee":0,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/10991/8852891015","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addfbadb/e166df1a5914a696_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514507799","title":"斗破苍穹(23)一版一印","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9,"price":0.9,"shippingFee":3,"differencePrice":-3.9,"GoodsUrl":"https://book.kongfz.com/668354/7024201760","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bacbcdcf/c0b24ea31449a10b_b.jpg","GoodsImgCount":"4","onSaleCount":243,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558902406","title":"不一样的圣诞节 达妮拉库洛特,方素珍 少年儿童出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":5.1,"shippingFee":3,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/521005/8337317394","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1B/43/p4YBAFqaO6-ADWX-AACLI7p96U4392_b.jpg","GoodsImgCount":"1","onSaleCount":117,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800420313","title":"难经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":65.9,"price":59.9,"shippingFee":6,"differencePrice":-65.9,"GoodsUrl":"https://book.kongfz.com/169274/8450740779","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbefdeb/17dce85a175b8604_b.jpg","GoodsImgCount":"4","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504747914","title":"王敬之讲田黄 9787504747914 王敬之 著 中国物资出版社 有疑问咨询客服","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.65,"price":12.65,"shippingFee":4,"differencePrice":-16.65,"GoodsUrl":"https://book.kongfz.com/790574/8853963934","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abbddeec/2595703d5b185aa7_b.jpg","GoodsImgCount":"1","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558911934","title":"海豚绘本花园:一家好认真好认真的餐厅","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.51,"price":10.91,"shippingFee":1.6,"differencePrice":-12.51,"GoodsUrl":"https://book.kongfz.com/470338/8091876352","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/16223501/d0ac2cf21ff67db3_b.jpg","GoodsImgCount":"0","onSaleCount":70,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121363634","title":"我超喜欢的趣味数学书 小学四年级 第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.59,"price":6.19,"shippingFee":2.4,"differencePrice":-8.59,"GoodsUrl":"https://book.kongfz.com/692223/8853556029","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adffadfd/7fc165d6fe4fbb20_b.jpg","GoodsImgCount":"1","onSaleCount":139,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509222133","title":"房地产企业全程会计核算与税务处理(第六版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":56,"price":50,"shippingFee":6,"differencePrice":-56,"GoodsUrl":"https://book.kongfz.com/520656/7331763806","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfcdfed/66caec80f6229f38_b.jpg","GoodsImgCount":"4","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510226991","title":"十大业务系列教材——职务犯罪检察业务","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":40,"shippingFee":8,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/584570/8436769476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdeafad/895dbfc10f7deb10_b.jpg","GoodsImgCount":"14","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810756075","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567597013","title":"大夏书系·教育的100种语言:丹麦教育见闻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.5,"price":10,"shippingFee":4.5,"differencePrice":-14.5,"GoodsUrl":"https://book.kongfz.com/585799/8333731294","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14917819/d342c68268bd6844_b.jpg","GoodsImgCount":"5","onSaleCount":90,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506749145","title":"医学衷中参西录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":50,"price":40,"shippingFee":10,"differencePrice":-50,"GoodsUrl":"https://book.kongfz.com/730822/8433255540","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/facdecbd/5cc0c5684378b427_b.jpg","GoodsImgCount":"5","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111288954","title":"供应链物流管理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.1,"price":4.1,"shippingFee":0,"differencePrice":-4.1,"GoodsUrl":"https://book.kongfz.com/733352/8279417108","imgBigUrl":"https://www0.kfzimg.com/G06/M00/58/FA/p4YBAFqcKLyANGCJAAErWD_1er4153_b.jpg","GoodsImgCount":"1","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214287892","title":"海外中国研究丛书·艺术系列 《中正之笔:颜真卿书法与宋代文人政治》赠包","quality":0,"qualityText":"","originalPrice":0,"totalPrice":60.08,"price":60.08,"shippingFee":0,"differencePrice":-60.08,"GoodsUrl":"https://book.kongfz.com/457799/8830585867","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/15505652/82c39efb161a5c45_b.jpg","GoodsImgCount":"1","onSaleCount":117,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501256730","title":"教育就是培养好习惯","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":1.3,"shippingFee":2,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/667558/8863965946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baadebdb/b72ce315488f2b9f_b.jpg","GoodsImgCount":"1","onSaleCount":431,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111326793","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540484958","title":"人类群星闪耀时","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.02,"price":5.42,"shippingFee":1.6,"differencePrice":-7.02,"GoodsUrl":"https://book.kongfz.com/457799/8321235881","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F7/BA/p4YBAFqhnLeANWRTAABg9lSn2Ks131_b.jpg","GoodsImgCount":"1","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556869824","title":"大中华寻宝系列26 新疆寻宝记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.5,"price":6.5,"shippingFee":5,"differencePrice":-11.5,"GoodsUrl":"https://book.kongfz.com/697065/8817518628","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdeffed/4edad2afd5490255_b.jpg","GoodsImgCount":"3","onSaleCount":193,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535429704","title":"少年天子 凌力著 长江文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.99,"price":4.99,"shippingFee":5,"differencePrice":-9.99,"GoodsUrl":"https://book.kongfz.com/1146983/8811740152","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcddced/5334a2f79e1bd2da_b.jpg","GoodsImgCount":"1","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532560868","title":"贾题韬讲坛经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/23153/8780563654","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/effabcae/0243a97a1d72ba14_b.jpg","GoodsImgCount":"15","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507535198","title":"暮色紫禁城 洋帝师眼中的溥仪与近代中国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.25,"price":2.85,"shippingFee":2.4,"differencePrice":-5.25,"GoodsUrl":"https://book.kongfz.com/692223/8222719769","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eabfeccd/807382cae33649cd_b.jpg","GoodsImgCount":"1","onSaleCount":175,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303086641","title":"说话的力量【封面几层书页有被顶破小洞】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":7,"shippingFee":7,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/211464/7174616446","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdceddbd/482a0066db3d5e28_b.jpg","GoodsImgCount":"9","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100034975","title":"美洲三书 扉页有水渍","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/12142/6630865417","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdedcae/cf96f3bd07d5c0df_b.jpg","GoodsImgCount":"7","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506449045","title":"开·合:纽扣拉链的连接艺术(书页干净无笔画。)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/273362/2564607312","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2593/022091c08a2390131d_b.jpg","GoodsImgCount":"4","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302364832","title":"国际物流黄新祥 等主编清华大学出版社9787302364832","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":0.5,"shippingFee":4,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/420387/8678386948","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/12298542/57d47de2dbc7168d_b.jpg","GoodsImgCount":"1","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302025207","title":"实用软件工程 第二版郑人杰等 编著清华大学出版社9787302025207","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.75,"price":3.75,"shippingFee":0,"differencePrice":-3.75,"GoodsUrl":"https://book.kongfz.com/366030/8275536127","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/e72b7e2e2cfde181_b.jpg","GoodsImgCount":"1","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208164208","title":"正版新书现货 宏观航运经济学 9787208164208 (希) 伊莱亚斯·卡拉基索斯, 兰布罗斯·瓦纳维兹著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31.26,"price":26.26,"shippingFee":5,"differencePrice":-31.26,"GoodsUrl":"https://book.kongfz.com/1181534/8500474938","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffaaddac/39f58d121b1b8db4_b.jpg","GoodsImgCount":"1","onSaleCount":67,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533951610","title":"吉姆:吉卜林作品(精装本)2018年1版1印","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.5,"price":25.5,"shippingFee":2,"differencePrice":-27.5,"GoodsUrl":"https://book.kongfz.com/1996/8650425365","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecedaeee/da61038dbe97ad9c_b.jpg","GoodsImgCount":"3","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801739261","title":"秦书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":50,"price":46,"shippingFee":4,"differencePrice":-50,"GoodsUrl":"https://book.kongfz.com/521036/8800425189","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbdafec/d093e26f8cc2c73f_b.jpg","GoodsImgCount":"8","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500690696","title":"边城","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.1,"price":4.1,"shippingFee":0,"differencePrice":-4.1,"GoodsUrl":"https://book.kongfz.com/880899/8678253491","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeedabd/1c5c446cb92761b3_b.jpg","GoodsImgCount":"2","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787570110940","title":"小学生叙事作文 思维导图作文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":1.5,"shippingFee":3,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/783956/8818428031","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffccbfba/91f578f8e6cdd416_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535295439","title":"张景中科普文集:漫话数学(精装典藏版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.84,"price":10.44,"shippingFee":4.4,"differencePrice":-14.84,"GoodsUrl":"https://book.kongfz.com/321650/8279680042","imgBigUrl":"https://www0.kfzimg.com/G06/M00/FE/71/p4YBAFqZclaARCtwAACby3byH0g317_b.jpg","GoodsImgCount":"1","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810462761","title":"大学英语精读-(3)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.14,"price":0.14,"shippingFee":3,"differencePrice":-3.14,"GoodsUrl":"https://book.kongfz.com/1092190/8867494474","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeefbab/adc884da026a2cc7_b.jpg","GoodsImgCount":"1","onSaleCount":257,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544678667","title":"大学英语基础口语教程 3(第2版)学生用书(附光盘)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.14,"price":26.14,"shippingFee":6,"differencePrice":-32.14,"GoodsUrl":"https://book.kongfz.com/444647/8628763673","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dffafdeb/aafce3d1f21adfff_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801567048","title":"中西医结合精神病学/新世纪全国高等医药院校规划教材","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31,"price":31,"shippingFee":0,"differencePrice":-31,"GoodsUrl":"https://book.kongfz.com/698100/8721476824","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceccdbbc/cad5c1ae98d17471_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787576049688","title":"奥数教程 六年级","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.17,"price":20.37,"shippingFee":3.8,"differencePrice":-24.17,"GoodsUrl":"https://book.kongfz.com/624030/8505456371","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4893319/c0ed3496e5c5bbb6_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805183671","title":"晚清小说史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":9,"shippingFee":10,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/179226/7693867371","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbdceed/20efe77062ee6a6f_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500909514","title":"中国武术人名辞典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37,"price":29,"shippingFee":8,"differencePrice":-37,"GoodsUrl":"https://book.kongfz.com/204356/7119094838","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdbdcadd/acc1900622c92670_b.jpg","GoodsImgCount":"7","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533003395","title":"武氏祠汉画像石","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":30,"shippingFee":13,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/24485/304549598","imgBigUrl":"https://www0.kfzimg.com/G03/M01/A0/E8/pYYBAFStYTyAK1C2AAElEuFY5XY899_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200120837","title":"大家小书 中国古代衣食住行","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":6,"shippingFee":4,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/20902/8727045221","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdbdccf/b167e6589d0bbda4_b.jpg","GoodsImgCount":"2","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564071028","title":"蒙台梭利早教方案:0-3岁智力及语言系统训练全书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8600000000000003,"price":1.86,"shippingFee":2,"differencePrice":-3.8600000000000003,"GoodsUrl":"https://book.kongfz.com/624177/8228419387","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadbfcaf/dd1d18ccaac06855_b.jpg","GoodsImgCount":"3","onSaleCount":540,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115602763","title":"孕期冥想心理课","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.04,"price":13.04,"shippingFee":2,"differencePrice":-15.04,"GoodsUrl":"https://book.kongfz.com/738826/8492472031","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbbfecda/4b467c05a7ff0e49_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787202025154","title":"河北通史 民国上卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.11,"price":13.11,"shippingFee":5,"differencePrice":-18.11,"GoodsUrl":"https://book.kongfz.com/1154627/8790091931","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafcfaad/346ccaf3ae2ecc3e_b.jpg","GoodsImgCount":"2","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117139618","title":"中药名方现代研究与应用·四物汤现代研究与应用","quality":0,"qualityText":"","originalPrice":0,"totalPrice":73.77,"price":69.27,"shippingFee":4.5,"differencePrice":-73.77,"GoodsUrl":"https://book.kongfz.com/792669/7996883998","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecacccb/cabb099d4ffa62eb_b.jpg","GoodsImgCount":"2","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200131475","title":"向解放军学习有效率组织的管理之道精编版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.14,"price":3.64,"shippingFee":4.5,"differencePrice":-8.14,"GoodsUrl":"https://book.kongfz.com/884575/8886801797","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdcabfd/c4649fe683ed4712_b.jpg","GoodsImgCount":"1","onSaleCount":335,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569912883","title":"雪球帮:为什么世界是今天这样的?","quality":0,"qualityText":"","originalPrice":0,"totalPrice":93,"price":90,"shippingFee":3,"differencePrice":-93,"GoodsUrl":"https://book.kongfz.com/889351/8359062152","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbeedbcc/46cba327d8dc3331_b.jpg","GoodsImgCount":"6","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801752093","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562622963","title":"大学军事教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.58,"price":0.59,"shippingFee":2.99,"differencePrice":-3.58,"GoodsUrl":"https://book.kongfz.com/784293/8214414858","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daacbdaf/63c3a8955499e0dd_b.jpg","GoodsImgCount":"5","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559617910","title":"和孩子一起去艺术博物馆","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":10,"shippingFee":10,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/265261/8694353313","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaebafae/e8ab83ffb9b4f994_b.jpg","GoodsImgCount":"7","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547260388","title":"全新小学生必背文言文注音版小学一二三四五六年级6-12岁语文教材必背文言文全集阅读小古文经典诵读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.99,"price":3.99,"shippingFee":0,"differencePrice":-3.99,"GoodsUrl":"https://book.kongfz.com/787255/8088016248","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1760/01588e892e1dfa98e4_b.jpg","GoodsImgCount":"1","onSaleCount":141,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502963460","title":"气象统计分析与预报方法(第4版)(首页有字迹)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/269417/7879872024","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdacbfe/4f1c6c5fe9e7ab60_b.jpg","GoodsImgCount":"5","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549850372","title":"意林18周年纪念书.B","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.89,"price":2.89,"shippingFee":0,"differencePrice":-2.89,"GoodsUrl":"https://book.kongfz.com/711444/8643457434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20517473/2b74e8a9e24dfb85_b.jpg","GoodsImgCount":"0","onSaleCount":507,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533643638","title":"魅力口才","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.05,"price":0.05,"shippingFee":5,"differencePrice":-5.05,"GoodsUrl":"https://book.kongfz.com/805022/8631298088","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbcaaac/3ebabf676af610eb_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807553274","title":"妖怪山","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.73,"price":3.23,"shippingFee":4.5,"differencePrice":-7.73,"GoodsUrl":"https://book.kongfz.com/765432/8854682434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbcccae/704257a20943f31f_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532137435","title":"静欲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1.5,"shippingFee":3.5,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/253683/8613551636","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6887408/5c50a923c692899b_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506545433","title":"古今中外心理战100例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":10,"shippingFee":7,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/20331/8181661495","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2868/0269943c229e5f365c_b.jpg","GoodsImgCount":"2","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121451928","title":"人人都能玩赚ChatGPT 高温消毒发货 黄小刀 电子工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.3,"price":2.5,"shippingFee":1.8,"differencePrice":-4.3,"GoodsUrl":"https://book.kongfz.com/259056/8887865046","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceaeddfd/444fd0181d292df1_b.jpg","GoodsImgCount":"1","onSaleCount":333,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201150321","title":"男孩故事 彩图注音有声版 笨笨狼童书坊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.1,"price":15.1,"shippingFee":5,"differencePrice":-20.1,"GoodsUrl":"https://book.kongfz.com/911923/8608024464","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecaccefc/d5a348a22b1aba4d_b.jpg","GoodsImgCount":"1","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115510907","title":"用图表说话如何简单有效地做数据分析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.8,"price":0.8,"shippingFee":5,"differencePrice":-5.8,"GoodsUrl":"https://book.kongfz.com/700512/8743345578","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebafedac/360e136d8247ad57_b.jpg","GoodsImgCount":"1","onSaleCount":119,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530638491","title":"现代西方历史的故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/6856/8690577625","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddddafae/afdd629a50acab25_b.jpg","GoodsImgCount":"14","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539990378","title":"虹口大爆炸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.48,"price":1.48,"shippingFee":5,"differencePrice":-6.48,"GoodsUrl":"https://book.kongfz.com/750161/8211811207","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fffaeced/9cd2a7b72eb0f4ac_b.jpg","GoodsImgCount":"1","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544542524","title":"从课本到奥数难题点拨 小学五年级 全新升级版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.7,"price":3.7,"shippingFee":3,"differencePrice":-6.7,"GoodsUrl":"https://book.kongfz.com/838443/8877688994","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdfddeb/3a9a15a02db2c2a7_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115477217","title":"足球战术与阵形图解:思路解说、案例分析及训练方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.5,"price":15,"shippingFee":5.5,"differencePrice":-20.5,"GoodsUrl":"https://book.kongfz.com/669776/8842681155","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbfdaca/86189842b664a053_b.jpg","GoodsImgCount":"3","onSaleCount":88,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530653180","title":"师陀散文选集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":1,"shippingFee":7,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/784196/8071376720","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbebaacf/387d7985239551bb_b.jpg","GoodsImgCount":"2","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030409836","title":"化学实验教学论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.16,"price":41.16,"shippingFee":0,"differencePrice":-41.16,"GoodsUrl":"https://book.kongfz.com/1120807/8901560862","imgBigUrl":"https://www0.kfzimg.com/G06/M00/57/62/p4YBAFqcDtqAYjz_AABOWff5Al4841_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806033494","title":"猫国春秋","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25.8,"price":20,"shippingFee":5.8,"differencePrice":-25.8,"GoodsUrl":"https://book.kongfz.com/914318/8378334053","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddbfdbf/f07a2f247617134c_b.jpg","GoodsImgCount":"2","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508534701","title":"超级梦想家像天才一样思考","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.05,"price":1.67,"shippingFee":5.38,"differencePrice":-7.05,"GoodsUrl":"https://book.kongfz.com/311927/8249147995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efffecaf/9f5fba8331161639_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530214008","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543231214","title":"吃掉情绪?——和食物的斗争","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":7,"shippingFee":6,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/22916/7541247337","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3008554/b610294fb1f49931_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521750393","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521300789","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509654163","title":"电力市场经济学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":71,"price":65,"shippingFee":6,"differencePrice":-71,"GoodsUrl":"https://book.kongfz.com/722278/8595373194","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edafadbf/7506fe39a352972e_b.jpg","GoodsImgCount":"7","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111321118","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213093449","title":"如何启动黄金圈思维","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53.49,"price":47.99,"shippingFee":5.5,"differencePrice":-53.49,"GoodsUrl":"https://book.kongfz.com/1153783/8871587942","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22135404/73612320da1a5cec_b.jpg","GoodsImgCount":"4","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806451427","title":"鲁迅书话","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.48,"price":19.98,"shippingFee":6.5,"differencePrice":-26.48,"GoodsUrl":"https://book.kongfz.com/18747/5221530317","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abecbfad/69d613574c951abc_b.jpg","GoodsImgCount":"13","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224140859","title":"现代文分类提升练·语文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.890000000000001,"price":3.89,"shippingFee":3,"differencePrice":-6.890000000000001,"GoodsUrl":"https://book.kongfz.com/771462/8574561248","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdbbead/c63a292e6fe6cc59_b.jpg","GoodsImgCount":"4","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550243576","title":"中华国学经典精粹·蒙学家训必读本:三字经·百家姓·千字文·弟子规","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.09,"price":1.09,"shippingFee":2,"differencePrice":-3.09,"GoodsUrl":"https://book.kongfz.com/624177/8743682753","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edccbabb/8141fa7ddeaca3c0_b.jpg","GoodsImgCount":"2","onSaleCount":764,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200030402","title":"苍生 华夏出版社编 北京出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":6.7,"shippingFee":5,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/398369/8618810522","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acabddfb/87e80f30013d13a0_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805937731","title":"二胡启蒙教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.46,"price":15.96,"shippingFee":3.5,"differencePrice":-19.46,"GoodsUrl":"https://book.kongfz.com/648701/8612669580","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C1/CE/p4YBAFqw4IGAHMeGAAECW5fmF94515_b.jpg","GoodsImgCount":"1","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537852838","title":"红楼梦—八十回回解精鉴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":148,"price":148,"shippingFee":0,"differencePrice":-148,"GoodsUrl":"https://book.kongfz.com/16743/7232736010","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdcebef/655584802429999d_b.jpg","GoodsImgCount":"1","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805191225","title":"金元明清词鉴赏辞典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":20,"shippingFee":9,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/883669/7889815425","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deaaefec/b7bf4814e6897207_b.jpg","GoodsImgCount":"6","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546358055","title":"美联储的秘密","quality":0,"qualityText":"","originalPrice":0,"totalPrice":60,"price":50,"shippingFee":10,"differencePrice":-60,"GoodsUrl":"https://book.kongfz.com/593893/8299743873","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eccffbbf/0b8db257b042f3e0_b.jpg","GoodsImgCount":"4","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300062372","title":"戴高乐书系:我的父亲戴高乐","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.5,"price":9.5,"shippingFee":8,"differencePrice":-17.5,"GoodsUrl":"https://book.kongfz.com/180278/8511632615","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccccaffe/e139d6f440938797_b.jpg","GoodsImgCount":"12","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556125227","title":"画知道答案","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.3,"price":6.3,"shippingFee":5,"differencePrice":-11.3,"GoodsUrl":"https://book.kongfz.com/893135/8473380609","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabefcfc/34f7142558ae9ce0_b.jpg","GoodsImgCount":"1","onSaleCount":153,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122135674","title":"正版二手 现代生物化学 第三版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.55,"price":13.55,"shippingFee":0,"differencePrice":-13.55,"GoodsUrl":"https://book.kongfz.com/745839/8780452119","imgBigUrl":"https://www0.kfzimg.com/G06/M00/CC/AF/p4YBAFqYnVSAGvflAAGZAQiLoGs040_b.jpg","GoodsImgCount":"0","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500168171","title":"极简元宇宙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.01,"price":2.01,"shippingFee":2,"differencePrice":-4.01,"GoodsUrl":"https://book.kongfz.com/755561/8129818306","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aeeaaefa/2ab5dd065e2dd348_b.jpg","GoodsImgCount":"2","onSaleCount":248,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549286348","title":"你哄我一下2 签名本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":3,"shippingFee":9,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/381029/8362454944","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddcbeadb/45eac4be85e7634e_b.jpg","GoodsImgCount":"7","onSaleCount":81,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532759095","title":"意大利风光","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":20,"shippingFee":9,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/638707/5528411427","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/17015971/bb54277e8cd73700_b.jpg","GoodsImgCount":"5","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513321174","title":"巴比伦时代","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.1,"price":9.1,"shippingFee":3,"differencePrice":-12.1,"GoodsUrl":"https://book.kongfz.com/808455/8886959658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbbcaeee/dfc8b85fc3bece6e_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807696001","title":"南烟以北","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.08,"price":0.08,"shippingFee":5,"differencePrice":-5.08,"GoodsUrl":"https://book.kongfz.com/878060/8738813937","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aeacadcc/9dbeb09260474062_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545801064","title":"浑家 拙荆 夫人 刘绍铭 上海书店出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":23,"shippingFee":5,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/878060/8575285157","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abaddfea/2da8202ac0a5e1a4_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513108577","title":"新世纪心理与心理健康教育文库9 人格心理学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.34,"price":4.34,"shippingFee":5,"differencePrice":-9.34,"GoodsUrl":"https://book.kongfz.com/23607/8458656434","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deecddbd/1c5a5efca63348db_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535917393","title":"广东茶点:[图集]","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":5,"shippingFee":4,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/769904/8539241272","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcccfcab/4cb012ab8cc45886_b.jpg","GoodsImgCount":"5","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810321556","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800504174","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540213169","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020110971","title":"普希金代表作上尉的女儿 俄 普希金著 磊然译 人民文学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.54,"price":6.54,"shippingFee":5,"differencePrice":-11.54,"GoodsUrl":"https://book.kongfz.com/672601/8830859922","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafebffc/0014b4a285f792dc_b.jpg","GoodsImgCount":"1","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544775854","title":"文学名著经典译林 欧也妮葛朗台 新版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.55,"price":2.55,"shippingFee":3,"differencePrice":-5.55,"GoodsUrl":"https://book.kongfz.com/1181761/8875292333","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbdadbf/1b838edc8ecf18b4_b.jpg","GoodsImgCount":"1","onSaleCount":174,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111523642","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301326640","title":"9787301326640 21世纪教师教育系列~ 外国高等教育史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34.07,"price":29.67,"shippingFee":4.4,"differencePrice":-34.07,"GoodsUrl":"https://book.kongfz.com/27495/8343052854","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4756272/1e6e8023f7617217_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301227671","title":"法律史译评","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.35,"price":15.35,"shippingFee":8,"differencePrice":-23.35,"GoodsUrl":"https://book.kongfz.com/820711/8391037776","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecbffba/bda90fee6c7c1436_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301209974","title":"理解美国:美国文化指南","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.6,"price":2.6,"shippingFee":3,"differencePrice":-5.6,"GoodsUrl":"https://book.kongfz.com/736627/8382555942","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadcbeda/860f249185e56c97_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503400490","title":"名僧录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":15,"shippingFee":5,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/398369/8195974665","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceabbfae/a43ce3e5787c2a5a_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301320327","title":"侠义三千年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":15,"shippingFee":0,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/419134/4596898069","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeedbec/96ecee234f4f480c_b.jpg","GoodsImgCount":"1","onSaleCount":135,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507514704","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113197445","title":"新手学开公司:创业融资常识","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1,"shippingFee":4,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/1210014/8842706502","imgBigUrl":"https://www0.kfzimg.com/G06/M00/04/EC/p4YBAFqZ55SAPmxSAADXtJjYMto864_b.jpg","GoodsImgCount":"1","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534247293","title":"史记故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.4,"price":4.4,"shippingFee":2,"differencePrice":-6.4,"GoodsUrl":"https://book.kongfz.com/667558/8898517027","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaecaffe/a6a58d3c0ae45e3d_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802113022","title":"人类与宗教","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53.2,"price":42,"shippingFee":11.2,"differencePrice":-53.2,"GoodsUrl":"https://book.kongfz.com/890580/8054767633","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decaefca/8f5bc4523bca53c2_b.jpg","GoodsImgCount":"6","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562858201","title":"中日跨文化交际实用教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.71,"price":3.71,"shippingFee":0,"differencePrice":-3.71,"GoodsUrl":"https://book.kongfz.com/892397/8511714742","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/206/24ff4c4e636a8af1_b.jpg","GoodsImgCount":"1","onSaleCount":162,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506007252","title":"十批判书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.95,"price":18.95,"shippingFee":2,"differencePrice":-20.95,"GoodsUrl":"https://book.kongfz.com/877749/8349858098","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/610ef12388c7aae3_b.jpg","GoodsImgCount":"3","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565107610","title":"幼儿园早期阅读资源. 幸福的种子 大班 导读手册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.8,"price":1.8,"shippingFee":3,"differencePrice":-4.8,"GoodsUrl":"https://book.kongfz.com/225395/6586000622","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabdbbce/277268d26c84ada2_b.jpg","GoodsImgCount":"6","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111607915","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100014205","title":"狄德罗传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/565102/7684520458","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afbfdeaf/49dfb3ffb3e393b9_b.jpg","GoodsImgCount":"9","onSaleCount":76,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532360437","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303113255","title":"伦理学经典著作选读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":52,"price":40,"shippingFee":12,"differencePrice":-52,"GoodsUrl":"https://book.kongfz.com/633074/5274343343","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeaeacae/eb4784a0715850e4_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535378569","title":"芭比小公主影院 芭比之公主学校 新版畅销版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9,"price":1.1,"shippingFee":2.8,"differencePrice":-3.9,"GoodsUrl":"https://book.kongfz.com/1093663/8697070175","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcbcecb/74f6ac0d15ec88fc_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567591547","title":"数学家画传·吴文俊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":10,"shippingFee":9,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/507602/7478663525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ababcabf/f04da9e185cf94d2_b.jpg","GoodsImgCount":"6","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500931003","title":":篮球运动教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.41,"price":3.41,"shippingFee":0,"differencePrice":-3.41,"GoodsUrl":"https://book.kongfz.com/20179/8594547518","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F2/CE/p4YBAFqZPEqAaXIFAAD8_GCgzIw699_b.jpg","GoodsImgCount":"1","onSaleCount":366,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521740196","title":"生命密码3:瘟疫传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":11,"shippingFee":6,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/624944/8895449656","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeeeddc/a0cdba4fddc59c7e_b.jpg","GoodsImgCount":"8","onSaleCount":283,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508235202","title":"职业技能培训丛书:电焊工入门与技巧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.24,"price":9.24,"shippingFee":2,"differencePrice":-11.24,"GoodsUrl":"https://book.kongfz.com/767143/8725850207","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdddabbd/5e8247e98682f766_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040506655","title":"西方政治思想史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":4.5,"shippingFee":0,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/638685/8638161704","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/445/5932042ae57cc3ce_b.jpg","GoodsImgCount":"1","onSaleCount":288,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538725421","title":"《希区柯克悬念故事集》-午夜追踪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.41,"price":4.91,"shippingFee":0.5,"differencePrice":-5.41,"GoodsUrl":"https://book.kongfz.com/156492/8287023578","imgBigUrl":"https://www0.kfzimg.com/G06/M00/4A/BF/p4YBAFqbw2CAMtcwAACLHc8-Kmw376_b.jpg","GoodsImgCount":"1","onSaleCount":127,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229148935","title":"少即是多:北欧自由生活意见新版与断舍离并提的人生整理术,樊登读书会创始人樊登亲自讲书推荐","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.92,"price":9.92,"shippingFee":5,"differencePrice":-14.92,"GoodsUrl":"https://book.kongfz.com/400965/8684128772","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddffccde/e26c93777dcaddbf_b.jpg","GoodsImgCount":"1","onSaleCount":140,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040402025","title":"管理心理学第二2版王晓钧 主编高等教育出版社9787040402025","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.72,"price":3.72,"shippingFee":0,"differencePrice":-3.72,"GoodsUrl":"https://book.kongfz.com/248516/8445959763","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/de788cd5eee0ea96_b.jpg","GoodsImgCount":"1","onSaleCount":126,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500081029","title":"曹汝霖一生之回忆","quality":0,"qualityText":"","originalPrice":0,"totalPrice":107.8,"price":102,"shippingFee":5.8,"differencePrice":-107.8,"GoodsUrl":"https://book.kongfz.com/51215/8461562441","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaefdbce/8c562bf3869c30fd_b.jpg","GoodsImgCount":"3","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030656407","title":"大学物理实验","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.1,"price":1.1,"shippingFee":3,"differencePrice":-4.1,"GoodsUrl":"https://book.kongfz.com/891713/8560427068","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aabafbce/ba4bec806b56ffe0_b.jpg","GoodsImgCount":"3","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122180339","title":"白菜与国王,心与手","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.9,"price":4.9,"shippingFee":0,"differencePrice":-4.9,"GoodsUrl":"https://book.kongfz.com/842883/8265631544","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceaeaadf/e35077eb4df6c14d_b.jpg","GoodsImgCount":"20","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547312964","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301302866","title":"法律研习的方法:作业、考试和论文写作","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":3,"shippingFee":10,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/891541/8813242545","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbdeecf/81217bf603b8cd44_b.jpg","GoodsImgCount":"2","onSaleCount":167,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506240789","title":"GRE 语文仿真试题","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.55,"price":2.55,"shippingFee":4,"differencePrice":-6.55,"GoodsUrl":"https://book.kongfz.com/203004/8427844598","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddcafaaf/ac83988286fb5146_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510454585","title":"中国社会科学全球化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35.81,"price":32.31,"shippingFee":3.5,"differencePrice":-35.81,"GoodsUrl":"https://book.kongfz.com/904671/8421015503","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbeeedeb/033d993974bafbe5_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558308178","title":"肖云峰阳光成长小说系列:我的筷子班主任","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":0.5,"shippingFee":4,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/768172/8469297539","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcfddbee/d237e91dc5b7f728_b.jpg","GoodsImgCount":"4","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040024135","title":"艺术概论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.8,"price":1.8,"shippingFee":3,"differencePrice":-4.8,"GoodsUrl":"https://book.kongfz.com/602194/6362597815","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbdecfeb/5da7fa93a557f9aa_b.jpg","GoodsImgCount":"4","onSaleCount":214,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535631329","title":"湖湘篆刻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":90,"price":80,"shippingFee":10,"differencePrice":-90,"GoodsUrl":"https://book.kongfz.com/27254/8219331776","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deeeddaf/74aeb2b4b131791a_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787570612352","title":"小学数学竞赛年鉴:MO2020","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":8,"shippingFee":5,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/426911/7902501351","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/7611848/fda903b85b9134bc_b.jpg","GoodsImgCount":"4","onSaleCount":124,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040285246","title":"正版二手 地球与空间科学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.7,"price":4.7,"shippingFee":0,"differencePrice":-4.7,"GoodsUrl":"https://book.kongfz.com/549116/8836455149","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/917/a23746764cd07ab3_b.jpg","GoodsImgCount":"1","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545812886","title":"三苏评传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":70,"price":58,"shippingFee":12,"differencePrice":-70,"GoodsUrl":"https://book.kongfz.com/23265/8181755497","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addddfac/fa013300f5292783_b.jpg","GoodsImgCount":"7","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510446566","title":"500美元问鼎百事CEO:全球头号女强人卢英德的经营哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/592021/5550361559","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddabecfa/dbc1bfe082195815_b.jpg","GoodsImgCount":"4","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121380440","title":"电气控制与plc技术应用 大中专理科水利电力 刘小春","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":13,"shippingFee":10,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/712076/8416032209","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dccdcafa/dec1e5d38d5f38ee_b.jpg","GoodsImgCount":"6","onSaleCount":53,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542618368","title":"德意志精神漫游","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.31,"price":17.31,"shippingFee":0,"differencePrice":-17.31,"GoodsUrl":"https://book.kongfz.com/919786/8892987379","imgBigUrl":"https://www0.kfzimg.com/G06/M00/6F/AB/p4YBAFqdEgyAcQgWAABHsHusPPc676_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787304008789","title":"艺术赏析概要","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.5,"price":0.5,"shippingFee":3,"differencePrice":-3.5,"GoodsUrl":"https://book.kongfz.com/838443/8859718589","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecffaac/dcae10f91c4a308b_b.jpg","GoodsImgCount":"1","onSaleCount":171,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562296195","title":"考点同步解读 高中化学 选择性必修一 化学反应原理 有笔记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":23,"shippingFee":3,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/211077/7520896879","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceaccafa/ab450e1ce8320b0e_b.jpg","GoodsImgCount":"4","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539947235","title":"铠甲勇士:神秘的陨石1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23.8,"price":18,"shippingFee":5.8,"differencePrice":-23.8,"GoodsUrl":"https://book.kongfz.com/747887/6880955959","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbcefbbc/682c32a3d38bb55d_b.jpg","GoodsImgCount":"7","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115375438","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564817688","title":"二手财经应用文写作9787564817688刘鑫","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":2.6,"shippingFee":2.9,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/750659/8426123356","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/affafccf/9af32edd2ccd7249_b.jpg","GoodsImgCount":"1","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503318443","title":"白登之围3 帝国草原三部曲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.5,"price":7.5,"shippingFee":5,"differencePrice":-12.5,"GoodsUrl":"https://book.kongfz.com/798681/8249118687","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeafdca/8450b15747941350_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787557014858","title":"诡秘之主4","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.46,"price":10.46,"shippingFee":5,"differencePrice":-15.46,"GoodsUrl":"https://book.kongfz.com/771462/8867879036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accbddaf/f6fcebe29db0cd77_b.jpg","GoodsImgCount":"4","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787225013046","title":"黄埔军校百将传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.98,"price":4,"shippingFee":2.98,"differencePrice":-6.98,"GoodsUrl":"https://book.kongfz.com/840438/8881985399","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfedbef/5eadb46b1348058c_b.jpg","GoodsImgCount":"2","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539798387","title":"妄想银行星新一 李盈春安徽少年儿童出版社9787539798387","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.19,"price":5.19,"shippingFee":0,"differencePrice":-5.19,"GoodsUrl":"https://book.kongfz.com/366030/8864056391","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/b0cc76b216b8cb24_b.jpg","GoodsImgCount":"1","onSaleCount":103,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544323086","title":"张家界旅游导读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/778224/6948456565","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfebdfee/1911341d2cf4b3cd_b.jpg","GoodsImgCount":"1","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516922811","title":"集体的失忆 杨定一全部生命系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33.65,"price":30.65,"shippingFee":3,"differencePrice":-33.65,"GoodsUrl":"https://book.kongfz.com/762329/8780202649","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10564427/c571335c6e98d724_b.jpg","GoodsImgCount":"0","onSaleCount":97,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302249085","title":"国际物流:国际贸易中的运作管理(第2版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":73.06,"price":61.06,"shippingFee":12,"differencePrice":-73.06,"GoodsUrl":"https://book.kongfz.com/795825/7334746188","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14523379/51ba99736a77252f_b.jpg","GoodsImgCount":"2","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810035750","title":"截拳道","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/233440/4385393174","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecbecbe/4a6d598b9537b021_b.jpg","GoodsImgCount":"4","onSaleCount":219,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807205913","title":"古玉收藏三百问 鉴宝 大众收藏3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":3,"shippingFee":2.4,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/561672/8415735311","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaccbcc/f11e6347fa684356_b.jpg","GoodsImgCount":"1","onSaleCount":128,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805747637","title":"西塘民间建筑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.1,"price":7.6,"shippingFee":5.5,"differencePrice":-13.1,"GoodsUrl":"https://book.kongfz.com/250120/8810679961","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edccedac/3fe60dbba98c7088_b.jpg","GoodsImgCount":"3","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100186506","title":"钱颖一对话录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":68,"price":58,"shippingFee":10,"differencePrice":-68,"GoodsUrl":"https://book.kongfz.com/17030/8830419237","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffceeede/2e8b3b3f24aa0fb7_b.jpg","GoodsImgCount":"7","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508673073","title":"茶当酒集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":4.5,"shippingFee":3.5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/401024/8872498867","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cacabaec/912f51c1b0fefcbd_b.jpg","GoodsImgCount":"2","onSaleCount":193,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801211453","title":"妇科病外治独特新疗法--内病外治·外病外治独特新疗法丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":15,"shippingFee":5,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/16472/6638610438","imgBigUrl":"https://www0.kfzimg.com/G06/M00/6D/DF/p4YBAFt2j6eAVdSMAAHEQyrZmzw541_b.jpg","GoodsImgCount":"2","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505438132","title":"探索·科学专题百科绘本 :植物的奥秘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":18,"shippingFee":10,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/427935/8151202484","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cffbddcd/b9350271a6c67aac_b.jpg","GoodsImgCount":"4","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113284220","title":"城市轨道交通信号技术(第二版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55.82,"price":49.82,"shippingFee":6,"differencePrice":-55.82,"GoodsUrl":"https://book.kongfz.com/533712/7445893108","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fffddefa/e3eecc18ea41d9a3_b.jpg","GoodsImgCount":"1","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560826462","title":"老上海名宅赏析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21,"price":12,"shippingFee":9,"differencePrice":-21,"GoodsUrl":"https://book.kongfz.com/366445/8584945980","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eabffdea/b445c31f3017c8ec_b.jpg","GoodsImgCount":"7","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805112329","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544786218","title":"小译林国际大奖童书:我的哥哥吹黑管","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.99,"price":4.99,"shippingFee":6,"differencePrice":-10.99,"GoodsUrl":"https://book.kongfz.com/273843/8153980235","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deffacda/736311caf50ede76_b.jpg","GoodsImgCount":"2","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504770356","title":"加盟连锁招商模式顶级设计思维 李松 李爽 9787504770356 中国财富出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.62,"price":5.12,"shippingFee":2.5,"differencePrice":-7.62,"GoodsUrl":"https://book.kongfz.com/237713/8695995574","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/940/a676d512dc1104ae_b.jpg","GoodsImgCount":"1","onSaleCount":165,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539168975","title":"胡平文集:百年误读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.46,"price":16.46,"shippingFee":2,"differencePrice":-18.46,"GoodsUrl":"https://book.kongfz.com/1214248/8872764563","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abbcffec/36a14534af372c1d_b.jpg","GoodsImgCount":"2","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534808944","title":"野叟曝言 下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.879999999999999,"price":4.88,"shippingFee":5,"differencePrice":-9.879999999999999,"GoodsUrl":"https://book.kongfz.com/750161/8080623189","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdfbabfb/bd7efa40cb71d18c_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810367899","title":"杨桃文化·新手食谱系列 41~45","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1,"shippingFee":4,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/891293/8009230723","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbffdadd/2dc8960a8a687a9f_b.jpg","GoodsImgCount":"3","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569931549","title":"看见梵高:孤独与伟大(写给大家的360度艺术启蒙书)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":2,"shippingFee":10,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/453237/8801143694","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acddcacb/fd041a1fd8b81733_b.jpg","GoodsImgCount":"11","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800220272","title":"常见病简易中医疗法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/322775/7550848376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cddccbec/e7fbcfaad8043cd4_b.jpg","GoodsImgCount":"11","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533758684","title":"超级秀·小学英语随堂故事:三年级","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.470000000000002,"price":27.87,"shippingFee":1.6,"differencePrice":-29.470000000000002,"GoodsUrl":"https://book.kongfz.com/470338/8595088507","imgBigUrl":"https://www0.kfzimg.com/G06/M00/FB/9F/p4YBAFqh40GANBXkAADzfKO38vM478_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553122250","title":"中国雕塑史 梁思成 著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.8,"price":18.8,"shippingFee":4,"differencePrice":-22.8,"GoodsUrl":"https://book.kongfz.com/651345/8071240129","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4893319/632f3df473149970_b.jpg","GoodsImgCount":"1","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806890356","title":"金田一探案集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.9,"price":6,"shippingFee":4.9,"differencePrice":-10.9,"GoodsUrl":"https://book.kongfz.com/588886/8817249258","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fddedbab/536b81fb83ff03a4_b.jpg","GoodsImgCount":"6","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122112309","title":"典型液压气动回路600例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27,"price":22,"shippingFee":5,"differencePrice":-27,"GoodsUrl":"https://book.kongfz.com/891499/8842174912","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eefdafbb/afc934890793788e_b.jpg","GoodsImgCount":"6","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500625827","title":"马说陶瓷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.8,"price":32,"shippingFee":5.8,"differencePrice":-37.8,"GoodsUrl":"https://book.kongfz.com/681126/8811277816","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbbbdfeb/569966dc1788862d_b.jpg","GoodsImgCount":"2","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214254863","title":"诗意人生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35.8,"price":29,"shippingFee":6.8,"differencePrice":-35.8,"GoodsUrl":"https://book.kongfz.com/13883/8535361435","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdafdced/5137129530c3717e_b.jpg","GoodsImgCount":"2","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535548887","title":"玻璃城堡","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":5,"shippingFee":4,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/512101/5119116553","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14073610/877fc17482e5334d_b.jpg","GoodsImgCount":"4","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787112273393","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534253621","title":"世界少年文学经典文库 叶圣陶作品精选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.48,"price":0.48,"shippingFee":3,"differencePrice":-3.48,"GoodsUrl":"https://book.kongfz.com/791250/8878211228","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aebcbced/163c2c611b494d45_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810035927","title":"奇门护身暗器练法(一版一印)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":30,"shippingFee":8,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/137604/7693281367","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfafeaac/d69912592ceffad6_b.jpg","GoodsImgCount":"5","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565659676","title":"最新五年中考满分作文大全","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/911923/8806310513","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbadcca/b8961895538c4451_b.jpg","GoodsImgCount":"1","onSaleCount":120,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040519297","title":"中学语文教学设计 郑桂华 9787040519297 高等教育出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.99,"price":5.99,"shippingFee":3,"differencePrice":-8.99,"GoodsUrl":"https://book.kongfz.com/240018/8661063245","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/424/549f95263f2b8049_b.jpg","GoodsImgCount":"0","onSaleCount":137,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550243552","title":"中华国学经典精粹·历史地理必读本:三国志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.8899999999999997,"price":0.11,"shippingFee":2.78,"differencePrice":-2.8899999999999997,"GoodsUrl":"https://book.kongfz.com/785333/8761856529","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbbebddd/b733d5d903cb7b1d_b.jpg","GoodsImgCount":"1","onSaleCount":789,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571103408","title":"中国现当代作家作品专题研究/河南省高等教育自学考试汉语言文学专业本科教材","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":18,"shippingFee":6,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/778238/8492605781","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdfafbca/e1fb525eb35a401b_b.jpg","GoodsImgCount":"12","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532614813","title":"8848我为歌狂终结本漫画版·楚天歌篇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33,"price":25,"shippingFee":8,"differencePrice":-33,"GoodsUrl":"https://book.kongfz.com/778785/7495502311","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecedbdcd/21cedd66962c506c_b.jpg","GoodsImgCount":"5","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539443744","title":"历代书法名迹技法选讲(第1辑):王铎诗卷.","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/18033/8237184983","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdffaecd/9190e5260d56e5dc_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515360607","title":"念力的秘密:2:2","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.2,"price":3.2,"shippingFee":5,"differencePrice":-8.2,"GoodsUrl":"https://book.kongfz.com/180897/8428663147","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dddfcdbd/210a611eee19a8eb_b.jpg","GoodsImgCount":"1","onSaleCount":144,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539154541","title":"绿山墙的安妮","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":4,"shippingFee":4,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/413068/2855797793","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3373/02e31e12e618d9a492_b.jpg","GoodsImgCount":"3","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539731766","title":"虹猫蓝兔七侠传.2","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.5,"price":1.5,"shippingFee":4,"differencePrice":-5.5,"GoodsUrl":"https://book.kongfz.com/198833/8806246345","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5862318/af620f5bab4bd51e_b.jpg","GoodsImgCount":"1","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544131834","title":"郑振铎藏本红楼梦","quality":0,"qualityText":"","originalPrice":0,"totalPrice":73,"price":65,"shippingFee":8,"differencePrice":-73,"GoodsUrl":"https://book.kongfz.com/25093/8534180256","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feabbbed/4e83283b2d4203e9_b.jpg","GoodsImgCount":"9","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511828156","title":"法律方法论 (书面有划横伤)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.9,"price":1.9,"shippingFee":8,"differencePrice":-9.9,"GoodsUrl":"https://book.kongfz.com/271477/8201797030","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffebdafa/76c5fecaf81060f1_b.jpg","GoodsImgCount":"5","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806657607","title":"明清小品选评 高温消毒发货 杨义著 李玫著 岳麓书社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.89,"price":8.09,"shippingFee":1.8,"differencePrice":-9.89,"GoodsUrl":"https://book.kongfz.com/110/8696629154","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caebcddd/7a1589c89b1a04c4_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787523202487","title":"2024世图版第二版英语皮考研真题逐词逐句精讲册 基础试卷版2004-2010曾鸣 张剑 刘京霄世界图书出版公司9787523202487","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":6.9,"shippingFee":0,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/248516/8585451759","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/1b6430cf81a207af_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108043597","title":"坚忍与守望 近代韩江下游的福音姿娘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.05,"price":12.55,"shippingFee":5.5,"differencePrice":-18.05,"GoodsUrl":"https://book.kongfz.com/244432/8796690963","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffeefbad/6720ba4115d67751_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535436375","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787830054038","title":"男科疾病诊断治疗指南(2022 版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":30,"shippingFee":5,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/196496/7650931803","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdebcfdf/e3d909f5ed9a00c8_b.jpg","GoodsImgCount":"6","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111307921","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544714587","title":"猫和老鼠:浪漫的代价","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.5,"price":0.5,"shippingFee":6,"differencePrice":-6.5,"GoodsUrl":"https://book.kongfz.com/570846/8637927606","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbcddccc/42e5131764a6ee79_b.jpg","GoodsImgCount":"7","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111244813","title":"HyperWorks分析应用实例9787111244813李楚琳机械工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.2,"price":16.7,"shippingFee":2.5,"differencePrice":-19.2,"GoodsUrl":"https://book.kongfz.com/1092759/8781226015","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbdedaf/05761766ae23af61_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513352109","title":"早期中国的鬼","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.85,"price":19.85,"shippingFee":3,"differencePrice":-22.85,"GoodsUrl":"https://book.kongfz.com/791250/8897892698","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaceecf/57e4bbc2456853dd_b.jpg","GoodsImgCount":"1","onSaleCount":160,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121253799","title":"体验引擎:游戏设计全景探秘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.48,"price":24.48,"shippingFee":0,"differencePrice":-24.48,"GoodsUrl":"https://book.kongfz.com/492548/8866402714","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C5/31/p4YBAFqYOW-AMOJ-AADBpjNYdUU066_b.jpg","GoodsImgCount":"1","onSaleCount":183,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508396170","title":"国家电网公司生产技能人员职业能力培训通用教材 继电保护及自动","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.45,"price":12.95,"shippingFee":4.5,"differencePrice":-17.45,"GoodsUrl":"https://book.kongfz.com/654834/8738560594","imgBigUrl":"https://www0.kfzimg.com/G06/M00/1C/8B/p4YBAFq7vXaAM8zEAADX1CViJh8024_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213086113","title":"【正版】创造自然9787213086113","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.86,"price":28.86,"shippingFee":0,"differencePrice":-28.86,"GoodsUrl":"https://book.kongfz.com/774490/8790671476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedbbfba/1175b5720aeccb00_b.jpg","GoodsImgCount":"1","onSaleCount":123,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535441058","title":"白色群像","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.2800000000000002,"price":0.28,"shippingFee":3,"differencePrice":-3.2800000000000002,"GoodsUrl":"https://book.kongfz.com/885099/8677269564","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfdeebbc/0c1b88098d1c3758_b.jpg","GoodsImgCount":"4","onSaleCount":513,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506026468","title":"斯大林的女儿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":9,"shippingFee":8,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/280648/7012552257","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdeadaca/fc65bfaccdc26af3_b.jpg","GoodsImgCount":"10","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501948802","title":"高温消毒发货 100种天然食物营养治病全新彩装","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.18,"price":4.38,"shippingFee":1.8,"differencePrice":-6.18,"GoodsUrl":"https://book.kongfz.com/110/8853611246","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbcacbda/2b0d9fb3a6dffbdf_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503424182","title":"政协主席","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.5,"price":6.5,"shippingFee":5,"differencePrice":-11.5,"GoodsUrl":"https://book.kongfz.com/1207201/8642380606","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deffcaae/e40f087108ded6db_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208145405","title":"殷墟青铜器研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33,"price":27,"shippingFee":6,"differencePrice":-33,"GoodsUrl":"https://book.kongfz.com/592236/8433015685","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daafbefb/968585acf2692335_b.jpg","GoodsImgCount":"13","onSaleCount":74,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301244869","title":"俄罗斯文学史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.76,"price":3.26,"shippingFee":1.5,"differencePrice":-4.76,"GoodsUrl":"https://book.kongfz.com/774690/8696568956","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C7/FD/p4YBAFqYQpWAbJXyAAC4ESrSO-U746_b.jpg","GoodsImgCount":"1","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542844064","title":"隐喻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49.8,"price":39.8,"shippingFee":10,"differencePrice":-49.8,"GoodsUrl":"https://book.kongfz.com/302127/7140352552","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AB/1A/p4YBAFr8MQOAND_6AAC1fo4rTZA063_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787568287760","title":"梅兰妮·克莱因儿童心理学:嫉羡与感恩","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.2,"price":11.2,"shippingFee":5,"differencePrice":-16.2,"GoodsUrl":"https://book.kongfz.com/1155304/8779916761","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3038/02939e282aadcbb13b_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532740680","title":"还原论的局限 来自活细胞的训诫","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":26,"shippingFee":3.8,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/1937/8841925682","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccfcafba/14d8bbf616f6cca3_b.jpg","GoodsImgCount":"6","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501056361","title":"嘉德日历2019","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":6,"shippingFee":10,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/593645/7150712837","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eadecbcb/e27d123c6ae6f237_b.jpg","GoodsImgCount":"6","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502848378","title":"怎么选择成长股 美 菲利普 A 费舍 地震出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.75,"price":7.75,"shippingFee":5,"differencePrice":-12.75,"GoodsUrl":"https://book.kongfz.com/180897/8899731120","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecaaabee/4d03e36f79e8d89c_b.jpg","GoodsImgCount":"1","onSaleCount":313,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571404512","title":"真相只有一个","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":1,"shippingFee":4,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/893934/8882047074","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbcdefeb/8e226b7ee365b547_b.jpg","GoodsImgCount":"3","onSaleCount":275,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302649847","title":"微积分","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.14,"price":37.34,"shippingFee":3.8,"differencePrice":-41.14,"GoodsUrl":"https://book.kongfz.com/717628/8773767244","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13270436/44c070d95076cb9a_b.jpg","GoodsImgCount":"1","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513662109","title":"年度经营计划制订与管理企业管理年度计划","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.62,"price":18.62,"shippingFee":6,"differencePrice":-24.62,"GoodsUrl":"https://book.kongfz.com/339693/8767370008","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2196/01b864aa0eea225d39_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101124163","title":"中国兵器史稿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/766211/7869531760","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdaaaae/1ae140e68d413e75_b.jpg","GoodsImgCount":"2","onSaleCount":126,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040212495","title":"肥胖症咨询","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.89,"price":15.89,"shippingFee":6,"differencePrice":-21.89,"GoodsUrl":"https://book.kongfz.com/903355/8146162281","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AB/70/p4YBAFqnmtuAcKiLAACq2BdpEts751_b.jpg","GoodsImgCount":"0","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111536659","title":"创业八讲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9000000000000004,"price":0.2,"shippingFee":3.7,"differencePrice":-3.9000000000000004,"GoodsUrl":"https://book.kongfz.com/682861/6931289851","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afffdaff/55c74a8b7dc93c83_b.jpg","GoodsImgCount":"3","onSaleCount":293,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532785049","title":"旅行的艺术(阿兰·德波顿作品集) [英]阿兰·德波顿 著,南治国 彭俊豪 何世原 译 上海译文出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.4,"price":13.4,"shippingFee":3,"differencePrice":-16.4,"GoodsUrl":"https://book.kongfz.com/521005/8637635084","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2926/0277dc937e68954c4f_b.jpg","GoodsImgCount":"1","onSaleCount":141,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532727308","title":"上尉的女儿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.5,"price":8,"shippingFee":4.5,"differencePrice":-12.5,"GoodsUrl":"https://book.kongfz.com/563726/4981987527","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbfdfcde/746d3d61e7061c4a_b.jpg","GoodsImgCount":"9","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787568028318","title":"说服力 如何讲好一个故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.99,"price":2.29,"shippingFee":3.7,"differencePrice":-5.99,"GoodsUrl":"https://book.kongfz.com/760748/8801361701","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcceffd/a729199af997ee71_b.jpg","GoodsImgCount":"3","onSaleCount":59,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508679709","title":"汉字有意思(精装)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":23,"shippingFee":5,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/735780/8827432116","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accfbccf/622e02efc4893d76_b.jpg","GoodsImgCount":"4","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540479343","title":"聪明人的一张纸工作整理术:完美图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.279999999999999,"price":2.78,"shippingFee":1.5,"differencePrice":-4.279999999999999,"GoodsUrl":"https://book.kongfz.com/772556/7315801571","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D2/B7/p4YBAFqYsP6Abfz2AACosblIHW0452_b.jpg","GoodsImgCount":"1","onSaleCount":324,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546342399","title":"黑色记事本 二手书实拍图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.809999999999999,"price":5.21,"shippingFee":5.6,"differencePrice":-10.809999999999999,"GoodsUrl":"https://book.kongfz.com/899541/8721283986","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/babdebfe/c531fae696961d1c_b.jpg","GoodsImgCount":"1","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121287183","title":"视觉型团队 应用可视化工具开创团队创新新模式双色","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.7,"price":25.7,"shippingFee":5,"differencePrice":-30.7,"GoodsUrl":"https://book.kongfz.com/666339/8521897933","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddddceac/3da6222201dfdb6b_b.jpg","GoodsImgCount":"1","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111134916","title":"4+2什么对企业真正有效","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/847200/8208211887","imgBigUrl":"https://www0.kfzimg.com/G06/M00/FF/A5/p4YBAFqh9_KAOFbPAACEsYfS-Qk627_b.jpg","GoodsImgCount":"1","onSaleCount":101,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030722485","title":"中药炮制学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33.3,"price":33.3,"shippingFee":0,"differencePrice":-33.3,"GoodsUrl":"https://book.kongfz.com/196857/8732055060","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/7445133/1aaae00ef9686a5d_b.jpg","GoodsImgCount":"1","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805236988","title":"红楼梦","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/256283/8754312169","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decabaff/80a154bafe4d9f70_b.jpg","GoodsImgCount":"9","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308080125","title":"文化产业概论(第二版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.01,"price":0.01,"shippingFee":4,"differencePrice":-4.01,"GoodsUrl":"https://book.kongfz.com/781353/7169578229","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baaefbfb/8732ca3425966bcc_b.jpg","GoodsImgCount":"1","onSaleCount":179,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549259618","title":"明朝市井周刊","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9,"price":3.9,"shippingFee":3,"differencePrice":-6.9,"GoodsUrl":"https://book.kongfz.com/783956/8836247359","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aebbfbcf/12ee2b7c2fb85771_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508098586","title":"太平洋地缘政治学:地理与历史之间关系的研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":44,"price":32,"shippingFee":12,"differencePrice":-44,"GoodsUrl":"https://book.kongfz.com/256234/7416926912","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecfdce/6940ef59d0e3093f_b.jpg","GoodsImgCount":"12","onSaleCount":99,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510711213","title":"平安中国年鉴 2023 碟子在","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":7,"shippingFee":5,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/878710/8454275891","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbfedcbc/950dd6c01187f526_b.jpg","GoodsImgCount":"1","onSaleCount":104,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559655479","title":"子不语:完全珍藏版.3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":10,"shippingFee":10,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/624390/6910763145","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eecfcffc/22d5dc8a606de24c_b.jpg","GoodsImgCount":"5","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787204044559","title":"中国偏方全书 肝病 肾病泌尿病","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.08,"price":0.08,"shippingFee":5,"differencePrice":-5.08,"GoodsUrl":"https://book.kongfz.com/716746/8631109464","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcafcfaa/4e57320326499aca_b.jpg","GoodsImgCount":"1","onSaleCount":286,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541445026","title":"魔法少女①——寻找百变裙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6,"price":6,"shippingFee":0,"differencePrice":-6,"GoodsUrl":"https://book.kongfz.com/461620/5735289715","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eefedaae/806a6210a4e2dfb3_b.jpg","GoodsImgCount":"4","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787228064564","title":"中国九十年代诗歌精选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.35,"price":6.35,"shippingFee":5,"differencePrice":-11.35,"GoodsUrl":"https://book.kongfz.com/820017/8795346716","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fffceade/974ba7bca5ddfc42_b.jpg","GoodsImgCount":"2","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224013887","title":"中国善恶报应习俗","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":3,"shippingFee":7,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/679518/7011532548","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddfebbdb/feef7a302dcd8e57_b.jpg","GoodsImgCount":"3","onSaleCount":51,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115597533","title":"新潮职业","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/911923/8655383401","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cebcdddb/6e45ffcdec9a8925_b.jpg","GoodsImgCount":"1","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506073486","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541128509","title":"不会吟诗也会吟 诗词创作十日谈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.96,"price":8.96,"shippingFee":5,"differencePrice":-13.96,"GoodsUrl":"https://book.kongfz.com/798681/8340108119","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecdfddf/da80026a3f1892fe_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545303964","title":"副省长女秘书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2,"shippingFee":5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/1207077/8689348274","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcaebab/610f32d42234c9ec_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308030458","title":"大学写作陈建新 主编浙江大学出版社9787308030458","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.03,"price":4.03,"shippingFee":0,"differencePrice":-4.03,"GoodsUrl":"https://book.kongfz.com/366030/8589381214","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/093b49e8b778b4c2_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544707510","title":"林先生的小孙女","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34.7,"price":29.7,"shippingFee":5,"differencePrice":-34.7,"GoodsUrl":"https://book.kongfz.com/911923/8761066348","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbdfebfb/29358101e6344448_b.jpg","GoodsImgCount":"1","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500923909","title":"陈式太极拳五功八法十三势","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.7,"price":4.9,"shippingFee":5.8,"differencePrice":-10.7,"GoodsUrl":"https://book.kongfz.com/703680/8288986467","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecffcff/7ec83cb4d94bafd5_b.jpg","GoodsImgCount":"3","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506367608","title":"那个骑轮箱来的蜜儿","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/788761/8822390367","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddecfeba/cdd744b263a7e6e1_b.jpg","GoodsImgCount":"1","onSaleCount":108,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505619050","title":"抵岸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":45,"shippingFee":4,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/585018/8894888641","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaafcdcb/89e23d1b5842789f_b.jpg","GoodsImgCount":"8","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522609096","title":"安顿自己 76岁日本女性专家真理子奶奶教你如何过好这一生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":3,"shippingFee":2.4,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/692223/8526088916","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcfbaad/756f18d7352b9e62_b.jpg","GoodsImgCount":"1","onSaleCount":170,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534190711","title":"补益中药实用技巧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.5,"price":3,"shippingFee":3.5,"differencePrice":-6.5,"GoodsUrl":"https://book.kongfz.com/884581/8442926178","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbdcebac/cef24561f15d8822_b.jpg","GoodsImgCount":"5","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500621775","title":"篆刻欣赏 9787500621775","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.65,"price":3.15,"shippingFee":3.5,"differencePrice":-6.65,"GoodsUrl":"https://book.kongfz.com/507381/7533225690","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13271240/a8653532485645de_b.jpg","GoodsImgCount":"1","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108003461","title":"红楼启示录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/398369/8193296634","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfdaabaf/892c48e88bbcdc59_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532139255","title":"考骨纪 北疆生死契 张硕 上海文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/398369/8420118970","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aafafbed/94ce7550b610293d_b.jpg","GoodsImgCount":"1","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519296544","title":"心理学考研重难点1200题","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/135543/8584685391","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbfbfcf/2462ed352d3f44f8_b.jpg","GoodsImgCount":"2","onSaleCount":56,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301279816","title":"贝壳博物馆 博物文库/自然博物馆丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":234,"price":230,"shippingFee":4,"differencePrice":-234,"GoodsUrl":"https://book.kongfz.com/884382/8100768943","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beeeccfa/6424ef37f54fd9bf_b.jpg","GoodsImgCount":"13","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302563273","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301326381","title":"股权、控制权与公司治理:120个实务问题解析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/11146/8755374340","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaaeebd/0672c84311716bdf_b.jpg","GoodsImgCount":"8","onSaleCount":113,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558609701","title":"中外经典故事连环画——中国古代神话故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":13,"shippingFee":0,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/622488/5080907449","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdaebdb/b76efed91207d395_b.jpg","GoodsImgCount":"2","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787571400064","title":"说手—太极拳静思录(承道篇)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42,"price":34,"shippingFee":8,"differencePrice":-42,"GoodsUrl":"https://book.kongfz.com/597518/8053281899","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccecdcda/aeab93b2adf2a81c_b.jpg","GoodsImgCount":"7","onSaleCount":100,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540000103","title":"罗通扫北","quality":0,"qualityText":"","originalPrice":0,"totalPrice":46,"price":46,"shippingFee":0,"differencePrice":-46,"GoodsUrl":"https://book.kongfz.com/370626/7929080243","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aefbedbc/a4fc65d52116f37f_b.jpg","GoodsImgCount":"3","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511327925","title":"读史有智慧用史有学问","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":14,"shippingFee":3,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/268442/8600009342","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bafbcbab/396f0e52bd7a25d9_b.jpg","GoodsImgCount":"9","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787226038857","title":"中国近代文物事业简史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":16,"shippingFee":10,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/15851/688431873","imgBigUrl":"https://www0.kfzimg.com/W03/14/12/141221cee4836b17ae8e215d8c10180e_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540421434","title":"跟我学手风琴弹唱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.8,"price":9.8,"shippingFee":6,"differencePrice":-15.8,"GoodsUrl":"https://book.kongfz.com/257028/1108204319","imgBigUrl":"https://www0.kfzimg.com/G07/M00/E0/92/qoYBAFwjPOCAZqP-AAGp7_le9_0427_b.jpg","GoodsImgCount":"3","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539317311","title":"福建印人传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36,"price":30,"shippingFee":6,"differencePrice":-36,"GoodsUrl":"https://book.kongfz.com/26986/8178082271","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcfccecd/014b311a1df3276d_b.jpg","GoodsImgCount":"4","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787114114298","title":"物流产业发展规划理论与实践","quality":0,"qualityText":"","originalPrice":0,"totalPrice":777780.3,"price":777780.3,"shippingFee":0,"differencePrice":-777780.3,"GoodsUrl":"https://book.kongfz.com/390985/8890465732","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C4/B6/p4YBAFq4r2iAEiqwAAC_IROI4fY072_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806227794","title":"揭开雍正皇帝隐秘的面纱","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.5,"price":7.5,"shippingFee":10,"differencePrice":-17.5,"GoodsUrl":"https://book.kongfz.com/603552/7638624490","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afcbdbda/df84853aea96acc6_b.jpg","GoodsImgCount":"1","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562050445","title":"程序即是惩罚:基层刑事法院的案件处理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.14,"price":9.14,"shippingFee":6,"differencePrice":-15.14,"GoodsUrl":"https://book.kongfz.com/560577/8422900551","imgBigUrl":"https://www0.kfzimg.com/G06/M00/63/D0/p4YBAFq-KauAZ5KrAACo4MqJ-oY907_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512721722","title":"不止文静","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.3500000000000005,"price":1.7,"shippingFee":5.65,"differencePrice":-7.3500000000000005,"GoodsUrl":"https://book.kongfz.com/743642/8767293788","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfeebade/d7b6b7c62b2a40e5_b.jpg","GoodsImgCount":"3","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535795168","title":"第一推动丛书 物理系列:完美理论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":6,"shippingFee":6,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/206084/8817868442","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6137288/629b1a53703318bb_b.jpg","GoodsImgCount":"6","onSaleCount":113,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559623102","title":"顶级销售的111条军规","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.57,"price":7.57,"shippingFee":4,"differencePrice":-11.57,"GoodsUrl":"https://book.kongfz.com/607359/8796692730","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E7/C4/p4YBAFt_h6uANn-6AADhap7U0Cs462_b.jpg","GoodsImgCount":"1","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531214151","title":"名家彩图鉴赏名杉崎由绮琉 琉璃色的天使","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":8,"shippingFee":0,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/208724/6365919000","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6206642/305ac1b89c25cda6_b.jpg","GoodsImgCount":"3","onSaleCount":208,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511883018","title":"中华人民共和国森林法 最新修订版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.54,"price":0.04,"shippingFee":4.5,"differencePrice":-4.54,"GoodsUrl":"https://book.kongfz.com/757209/8460373718","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaedbbba/b0b467ad7807e8c8_b.jpg","GoodsImgCount":"2","onSaleCount":57,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510143618","title":"邦臣小红花 神奇洞洞书 这是什么颜色 北京小红花图书工作室 中国人口出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.73,"price":2.73,"shippingFee":5,"differencePrice":-7.73,"GoodsUrl":"https://book.kongfz.com/263231/8827442067","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daebfcdd/21853a8d3d6b6f4e_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108028310","title":"语文常谈:中学图书馆文库","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":3,"shippingFee":7,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/346280/8715238629","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebecffaa/c0082bbaa022388a_b.jpg","GoodsImgCount":"4","onSaleCount":93,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539050904","title":"图解黄帝内经(中国养生第一书 经典图解畅销版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":10,"shippingFee":4,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/20902/8088357878","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beacfaae/051481bdbde5a4c7_b.jpg","GoodsImgCount":"3","onSaleCount":313,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111326236","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508095950","title":"我命在我也在天:道家筋经内传指略","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":20,"shippingFee":5,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/849894/8780983692","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccfbfbeb/c181eed498b667bd_b.jpg","GoodsImgCount":"6","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535971531","title":"潮式风味点心制作工艺(广东省“粤菜师傅”工程培训教材)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.89,"price":8.89,"shippingFee":5,"differencePrice":-13.89,"GoodsUrl":"https://book.kongfz.com/502929/8245471444","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdfddbb/7d433d18b88839e7_b.jpg","GoodsImgCount":"11","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501400881","title":"谍海沉浮三十年:休.汉布尔顿的双重生涯(//1988-07一版一印馆藏未翻阅自然旧近10品/见描述/2)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":10,"shippingFee":14,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/7229/644810045","imgBigUrl":"https://www0.kfzimg.com/G05/M00/05/41/p4YBAFjFSF2Ab6FaAAClse2zg6k836_b.jpg","GoodsImgCount":"3","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505920514","title":"中国神仙养生大全","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38,"price":28,"shippingFee":10,"differencePrice":-38,"GoodsUrl":"https://book.kongfz.com/233973/8813481496","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafadabd/21780c3c3a50a749_b.jpg","GoodsImgCount":"5","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040433647","title":"环境工程原理第3版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.4699999999999998,"price":0.47,"shippingFee":3,"differencePrice":-3.4699999999999998,"GoodsUrl":"https://book.kongfz.com/830714/8836053658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faddeebf/73e1130a978eb2ab_b.jpg","GoodsImgCount":"1","onSaleCount":333,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562353416","title":"我们这样做生本教育·数学篇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.730000000000004,"price":26.73,"shippingFee":6,"differencePrice":-32.730000000000004,"GoodsUrl":"https://book.kongfz.com/701775/8673274568","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fddbbdea/243269b1eea9ec2d_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208093973","title":"忧伤的老板","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/284909/6860484341","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feeddceb/3070df6c3b2af8ed_b.jpg","GoodsImgCount":"7","onSaleCount":119,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507532890","title":"蒋经国传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.11,"price":15.11,"shippingFee":6,"differencePrice":-21.11,"GoodsUrl":"https://book.kongfz.com/845061/7763922871","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cebaaefb/007eff2770c0243f_b.jpg","GoodsImgCount":"9","onSaleCount":319,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111497929","title":"零基础学内部审计","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":36,"shippingFee":7,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/521179/7169944650","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbfcfaf/ec51ee601eb33d49_b.jpg","GoodsImgCount":"4","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511575678","title":"北京四中语文课:细说诗文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":15,"shippingFee":5,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/902933/8887092520","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edbebdaa/f72f2a49d8f650cd_b.jpg","GoodsImgCount":"4","onSaleCount":136,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559629906","title":"新书-- 后浪·因为我有生活:电影美术师杨占家从艺录(精装)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":7,"shippingFee":7,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/680109/8164552567","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/306/3af6ecaa708cfe4d_b.jpg","GoodsImgCount":"1","onSaleCount":160,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787810035767","title":"三皇炮捶一北京镖局拳术功法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":78,"price":68,"shippingFee":10,"differencePrice":-78,"GoodsUrl":"https://book.kongfz.com/17030/7934731735","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faacbdfe/9dd500da308d84fb_b.jpg","GoodsImgCount":"6","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532256327","title":"中外设计艺术论著精读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.2,"price":7.2,"shippingFee":5,"differencePrice":-12.2,"GoodsUrl":"https://book.kongfz.com/180897/8429017414","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/affbbacd/c725a34076a44bc5_b.jpg","GoodsImgCount":"1","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787576406528","title":"环境法调整范围问题研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.72,"price":13.72,"shippingFee":7,"differencePrice":-20.72,"GoodsUrl":"https://book.kongfz.com/753811/8420113257","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14256494/0c2399ce4c56befd_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530522493","title":"棋魂·光之棋(15)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.8,"price":3.8,"shippingFee":12,"differencePrice":-15.8,"GoodsUrl":"https://book.kongfz.com/259232/3263082368","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efbaeadf/d6e0defb6c2112d3_b.jpg","GoodsImgCount":"3","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115455611","title":"股市T+0交易实战技法图解升级版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.45,"price":6.95,"shippingFee":5.5,"differencePrice":-12.45,"GoodsUrl":"https://book.kongfz.com/898097/8767386927","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/debffbda/75ccfb20d83a74a1_b.jpg","GoodsImgCount":"2","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547717455","title":"来点给力的正能量 让我更加积极向上的故事 做最好的自己","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.52,"price":1.12,"shippingFee":2.4,"differencePrice":-3.52,"GoodsUrl":"https://book.kongfz.com/561672/8424838977","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfafacec/f67f9a463082e593_b.jpg","GoodsImgCount":"1","onSaleCount":116,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303099771","title":"自信的提升","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":15,"shippingFee":0,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/783975/7001458250","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecbbaac/c1db02303b2b0bbc_b.jpg","GoodsImgCount":"5","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513318365","title":"二手昆虫漫话科普经典文库新星","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.49,"price":4.49,"shippingFee":2,"differencePrice":-6.49,"GoodsUrl":"https://book.kongfz.com/769044/7879074016","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caaeebac/90432555072321fe_b.jpg","GoodsImgCount":"3","onSaleCount":214,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117172028","title":"·医学影像学第7版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.88,"price":0.08,"shippingFee":3.8,"differencePrice":-3.88,"GoodsUrl":"https://book.kongfz.com/237705/8801387036","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaddeaff/0a5c6cac3826b2fc_b.jpg","GoodsImgCount":"1","onSaleCount":325,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787312027079","title":"高等学校过渡教材读本 高中数学大学数学基本习题练习高三学生升大学大一新生数学过渡 谢盛刚 中国科学技术大学出版社图书籍","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.37,"price":7.37,"shippingFee":10,"differencePrice":-17.37,"GoodsUrl":"https://book.kongfz.com/374786/8679077396","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11488598/edc93870210278b7_b.jpg","GoodsImgCount":"1","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506731584","title":"孰能无错:创建更加安全的医疗卫生保健系统","quality":0,"qualityText":"","originalPrice":0,"totalPrice":119.47,"price":107.47,"shippingFee":12,"differencePrice":-119.47,"GoodsUrl":"https://book.kongfz.com/912097/8236582135","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23092773/64be6ccad3f4056e_b.jpg","GoodsImgCount":"2","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806325162","title":"股市预测方法大全","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.7,"price":6.7,"shippingFee":5,"differencePrice":-11.7,"GoodsUrl":"https://book.kongfz.com/911923/8760299166","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfafeeed/53759abb4d28ec0a_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501167326","title":"斯大林:鲜为人知的剖面","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.13,"price":19.13,"shippingFee":3,"differencePrice":-22.13,"GoodsUrl":"https://book.kongfz.com/566350/8837106767","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abcfdcca/3069be6490f47334_b.jpg","GoodsImgCount":"6","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544430548","title":"中国近现代学校音乐教育(1840-1949)(1949-1995)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":20,"shippingFee":6,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/27200/6963259840","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeaacada/c8352f4dd943f78f_b.jpg","GoodsImgCount":"5","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121281839","title":"内分泌决定女人健康","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.5,"price":7,"shippingFee":2.5,"differencePrice":-9.5,"GoodsUrl":"https://book.kongfz.com/361618/8008064383","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dccddaee/22195ad9be22f208_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506322751","title":"巴黎 艺术至上","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.9399999999999995,"price":1.94,"shippingFee":5,"differencePrice":-6.9399999999999995,"GoodsUrl":"https://book.kongfz.com/820017/8872308665","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcaabdff/8609546f9f9d59d4_b.jpg","GoodsImgCount":"2","onSaleCount":110,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559437839","title":"遗忘","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":8,"shippingFee":3,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/268442/8358622148","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dceaeeaf/d6f93765fd88c265_b.jpg","GoodsImgCount":"6","onSaleCount":143,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521740288","title":"华为组织力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":15,"shippingFee":9,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/762356/6953163766","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14883503/80b35d52657b3996_b.jpg","GoodsImgCount":"1","onSaleCount":135,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201161969","title":"地球上线.3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.779999999999999,"price":4.77,"shippingFee":0.01,"differencePrice":-4.779999999999999,"GoodsUrl":"https://book.kongfz.com/754078/8661022100","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbacffdf/639fc984f5b2e115_b.jpg","GoodsImgCount":"2","onSaleCount":515,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516116890","title":"美国研究十年回顾(2001-2010)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.1,"price":10.1,"shippingFee":5,"differencePrice":-15.1,"GoodsUrl":"https://book.kongfz.com/619532/7045149457","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdaacece/05f659a51981a4d6_b.jpg","GoodsImgCount":"4","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521715613","title":"航海少年团1·古灯塔的神秘之门","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.89,"price":0.09,"shippingFee":4.8,"differencePrice":-4.89,"GoodsUrl":"https://book.kongfz.com/780405/7827920500","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcabbed/2ac0d0a49357653f_b.jpg","GoodsImgCount":"4","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553734088","title":"神农本草经(精版) 9787553734088","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.86,"price":12.86,"shippingFee":2,"differencePrice":-14.86,"GoodsUrl":"https://book.kongfz.com/755561/8095945895","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cccaedbc/a2944602ab786932_b.jpg","GoodsImgCount":"2","onSaleCount":202,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533935085","title":"各自的朝圣路","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":4.5,"shippingFee":0,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/356195/8895884096","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/a1472ea00606d477_b.jpg","GoodsImgCount":"5","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802504004","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030080509","title":"接口电路入门","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":3,"shippingFee":8,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/737383/6250535451","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdaaaec/4255d8b549208d2b_b.jpg","GoodsImgCount":"6","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508056180","title":"内功是怎样炼成的","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":26.8,"shippingFee":3,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/1087817/8643065121","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adfaaafb/dc1ba998f7f55ecf_b.jpg","GoodsImgCount":"6","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300089089","title":"传播学专业英语教程(第四版) 巴兰 中国人民大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":4.9,"shippingFee":3,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/521005/8353652390","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C6/1B/p4YBAFqYPGyAGqpqAAC62maQM4A311_b.jpg","GoodsImgCount":"1","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787563399789","title":"诗歌读本(学前卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25.22,"price":14.22,"shippingFee":11,"differencePrice":-25.22,"GoodsUrl":"https://book.kongfz.com/832731/7502436066","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22203957/acb0519120203613_b.jpg","GoodsImgCount":"2","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508659121","title":"小熊很忙中英双语厚纸板游戏书:快乐的假期","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":1,"shippingFee":10,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/281327/8827437261","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddaafcaf/7c85a7abd7215d33_b.jpg","GoodsImgCount":"6","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516530399","title":"未来世界","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.690000000000001,"price":6.69,"shippingFee":5,"differencePrice":-11.690000000000001,"GoodsUrl":"https://book.kongfz.com/1212927/8625774682","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabfaeed/effb81294d8913ec_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507305227","title":"从宝塔山到中南海","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":20,"shippingFee":15,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/669739/8486939181","imgBigUrl":"https://www0.kfzimg.com/G07/M00/FA/0C/q4YBAFywU4aAImriAABJ4X3BxME372_b.jpg","GoodsImgCount":"1","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541018961","title":"【涵套装】中国西部太阳谷——得荣:[中英藏文本]","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":26,"shippingFee":9,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/439962/6640113502","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caddfaca/d7cc825d53483bca_b.jpg","GoodsImgCount":"30","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544774277","title":"远处的拉莫","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.93,"price":19.93,"shippingFee":5,"differencePrice":-24.93,"GoodsUrl":"https://book.kongfz.com/202798/8665745337","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcabcbac/c0577cb97558c6f2_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501048014","title":"大美之佛像:犍陀罗艺术(16开精装 全1册)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":104.88,"price":98.88,"shippingFee":6,"differencePrice":-104.88,"GoodsUrl":"https://book.kongfz.com/386071/8241300300","imgBigUrl":"https://www0.kfzimg.com/G06/M00/EB/82/p4YBAFqhN8yAXG-yAADLMdZzwV4982_b.jpg","GoodsImgCount":"1","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547259863","title":"回话的技术","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.7800000000000002,"price":0.78,"shippingFee":2,"differencePrice":-2.7800000000000002,"GoodsUrl":"https://book.kongfz.com/738826/8530510157","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdcadebc/80a28b6c4a823131_b.jpg","GoodsImgCount":"1","onSaleCount":1640,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519102586","title":"【正版二手书籍】 幼儿园科学领域教育精要:关键经验与活动指导 175-5-2-127","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.95,"price":8.95,"shippingFee":2,"differencePrice":-10.95,"GoodsUrl":"https://book.kongfz.com/826462/8673356833","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22052838/3f2484448a8e7784_b.jpg","GoodsImgCount":"3","onSaleCount":105,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533263423","title":"没有秘密长不大","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.01,"price":0.01,"shippingFee":3,"differencePrice":-3.01,"GoodsUrl":"https://book.kongfz.com/891713/7988364522","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdbefbe/fe803e1c2690f4d9_b.jpg","GoodsImgCount":"4","onSaleCount":830,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806598436","title":"佛教灵验记研究:以晋唐为中心","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":40,"shippingFee":8,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/23842/8011951958","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3149222/bc752f79a0734a0f_b.jpg","GoodsImgCount":"5","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564129255","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115352491","title":"Photoshop CS6实战从入门到精通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.5,"price":3.5,"shippingFee":0,"differencePrice":-3.5,"GoodsUrl":"https://book.kongfz.com/372285/8607946044","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbdafff/0e356f4ae5d6050d_b.jpg","GoodsImgCount":"4","onSaleCount":236,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506382298","title":"三重门-十五周年纪念版9787506382298","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.2,"price":3.6,"shippingFee":2.6,"differencePrice":-6.2,"GoodsUrl":"https://book.kongfz.com/20579/8888133382","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfcbdfb/c68163ee23660130_b.jpg","GoodsImgCount":"1","onSaleCount":53,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560381299","title":"拉马努金遗失笔记(第一卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":110,"price":105,"shippingFee":5,"differencePrice":-110,"GoodsUrl":"https://book.kongfz.com/319561/8249081973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcecbafe/c29d43db77317553_b.jpg","GoodsImgCount":"9","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500869016","title":"诡盗团","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.4,"price":10,"shippingFee":5.4,"differencePrice":-15.4,"GoodsUrl":"https://book.kongfz.com/7546/8297358995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abdbfdde/76f2d0edb31829de_b.jpg","GoodsImgCount":"2","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540343927","title":"中华成语全典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":90,"price":78,"shippingFee":12,"differencePrice":-90,"GoodsUrl":"https://book.kongfz.com/602730/8697095825","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbaccafa/924c480acee402ce_b.jpg","GoodsImgCount":"4","onSaleCount":5,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553420394","title":"西方经典哲学之旅系列 荣格的性格哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.859999999999999,"price":0.06,"shippingFee":4.8,"differencePrice":-4.859999999999999,"GoodsUrl":"https://book.kongfz.com/245306/8510038095","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdeafdd/43d52666b500e80f_b.jpg","GoodsImgCount":"1","onSaleCount":188,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502541897","title":"润滑剂与润滑(有水印)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":39,"shippingFee":10,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/353752/8432573477","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deeecfdd/2761ee960fe2bd5b_b.jpg","GoodsImgCount":"6","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572617270","title":"《我准备好了,变老也没关系》","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.9,"price":11.9,"shippingFee":6,"differencePrice":-17.9,"GoodsUrl":"https://book.kongfz.com/901995/8697497893","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13196094/c59e3bd7277ec52d_b.jpg","GoodsImgCount":"1","onSaleCount":161,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508663920","title":"商业区块链 开启加密经济新时代威廉 穆贾雅 著 林华 等 译中信出版社9787508663920","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.01,"price":4.01,"shippingFee":0,"differencePrice":-4.01,"GoodsUrl":"https://book.kongfz.com/248516/8732168980","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/f4e2971f8af4ba85_b.jpg","GoodsImgCount":"1","onSaleCount":331,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308022279","title":"中央银行关金券·金圆券","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":10,"shippingFee":6,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/364294/8442165598","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedfbadc/a39d3b2c67fb7320_b.jpg","GoodsImgCount":"4","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503883880","title":"IUCN自然保护地管理分类应用指南:纪念中国自然保护区建设60周年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/274216/8872061006","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adefaafa/ec00a58c55648b0d_b.jpg","GoodsImgCount":"4","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221041524","title":"大唐西域记全译","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":23,"shippingFee":5,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/1207201/8690378400","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abacbffd/2e48df6c99d72e02_b.jpg","GoodsImgCount":"1","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506748438","title":"国医大师颜德馨","quality":0,"qualityText":"","originalPrice":0,"totalPrice":43,"price":36,"shippingFee":7,"differencePrice":-43,"GoodsUrl":"https://book.kongfz.com/15548/6439625257","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceffcafa/676a35c42ee7db3f_b.jpg","GoodsImgCount":"3","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221158017","title":"我当心理咨询师遇到的那些怪诞事件3","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.8,"price":8,"shippingFee":3.8,"differencePrice":-11.8,"GoodsUrl":"https://book.kongfz.com/198833/7419472199","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/5862318/942b1c4a6bced624_b.jpg","GoodsImgCount":"1","onSaleCount":49,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522604435","title":"安英的魅力口才","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.33,"price":7.33,"shippingFee":3,"differencePrice":-10.33,"GoodsUrl":"https://book.kongfz.com/566350/8859451482","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/15424286/0c9700a9eeda2a28_b.jpg","GoodsImgCount":"1","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787574204058","title":"新编医圣张仲景奇方妙治","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.24,"price":3.24,"shippingFee":5,"differencePrice":-8.24,"GoodsUrl":"https://book.kongfz.com/1154627/8795652570","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfacacce/1f4e1df9d8365907_b.jpg","GoodsImgCount":"2","onSaleCount":246,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547908051","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503232589","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549630356","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111674887","title":"Rhino7犀利建模","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.86,"price":7.86,"shippingFee":0,"differencePrice":-7.86,"GoodsUrl":"https://book.kongfz.com/638685/8631701848","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3656/0329a70d76c057ea6f_b.jpg","GoodsImgCount":"1","onSaleCount":143,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532924899","title":"请大家保护自己的腰/新活力作家文丛","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55.98,"price":45.98,"shippingFee":10,"differencePrice":-55.98,"GoodsUrl":"https://book.kongfz.com/832982/7495387597","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22231533/28e7f7f1bdb87c7f_b.jpg","GoodsImgCount":"2","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502419035","title":"重有色金属冶炼设计手册:冶炼烟气收尘·通用工程(常用数据卷)(藏书\\无笔记\\实物拍摄)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":228,"price":220,"shippingFee":8,"differencePrice":-228,"GoodsUrl":"https://book.kongfz.com/218311/7537560196","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/effdedef/6c145f37a0818a46_b.jpg","GoodsImgCount":"14","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787304093150","title":"DK玩出来的百科:棋子数学游戏(新版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/678667/7919607286","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bffefdbb/7bfd77f54abb77e1_b.jpg","GoodsImgCount":"4","onSaleCount":163,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500475965","title":"精英与资本:转型期中国乡村精英结构变迁的实证研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.4,"price":5,"shippingFee":4.4,"differencePrice":-9.4,"GoodsUrl":"https://book.kongfz.com/12041/8322135237","imgBigUrl":"https://www0.kfzimg.com/G06/M00/2E/97/p4YBAFs0qnmAL_i4AACf9Lup5DI641_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534059308","title":"排球少年!! 2:最高处的风景","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.5,"price":4.5,"shippingFee":6,"differencePrice":-10.5,"GoodsUrl":"https://book.kongfz.com/648064/8020657037","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbfddbcd/2983bfa0f566d3be_b.jpg","GoodsImgCount":"7","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787563392926","title":"浮生:清美凄凉的伶人传奇 馆藏无笔迹","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.2,"price":0.2,"shippingFee":6,"differencePrice":-6.2,"GoodsUrl":"https://book.kongfz.com/180265/5033827968","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feecdbac/ef77ae61ce991e03_b.jpg","GoodsImgCount":"2","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508682945","title":"我的世界就是一座花园","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.6,"price":17.6,"shippingFee":10,"differencePrice":-27.6,"GoodsUrl":"https://book.kongfz.com/901511/8212002579","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caddcbaf/376c04b8d6e29e64_b.jpg","GoodsImgCount":"4","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101040418","title":"三曹资料汇编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":54.42,"price":45.42,"shippingFee":9,"differencePrice":-54.42,"GoodsUrl":"https://book.kongfz.com/797172/8353517037","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21462970/467b1a4dcf01baf8_b.jpg","GoodsImgCount":"1","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530888469","title":"健康有捷径:气血旺 百病消","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/262475/4642903053","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfddfdfd/292f2b4eb304bb3e_b.jpg","GoodsImgCount":"9","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544789332","title":"人文与社会译丛:风险社会","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20,"price":12,"shippingFee":8,"differencePrice":-20,"GoodsUrl":"https://book.kongfz.com/591983/8368601013","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baeafbdb/ba8a68ab686c5496_b.jpg","GoodsImgCount":"5","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201110066","title":"正版 小鹿斑比 费利克斯 萨尔腾一部关于爱 成长与生命的童话 迪士尼同名动画原著小说 儿童文学 迪士尼 果麦图书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":45.5,"price":33.5,"shippingFee":12,"differencePrice":-45.5,"GoodsUrl":"https://book.kongfz.com/765896/6847101073","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20763945/401ff2ad8d22b54c_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521702019","title":"地球","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.93,"price":18.93,"shippingFee":10,"differencePrice":-28.93,"GoodsUrl":"https://book.kongfz.com/791821/8547538750","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/564/6d855bb66320948e_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787121288579","title":"高效运作项目管理办公室:PMO实践、案例和启示 张富民 著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.04,"price":12.04,"shippingFee":0,"differencePrice":-12.04,"GoodsUrl":"https://book.kongfz.com/169647/8662261121","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/3674971/90a67a9cc84613ca_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511361547","title":"股市心理战:一位资深股民的投资哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":35,"price":25,"shippingFee":10,"differencePrice":-35,"GoodsUrl":"https://book.kongfz.com/356104/4811368206","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaefbafe/a5e0de1094aec3d8_b.jpg","GoodsImgCount":"3","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547239438","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800689659","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040274202","title":"设计原理彭澎编著高等教育出版社9787040274202","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.79,"price":4.79,"shippingFee":0,"differencePrice":-4.79,"GoodsUrl":"https://book.kongfz.com/366030/8354018430","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/03d8b190e2261d50_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542847621","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801786029","title":"【原版闪电发货】原《金口诀应用学》(各类实战例题解读)/张得计大小六壬入门四柱学盲派书籍图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":50.4,"price":40.4,"shippingFee":10,"differencePrice":-50.4,"GoodsUrl":"https://book.kongfz.com/274158/7360476472","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9625326/3ee67f794e6b1f58_b.jpg","GoodsImgCount":"2","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787503400032","title":"忆往谈旧录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.1,"price":8.1,"shippingFee":3,"differencePrice":-11.1,"GoodsUrl":"https://book.kongfz.com/577988/7210036783","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdffcae/40a87de7683567d9_b.jpg","GoodsImgCount":"3","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559608710","title":"高敏感是种天赋 拯救全球15亿人的心灵之书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.55,"price":6.05,"shippingFee":1.5,"differencePrice":-7.55,"GoodsUrl":"https://book.kongfz.com/825417/8696502179","imgBigUrl":"https://www0.kfzimg.com/G06/M00/CB/77/p4YBAFqYl1eAXrB-AADwJUlM01E764_b.jpg","GoodsImgCount":"0","onSaleCount":467,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532264643","title":"铠甲勇士·刑天:对战大图鉴1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":20,"shippingFee":8,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/261367/8881674842","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dacfeccc/2c82927f965d5eea_b.jpg","GoodsImgCount":"11","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553443751","title":"菲尔博士率众前来","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":9,"shippingFee":8,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/188947/8481004836","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbdacdf/05ba38b868d0fca8_b.jpg","GoodsImgCount":"7","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305032974","title":"孟子评传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":148,"price":148,"shippingFee":0,"differencePrice":-148,"GoodsUrl":"https://book.kongfz.com/15335/8300858073","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baccaafc/a39615a199559525_b.jpg","GoodsImgCount":"8","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508678993","title":"我愿意等,熊猫先生(单册价格,套装咨询客服)(单册价格,套装咨询客服)(单册价格,套装咨询客服)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.91,"price":7.91,"shippingFee":2,"differencePrice":-9.91,"GoodsUrl":"https://book.kongfz.com/769044/8613050954","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecdbfbdf/00d80d1cc0ca28cc_b.jpg","GoodsImgCount":"2","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538550368","title":"疯了!桂宝(第贰卷)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.09,"price":0.09,"shippingFee":5,"differencePrice":-5.09,"GoodsUrl":"https://book.kongfz.com/11912/5836900069","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbaecaeb/c5c246f371e9cc2a_b.jpg","GoodsImgCount":"4","onSaleCount":161,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532750108","title":"炎夏之都","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32,"price":23,"shippingFee":9,"differencePrice":-32,"GoodsUrl":"https://book.kongfz.com/810477/8511733932","imgBigUrl":"https://www0.kfzimg.com/G06/M00/DE/4B/p4YBAFrUlHCAH8skAAB13jNBPts242_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514302646","title":"素食达人","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.95,"price":4.95,"shippingFee":4,"differencePrice":-8.95,"GoodsUrl":"https://book.kongfz.com/1027325/8690643837","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccafdaaf/ecd79dc361fa7827_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500489559","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787549559299","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115525932","title":"建筑施工会计真账实操全流程演练第2版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.82,"price":6.82,"shippingFee":0,"differencePrice":-6.82,"GoodsUrl":"https://book.kongfz.com/548348/8649348889","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/801/8da2143eeaea7a0b_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302165682","title":"清华大学化学类教材:简明物理化学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":31.78,"price":24.78,"shippingFee":7,"differencePrice":-31.78,"GoodsUrl":"https://book.kongfz.com/722739/8596219163","imgBigUrl":"https://www0.kfzimg.com/G06/M00/42/8C/p4YBAFqbhNuARHsYAAB-WYFXRzQ862_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101100938","title":"宋词三百首","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.780000000000001,"price":4.78,"shippingFee":4,"differencePrice":-8.780000000000001,"GoodsUrl":"https://book.kongfz.com/330788/8429376914","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbaffcff/acaca30e37ab4659_b.jpg","GoodsImgCount":"1","onSaleCount":145,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787800137495","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512679436","title":"原来化学可以这样学 化学奇谈","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.25,"price":0.25,"shippingFee":5,"differencePrice":-5.25,"GoodsUrl":"https://book.kongfz.com/202798/8459717610","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcecdaaf/b6227047461d7a66_b.jpg","GoodsImgCount":"1","onSaleCount":237,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9780375813658","title":"Magic Tree House Books #1-4神奇树屋合辑(1-4)(缺3册)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":4,"shippingFee":8,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/5669/7756604676","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1278/ecde0a6674bba01f_b.jpg","GoodsImgCount":"3","onSaleCount":72,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556828623","title":"苍蝇和大象的足球赛米切尔 恩德20周年纪念版精装","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.86,"price":5.86,"shippingFee":5,"differencePrice":-10.86,"GoodsUrl":"https://book.kongfz.com/911923/8827352288","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dacdaecc/d202436c78aecf55_b.jpg","GoodsImgCount":"1","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300145365","title":"刑法各论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/265019/8666457069","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C7/25/p4YBAFqYP2SACg9mAACfG_cnNJI045_b.jpg","GoodsImgCount":"1","onSaleCount":86,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787551715843","title":"VI设计9787551715843","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.69,"price":0.19,"shippingFee":3.5,"differencePrice":-3.69,"GoodsUrl":"https://book.kongfz.com/1152148/8524904150","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/becaaeef/50d6f4ba2c5a29e3_b.jpg","GoodsImgCount":"3","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532793365","title":"安娜·卡列尼娜的真实故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.8,"price":25,"shippingFee":4.8,"differencePrice":-29.8,"GoodsUrl":"https://book.kongfz.com/567272/8398230717","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abcfbbca/a0f81346232c398b_b.jpg","GoodsImgCount":"1","onSaleCount":124,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556101429","title":"爸爸去哪儿(实用版)超级龙蛋王亲子互动漫画(未拆封)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.5,"price":15,"shippingFee":5.5,"differencePrice":-20.5,"GoodsUrl":"https://book.kongfz.com/346699/4684397376","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/6198840/45e55b1a2a1686ca_b.jpg","GoodsImgCount":"3","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511354785","title":"高效经营法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17,"price":7,"shippingFee":10,"differencePrice":-17,"GoodsUrl":"https://book.kongfz.com/356060/8256005905","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcfceede/8183e6993263453c_b.jpg","GoodsImgCount":"3","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535692023","title":"浮世绘【浦睿文化出品】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.99,"price":22.99,"shippingFee":5,"differencePrice":-27.99,"GoodsUrl":"https://book.kongfz.com/914444/8566543484","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abccddda/84545b02d8c7d573_b.jpg","GoodsImgCount":"8","onSaleCount":151,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787507737172","title":"神农本草经读","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36.14,"price":24.14,"shippingFee":12,"differencePrice":-36.14,"GoodsUrl":"https://book.kongfz.com/795825/7321125946","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14523379/60a9962271d44fca_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787556240944","title":"儿童英语轻松学系列 儿童英语启蒙1000词","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.050000000000001,"price":2.16,"shippingFee":2.89,"differencePrice":-5.050000000000001,"GoodsUrl":"https://book.kongfz.com/785333/8282614242","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebbbeebb/ec1d8b32a5bea2e3_b.jpg","GoodsImgCount":"1","onSaleCount":121,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550042308","title":"丰子恺给孩子的阅读写作课 游记卷 丰子恺著绘 张伟锋点评 白马时光出品 百花洲文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":2.9,"shippingFee":5,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/398369/8726837081","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addfdfdc/53c3f12c6f960ff8_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111667278","title":"IT运维服务管理","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.26,"price":16.26,"shippingFee":0,"differencePrice":-16.26,"GoodsUrl":"https://book.kongfz.com/196857/8731918717","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2750/02491aeaaef30c5f3b_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544490337","title":"白马湖书系 培养真正的阅读者 整本书阅读之理论基础 吴欣歆 上海教育出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.59,"price":7.59,"shippingFee":5,"differencePrice":-12.59,"GoodsUrl":"https://book.kongfz.com/903313/8744997561","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efeeabfe/6b03cfc027eedc60_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539554594","title":"云梦泽屠龙记鬼谷学校 第五卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.01,"price":4.01,"shippingFee":3,"differencePrice":-7.01,"GoodsUrl":"https://book.kongfz.com/1181761/8874528061","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daceffce/ebcdaf1d65f390fb_b.jpg","GoodsImgCount":"1","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309079418","title":"三十七道品偈诵释义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":6,"shippingFee":6,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/386898/7963978478","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daefeadc/063dce8cf89efcab_b.jpg","GoodsImgCount":"3","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535957450","title":"寻味广东丛书:百年老店·广州老食肆与老食语","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":10,"shippingFee":4,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/203004/8386290176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfeebdfa/811d13534a3f61d4_b.jpg","GoodsImgCount":"1","onSaleCount":81,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305022906","title":"数学奥林匹克题典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":17,"shippingFee":7,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/188968/7578688674","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accadcff/4b343540fbb642e0_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787546376806","title":"西游记 吴承恩著 9787546376806 吉林出版集团有限责任公司","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.48,"price":3.98,"shippingFee":2.5,"differencePrice":-6.48,"GoodsUrl":"https://book.kongfz.com/237713/8683926712","imgBigUrl":"https://www0.kfzimg.com/G06/M00/49/0D/p4YBAFqbt_2AQMoYAABFGK4V49k913_b.jpg","GoodsImgCount":"1","onSaleCount":145,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521714074","title":"外国摄影师镜头里的中国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":72,"price":65,"shippingFee":7,"differencePrice":-72,"GoodsUrl":"https://book.kongfz.com/281199/8410912596","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfffacae/d2279aa3b06bc73f_b.jpg","GoodsImgCount":"11","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531171423","title":"嘻哈小天才. 9","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26,"price":16,"shippingFee":10,"differencePrice":-26,"GoodsUrl":"https://book.kongfz.com/497994/8873990567","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afaefffa/165fe0bdd58127cb_b.jpg","GoodsImgCount":"10","onSaleCount":16,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530500606","title":"欧洲绘画简史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.5,"price":5,"shippingFee":6.5,"differencePrice":-11.5,"GoodsUrl":"https://book.kongfz.com/754002/7204027658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdddbbcd/56f24b5b0f8784bb_b.jpg","GoodsImgCount":"4","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787510888489","title":"周易本义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":20,"shippingFee":8,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/228843/6865717081","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdfdfafb/dce8a087d28c2705_b.jpg","GoodsImgCount":"1","onSaleCount":133,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213013386","title":"人生絮语","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":3,"shippingFee":4,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/727057/8432652339","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbacfccd/b9fed35ba00032e8_b.jpg","GoodsImgCount":"7","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506748544","title":"国医大师唐由之","quality":0,"qualityText":"","originalPrice":0,"totalPrice":99.09,"price":90.09,"shippingFee":9,"differencePrice":-99.09,"GoodsUrl":"https://book.kongfz.com/465465/7167355375","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E2/3C/p4YBAFqY552AUUL5AACreTJSD6s208_b.jpg","GoodsImgCount":"1","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501946983","title":"家庭治疗基础","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38.9,"price":33.9,"shippingFee":5,"differencePrice":-38.9,"GoodsUrl":"https://book.kongfz.com/911923/8779777083","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cadeeebc/3589bebebfa3f806_b.jpg","GoodsImgCount":"1","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520822022","title":"中国古琴","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.51,"price":8.51,"shippingFee":3,"differencePrice":-11.51,"GoodsUrl":"https://book.kongfz.com/718844/7361733092","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/19134004/9c42134fc4f080b2_b.jpg","GoodsImgCount":"1","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530149188","title":"正版图书 蒲公英中国儿童文学名家精品丛书:小巫婆的大扫帚(注音版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":15,"shippingFee":10,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/525155/8129835817","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfededad/b9702bb478982502_b.jpg","GoodsImgCount":"9","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309016987","title":"孟子旁通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":11,"shippingFee":2,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/624177/8000572501","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedefadf/97ba0db0d0c9eeef_b.jpg","GoodsImgCount":"3","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544428651","title":"华师大二附中","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.4,"price":5.9,"shippingFee":5.5,"differencePrice":-11.4,"GoodsUrl":"https://book.kongfz.com/1182056/8831011997","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/1632/013b0116920fd5ef7a_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501986002","title":"家具专业英语实务(普通高等教育室内与家具设计专业十二五规划教材)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":47.1,"price":40.7,"shippingFee":6.4,"differencePrice":-47.1,"GoodsUrl":"https://book.kongfz.com/561989/8852981910","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbeebcf/437692bc37429777_b.jpg","GoodsImgCount":"1","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787558606212","title":"正版二手书书画巨匠艺库:傅抱石·傅抱石中国画法要论(精装本)9787558606212","quality":0,"qualityText":"","originalPrice":0,"totalPrice":106,"price":106,"shippingFee":0,"differencePrice":-106,"GoodsUrl":"https://book.kongfz.com/765962/8143826136","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbefebd/2596c704c26b9418_b.jpg","GoodsImgCount":"1","onSaleCount":98,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544878227","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506382014","title":"西班牙在心中:反法西斯诗选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":154,"price":145,"shippingFee":9,"differencePrice":-154,"GoodsUrl":"https://book.kongfz.com/758397/8540606900","imgBigUrl":"https://www0.kfzimg.com/G06/M00/A7/E1/p4YBAFqevjeAUjMWAABuc9xLDZQ430_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500112396","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787517147213","title":"铜雀锁金钗 民国虐心必看榜单神作 高温消毒发货 世味煮茶 中国言实出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":20.4,"price":18.4,"shippingFee":2,"differencePrice":-20.4,"GoodsUrl":"https://book.kongfz.com/1113/8677185936","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbbaede/051a0d80939bf3c7_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506086943","title":"噼里啪啦牙菌来啦","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.99,"price":4.99,"shippingFee":5,"differencePrice":-9.99,"GoodsUrl":"https://book.kongfz.com/375512/8829692617","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccfafccd/0e5374b790a97b04_b.jpg","GoodsImgCount":"4","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530640333","title":"李叔同影事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.35,"price":5.85,"shippingFee":5.5,"differencePrice":-11.35,"GoodsUrl":"https://book.kongfz.com/789796/8145140253","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaaeacdf/bc6e13229b611f82_b.jpg","GoodsImgCount":"14","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539958316","title":"能量场","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32,"price":26,"shippingFee":6,"differencePrice":-32,"GoodsUrl":"https://book.kongfz.com/398434/8881638801","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbaeabc/7827a2f39328e335_b.jpg","GoodsImgCount":"1","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540477240","title":"《发货快》留学口语从头学 赖世雄, 吴纪维 湖南文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.37,"price":6.87,"shippingFee":0.5,"differencePrice":-7.37,"GoodsUrl":"https://book.kongfz.com/156492/8283749461","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4362605/b9672e2119790224_b.jpg","GoodsImgCount":"1","onSaleCount":62,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509629727","title":"破解股市陷阱系列之二:技术指标虚假信号及破解方法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22.38,"price":22.38,"shippingFee":0,"differencePrice":-22.38,"GoodsUrl":"https://book.kongfz.com/792228/8894405073","imgBigUrl":"https://www0.kfzimg.com/G06/M00/27/6C/p4YBAFqaeZOARcnDAACg7i988Vw421_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807243991","title":"5分钟和陌生人成为朋友","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.57,"price":3.57,"shippingFee":0,"differencePrice":-3.57,"GoodsUrl":"https://book.kongfz.com/887808/8391689793","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bccbffae/f8debbec62ce7351_b.jpg","GoodsImgCount":"7","onSaleCount":685,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542644916","title":"诗人的迟缓【全新带塑封】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":21,"shippingFee":8,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/85357/7659329715","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2747720/00bc6133660a1e42_b.jpg","GoodsImgCount":"10","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300279107","title":"自媒体营销施薇 李灿辉 肖凭中国人民大学出版社9787300279107","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.97,"price":3.97,"shippingFee":0,"differencePrice":-3.97,"GoodsUrl":"https://book.kongfz.com/366030/8472562730","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/b8aec546a3b2d85b_b.jpg","GoodsImgCount":"1","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806749012","title":"中央美术学院教学素描典藏2:油画系1978级至2000级","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":39,"shippingFee":10,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/353476/8412551966","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdfbdcaf/03d7eb67b33a5434_b.jpg","GoodsImgCount":"8","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508612690","title":"美国怎么了?:一个自由主义者的良知","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":3.8,"shippingFee":0,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/356195/8832243949","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/10764816/39296172e9a70322_b.jpg","GoodsImgCount":"5","onSaleCount":688,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530914144","title":"外国文学小百科","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":5,"shippingFee":8,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/266365/1600675441","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/459/5bec61e229676ba7_b.jpg","GoodsImgCount":"5","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218123943","title":"早起的奇迹:那些能够在早晨8:00前改变人生的秘密","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.6,"price":6.6,"shippingFee":4,"differencePrice":-10.6,"GoodsUrl":"https://book.kongfz.com/1210014/8818511610","imgBigUrl":"https://www0.kfzimg.com/G06/M00/BE/35/p4YBAFsjew-AZMa4AADQy1ZsI-E761_b.jpg","GoodsImgCount":"0","onSaleCount":800,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559468185","title":"今日喜你(2)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30.18,"price":27.28,"shippingFee":2.9,"differencePrice":-30.18,"GoodsUrl":"https://book.kongfz.com/566350/8416910242","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfadadcb/ab01eb1968feebe1_b.jpg","GoodsImgCount":"2","onSaleCount":4,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806769300","title":"上海电影图史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.41,"price":11.41,"shippingFee":2,"differencePrice":-13.41,"GoodsUrl":"https://book.kongfz.com/769034/8690883878","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdebedb/8a4108e8115dcd59_b.jpg","GoodsImgCount":"3","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787517503569","title":"2019年政策粮食库存大清查培训教材 经济理论、法规 政策粮食库存数量和质量大清查部际协调机制办公室编 新华正版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.96,"price":0.06,"shippingFee":7.9,"differencePrice":-7.96,"GoodsUrl":"https://book.kongfz.com/266593/8181243192","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffeffcdf/08facbab7c467c40_b.jpg","GoodsImgCount":"3","onSaleCount":48,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218112039","title":"走进客家历史田野","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.67,"price":13.67,"shippingFee":2,"differencePrice":-15.67,"GoodsUrl":"https://book.kongfz.com/877749/8552934938","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/dbe28f6f66ba679c_b.jpg","GoodsImgCount":"2","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806460733","title":"千古名赋 咬文嚼字书林 吟诵卷 高建中选注 上海文化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.280000000000001,"price":7.28,"shippingFee":5,"differencePrice":-12.280000000000001,"GoodsUrl":"https://book.kongfz.com/180897/8848284913","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feefcbda/544e560d07370a8f_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221126634","title":"在血与火中穿行","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.4399999999999995,"price":1.44,"shippingFee":3,"differencePrice":-4.4399999999999995,"GoodsUrl":"https://book.kongfz.com/371891/3670304267","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cafcdcea/832f209afe7f1e48_b.jpg","GoodsImgCount":"7","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501035120","title":"吴门篆刻史研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.46,"price":28.96,"shippingFee":3.5,"differencePrice":-32.46,"GoodsUrl":"https://book.kongfz.com/904671/8420602978","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dedcceac/a3f246f9df94771a_b.jpg","GoodsImgCount":"1","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522901176","title":"烹饪原料学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":9,"shippingFee":7,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/791901/8236858701","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbaafabd/d14d90ded1b4853a_b.jpg","GoodsImgCount":"14","onSaleCount":37,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515304786","title":"器材大师2佳能EOS60D数码单反摄影完全攻略","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.05,"price":7.55,"shippingFee":4.5,"differencePrice":-12.05,"GoodsUrl":"https://book.kongfz.com/531994/8713723345","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfaaedc/5774b1aee3694d8d_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535557865","title":"经济学大纲李达著湖南教育出版社正版马克思主义经济学教科书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":96.60000000000001,"price":86.7,"shippingFee":9.9,"differencePrice":-96.60000000000001,"GoodsUrl":"https://book.kongfz.com/498749/7330285594","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/13768817/f620e30b590271c7_b.jpg","GoodsImgCount":"5","onSaleCount":4,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100007986","title":"外国地名译名手册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":10,"shippingFee":3,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/783956/8818059184","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddadbdae/0c467f31d5f788c4_b.jpg","GoodsImgCount":"1","onSaleCount":118,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807283690","title":"饭前好汤","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.49,"price":1.51,"shippingFee":2.98,"differencePrice":-4.49,"GoodsUrl":"https://book.kongfz.com/761854/8327314613","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbeddfff/771d2b0ef4627887_b.jpg","GoodsImgCount":"2","onSaleCount":50,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501946822","title":"发展心理学:心理学导读系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":10,"shippingFee":8,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/619676/8100134597","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfebddff/67fab02ba70db394_b.jpg","GoodsImgCount":"10","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020152513","title":"哈利 波特与密室1 英 J K 罗琳著 马爱农 马爱新译 人民文学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.02,"price":2.02,"shippingFee":5,"differencePrice":-7.02,"GoodsUrl":"https://book.kongfz.com/180897/8899464885","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdaeaadb/03de942e85445e90_b.jpg","GoodsImgCount":"1","onSaleCount":192,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301138731","title":"经济发展与转型 思潮 战略与自生能力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.75,"price":1.75,"shippingFee":5,"differencePrice":-6.75,"GoodsUrl":"https://book.kongfz.com/263231/8460658424","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfcfefff/4a059682c31d1bf7_b.jpg","GoodsImgCount":"1","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122145031","title":"人生没有假如 一个 渐冻人 的悟与行 王甲著 化学工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/1146983/8773150111","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddecdabb/1a7c05d00ab28762_b.jpg","GoodsImgCount":"1","onSaleCount":200,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807657590","title":"楚留香新传4:新月传奇·午夜兰花","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":11,"shippingFee":8,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/623665/8695112105","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeaacdc/c5c542d15f9601b9_b.jpg","GoodsImgCount":"9","onSaleCount":81,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553443133","title":"星火英语·专4新题型标准阅读180篇","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.86,"price":0.06,"shippingFee":3.8,"differencePrice":-3.86,"GoodsUrl":"https://book.kongfz.com/237705/8785081658","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffdeffbe/1fadee5fe9aa9939_b.jpg","GoodsImgCount":"1","onSaleCount":75,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020073948","title":"思无邪","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.6,"price":0.6,"shippingFee":3,"differencePrice":-3.6,"GoodsUrl":"https://book.kongfz.com/903324/8684232524","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabbfacc/a28a9fc194d8bb7e_b.jpg","GoodsImgCount":"4","onSaleCount":552,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787554709719","title":"中国线描 钟馗迎祥纳福百图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":7,"shippingFee":5,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/735086/6940082430","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfdddfbc/d60edd964b638b70_b.jpg","GoodsImgCount":"5","onSaleCount":95,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111527077","title":"质量总监成长记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28,"price":24.2,"shippingFee":3.8,"differencePrice":-28,"GoodsUrl":"https://book.kongfz.com/237705/8642867339","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedfaddf/ef6b31285894943a_b.jpg","GoodsImgCount":"1","onSaleCount":44,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521723311","title":"地球的故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":111.96,"price":102.96,"shippingFee":9,"differencePrice":-111.96,"GoodsUrl":"https://book.kongfz.com/518589/8629261141","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3457/02f88e006ed44dea44_b.jpg","GoodsImgCount":"1","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787502850449","title":"十年三","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.21,"price":2.21,"shippingFee":5,"differencePrice":-7.21,"GoodsUrl":"https://book.kongfz.com/714758/7591149701","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/badfefcf/bfbebc21eedd5e0e_b.jpg","GoodsImgCount":"2","onSaleCount":221,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513256698","title":"中国孩子中医养:坐月子怎么吃(全彩)用适合中国人的方式让宝妈不落病奶水足,宝宝不生病长得壮!","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/462171/8660821950","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbebeecf/2f6e7e0bf01a00d5_b.jpg","GoodsImgCount":"2","onSaleCount":89,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542621641","title":"近代私法史下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":97,"price":93,"shippingFee":4,"differencePrice":-97,"GoodsUrl":"https://book.kongfz.com/330788/8423978555","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeffbcd/a893aaab265655e0_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787542837875","title":"相对论的意义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/246207/8481578074","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfabecbe/a2e86389c5114683_b.jpg","GoodsImgCount":"6","onSaleCount":22,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500421900","title":"佛陀和原始佛教思想","quality":0,"qualityText":"","originalPrice":0,"totalPrice":76.92,"price":71.42,"shippingFee":5.5,"differencePrice":-76.92,"GoodsUrl":"https://book.kongfz.com/250120/8708990278","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddddeaad/33b05c5af02f72b6_b.jpg","GoodsImgCount":"3","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532158263","title":"眼睛游戏 二手书实拍图","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.719999999999999,"price":7.12,"shippingFee":5.6,"differencePrice":-12.719999999999999,"GoodsUrl":"https://book.kongfz.com/899541/8749220703","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecfdeda/8b6bf25d96064288_b.jpg","GoodsImgCount":"1","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111669531","title":"SiC/GaN功率半导体封装和可靠性评估技术","quality":0,"qualityText":"","originalPrice":0,"totalPrice":45.27,"price":38.27,"shippingFee":7,"differencePrice":-45.27,"GoodsUrl":"https://book.kongfz.com/162938/8886458225","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3374/02e33f6a36d6a2b377_b.jpg","GoodsImgCount":"1","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518033645","title":"为什么你说话别人不爱听张鸿9787518033645","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.3,"price":0.5,"shippingFee":2.8,"differencePrice":-3.3,"GoodsUrl":"https://book.kongfz.com/881983/7867281773","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaebadcb/3cd42d6ced8893f8_b.jpg","GoodsImgCount":"1","onSaleCount":550,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787543981515","title":"从陪伴到放手:复旦五浦汇丛书-说李白黄玉峰","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13,"price":8,"shippingFee":5,"differencePrice":-13,"GoodsUrl":"https://book.kongfz.com/15335/8689567387","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcbfadf/be78bc3cc126b571_b.jpg","GoodsImgCount":"4","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505740570","title":"七根凶简渔线人偶仙人指路 尾鱼 中国友谊出版公司","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.71,"price":10.71,"shippingFee":5,"differencePrice":-15.71,"GoodsUrl":"https://book.kongfz.com/903313/8601974525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaecddef/9c5814706496e1ad_b.jpg","GoodsImgCount":"1","onSaleCount":164,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111604518","title":"数据化运营:系统方法与实践案例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.61,"price":8.61,"shippingFee":0,"differencePrice":-8.61,"GoodsUrl":"https://book.kongfz.com/768603/8897179135","imgBigUrl":"https://www0.kfzimg.com/G06/M00/0A/A8/p4YBAFuMo-KAabDXAABizTiDPo4865_b.jpg","GoodsImgCount":"1","onSaleCount":136,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544733434","title":"战争临到美国:丘吉尔第二次世界大战回忆录06","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.83,"price":8.83,"shippingFee":2,"differencePrice":-10.83,"GoodsUrl":"https://book.kongfz.com/754405/8464078588","imgBigUrl":"https://www0.kfzimg.com/G06/M00/AD/60/p4YBAFqfHMGAE36pAAEpfYi4KYI348_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802031623","title":"冯德全早教方案:三岁缔造一生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9,"price":0.9,"shippingFee":3,"differencePrice":-3.9,"GoodsUrl":"https://book.kongfz.com/832065/8677106895","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E4/42/p4YBAFqY74iAIP61AADPFXvXBAk285_b.jpg","GoodsImgCount":"1","onSaleCount":287,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787112243693","title":"自然与道德(古代永州地区城市规划设计研究)/人居环境科学丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":51.37,"price":49.37,"shippingFee":2,"differencePrice":-51.37,"GoodsUrl":"https://book.kongfz.com/476106/8289767243","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdfbdcfc/d5c28fc209e2480f_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504662774","title":"老科学家学术成长资料采集工程丛书国科学院院士传记丛书大音希声应崇福传 王传超著 国科学技术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.1,"price":6.1,"shippingFee":5,"differencePrice":-11.1,"GoodsUrl":"https://book.kongfz.com/911923/8642786730","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eedbfedb/0ee80689f3f1f141_b.jpg","GoodsImgCount":"1","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532763399","title":"第二性","quality":0,"qualityText":"","originalPrice":0,"totalPrice":48,"price":39,"shippingFee":9,"differencePrice":-48,"GoodsUrl":"https://book.kongfz.com/24286/8655519438","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdbbcff/11326043b66b78d8_b.jpg","GoodsImgCount":"8","onSaleCount":208,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787221181442","title":"西游密档 死亡诅咒","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.190000000000001,"price":6.19,"shippingFee":3,"differencePrice":-9.190000000000001,"GoodsUrl":"https://book.kongfz.com/774181/8822974772","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/16365868/be960223de05f0da_b.jpg","GoodsImgCount":"1","onSaleCount":107,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108056283","title":"窥视日本","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.4,"price":14.4,"shippingFee":5,"differencePrice":-19.4,"GoodsUrl":"https://book.kongfz.com/640398/8325622171","imgBigUrl":"https://www0.kfzimg.com/G06/M00/61/9C/p4YBAFqctU6AC_foAAC3m52T-Pg635_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522510606","title":"别再说我恋爱脑 亲密关系 金钱与自我 孙能能 九州出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":2.9,"shippingFee":5,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/878060/8575274097","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeedfbcd/cf34c35618e4846a_b.jpg","GoodsImgCount":"1","onSaleCount":185,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010136479","title":"日本如何面对历史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.9,"price":4.9,"shippingFee":5,"differencePrice":-9.9,"GoodsUrl":"https://book.kongfz.com/398369/8886414153","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeabacd/414f2354130e7c2b_b.jpg","GoodsImgCount":"1","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537863407","title":"沈从文全集·补遗卷(历经十七年搜集、整理的遗落于《沈从文全集》之外的篇目)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":151.8,"price":151.8,"shippingFee":0,"differencePrice":-151.8,"GoodsUrl":"https://book.kongfz.com/506993/8197585884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddbdadc/863af2d42f64a712_b.jpg","GoodsImgCount":"4","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564365103","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787512501010","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534069109","title":"画猫.雅宋:宋朝风情绘卷 16开 原价68元 ,画集以猫拟人,用千姿百态的猫咪演绎宋朝的绝代佳人、名士才子、休闲娱乐、生活习俗以及饮食文化等内容,收录五十张插画,分为【宋朝红颜谱】【宋朝才俊传】【宋朝闲乐篇】【宋朝百家事】【宋朝食事说】五大部分,展现出独特的宋朝风貌。","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":16,"shippingFee":0,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/22178/8842692481","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabfaccc/296ab20dabec1d3d_b.jpg","GoodsImgCount":"8","onSaleCount":68,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787555102571","title":"你了解动物朋友吗/思考的魅力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.88,"price":0.08,"shippingFee":3.8,"differencePrice":-3.88,"GoodsUrl":"https://book.kongfz.com/237705/8818015350","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddbeada/454883a43146e865_b.jpg","GoodsImgCount":"1","onSaleCount":96,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801273963","title":"心灵导师 情绪管理全书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.6,"price":0.6,"shippingFee":3,"differencePrice":-3.6,"GoodsUrl":"https://book.kongfz.com/791250/8376938616","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daafbaca/99cdf254dc0503cf_b.jpg","GoodsImgCount":"1","onSaleCount":328,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550285811","title":"很老很老的老偏方 :","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.06,"price":4.05,"shippingFee":0.01,"differencePrice":-4.06,"GoodsUrl":"https://book.kongfz.com/778027/8309893135","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eafeceea/577f1db4f57123fd_b.jpg","GoodsImgCount":"5","onSaleCount":622,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504468079","title":"煤矿 科学环境风水学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.8,"price":7.8,"shippingFee":5,"differencePrice":-12.8,"GoodsUrl":"https://book.kongfz.com/903313/8491513788","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23176617/284894c1eaa3b820_b.jpg","GoodsImgCount":"2","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787102080901","title":"中华砚文化汇典:砚谱卷:归云楼砚谱新编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":118.48,"price":114.08,"shippingFee":4.4,"differencePrice":-118.48,"GoodsUrl":"https://book.kongfz.com/27495/8065738536","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/14256494/e9d0ec6a139e5a6d_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122387813","title":"变频器故障检修260例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":46.2,"price":40.2,"shippingFee":6,"differencePrice":-46.2,"GoodsUrl":"https://book.kongfz.com/1118298/8825504310","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/7445133/6b80c75aef1c1c8d_b.jpg","GoodsImgCount":"1","onSaleCount":64,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530415702","title":"小学生作文大全 创新作文","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.1,"price":0.1,"shippingFee":3,"differencePrice":-3.1,"GoodsUrl":"https://book.kongfz.com/371891/5644920378","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acedfbbf/2d736b34bda93f2c_b.jpg","GoodsImgCount":"3","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509141892","title":"30年临证实验录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55.92,"price":45.92,"shippingFee":10,"differencePrice":-55.92,"GoodsUrl":"https://book.kongfz.com/833207/7490953622","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22165297/2cd24e3e0d92cfc5_b.jpg","GoodsImgCount":"2","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201161693","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108009234","title":"大剖面:不可思议的剖面","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53,"price":45,"shippingFee":8,"differencePrice":-53,"GoodsUrl":"https://book.kongfz.com/310577/5906903518","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dedcfdcb/ee738917471fe03f_b.jpg","GoodsImgCount":"6","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515406466","title":"回忆萧华:纪念开国上将萧华诞辰100周年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":69,"price":60,"shippingFee":9,"differencePrice":-69,"GoodsUrl":"https://book.kongfz.com/634974/8146082829","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addeffcf/50b393dd54382db6_b.jpg","GoodsImgCount":"6","onSaleCount":27,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505907294","title":"人类性爱史话","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.5,"price":1.5,"shippingFee":5,"differencePrice":-6.5,"GoodsUrl":"https://book.kongfz.com/890432/8719655764","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fddffafa/1b2b73ba2dc29f83_b.jpg","GoodsImgCount":"1","onSaleCount":177,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787806155073","title":"金点子赚大钱赚钱点子 金 字系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.1,"price":0.1,"shippingFee":5,"differencePrice":-5.1,"GoodsUrl":"https://book.kongfz.com/1207201/8801350603","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddccedcf/bc869c63b26b2662_b.jpg","GoodsImgCount":"1","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787303119752","title":"20世纪西方文论新编 陈太胜 9787303119752 北京师范大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.53,"price":1.53,"shippingFee":3,"differencePrice":-4.53,"GoodsUrl":"https://book.kongfz.com/240018/8665248260","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C8/18/p4YBAFqotxaAffdjAADUpAcClLs234_b.jpg","GoodsImgCount":"1","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541126895","title":"三国演义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.29,"price":3.79,"shippingFee":2.5,"differencePrice":-6.29,"GoodsUrl":"https://book.kongfz.com/782278/8848213757","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afffccde/20b47fe8625e47a6_b.jpg","GoodsImgCount":"1","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500436867","title":"二手正版在下沉、下沉的世界里上升、上升9787500436867","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":4,"shippingFee":0,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/765962/6746217821","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eaeeefbd/ccebe6c255823c7a_b.jpg","GoodsImgCount":"1","onSaleCount":60,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553313368","title":"不会说话,你就输了","quality":0,"qualityText":"","originalPrice":0,"totalPrice":2.9,"price":0.9,"shippingFee":2,"differencePrice":-2.9,"GoodsUrl":"https://book.kongfz.com/738826/8619357112","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adcaaddb/f1b58548dcfe64be_b.jpg","GoodsImgCount":"1","onSaleCount":1327,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787576007565","title":"从课本到奥数 7年级 第2学期 A版 第3版·视频讲解版 吴建平熊斌主编 华东师范大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.25,"price":14.75,"shippingFee":3.5,"differencePrice":-18.25,"GoodsUrl":"https://book.kongfz.com/610883/8510316729","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ecfaafff/60aabde21e985ecd_b.jpg","GoodsImgCount":"5","onSaleCount":54,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787557548193","title":"我叫丁 隐形的朋友 杨校艳 吉林美术出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":4.8,"shippingFee":5,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/263231/8583717995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/befeffda/7748c91965d89732_b.jpg","GoodsImgCount":"1","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559620668","title":"你要如何衡量你的人生","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.36,"price":9.36,"shippingFee":5,"differencePrice":-14.36,"GoodsUrl":"https://book.kongfz.com/750161/8749953015","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddafebab/9ee757288f1baef8_b.jpg","GoodsImgCount":"1","onSaleCount":115,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532552726","title":"周易虞氏易象释易则","quality":0,"qualityText":"","originalPrice":0,"totalPrice":108,"price":90,"shippingFee":18,"differencePrice":-108,"GoodsUrl":"https://book.kongfz.com/476973/4795679344","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edafaabb/a4e9fc477f428e7d_b.jpg","GoodsImgCount":"5","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530220771","title":"绘本 三国志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37,"price":31,"shippingFee":6,"differencePrice":-37,"GoodsUrl":"https://book.kongfz.com/283241/8877731096","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbadebae/8da18a79e50e7791_b.jpg","GoodsImgCount":"9","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115449238","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535218292","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787541151408","title":"昆仑.大结局","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":8,"shippingFee":7,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/624391/5408060815","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcbfadbb/07c3be2711e5771a_b.jpg","GoodsImgCount":"12","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537728317","title":"梁秀清临床经验选","quality":0,"qualityText":"","originalPrice":0,"totalPrice":108,"price":98,"shippingFee":10,"differencePrice":-108,"GoodsUrl":"https://book.kongfz.com/12117/8755654368","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eafaffdb/a731ef1a1cca7b58_b.jpg","GoodsImgCount":"2","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511536600","title":"人民日报记者说:典型人物采访与写作","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":7.2,"shippingFee":0,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/27736/8222096683","imgBigUrl":"https://www0.kfzimg.com/G06/M00/5F/DB/p4YBAFqlT3GAMPjmAACYZ6OExoQ676_b.jpg","GoodsImgCount":"1","onSaleCount":247,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801702715","title":"王树声传 王树声传 编写组编 当代中国出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":33,"price":28,"shippingFee":5,"differencePrice":-33,"GoodsUrl":"https://book.kongfz.com/911923/8772814849","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abeedcfa/bdd7e96d5ebd45fe_b.jpg","GoodsImgCount":"1","onSaleCount":90,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787219045039","title":"中国吴氏通书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":238,"price":228,"shippingFee":10,"differencePrice":-238,"GoodsUrl":"https://book.kongfz.com/388938/5635734530","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedacdfd/776fd9e3856a5399_b.jpg","GoodsImgCount":"4","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564061128","title":"聪明的女人不生气","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.48,"price":0.48,"shippingFee":3,"differencePrice":-3.48,"GoodsUrl":"https://book.kongfz.com/566350/8631713045","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcccbcda/e73ef67510e788b8_b.jpg","GoodsImgCount":"9","onSaleCount":175,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539272757","title":"货币哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.35,"price":32.35,"shippingFee":5,"differencePrice":-37.35,"GoodsUrl":"https://book.kongfz.com/403679/8309828791","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F8/D9/p4YBAFqZU3CAcNrGAACsHGgv654706_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787532775903","title":"竞艳(永井荷风小说精选)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":18,"shippingFee":0,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/274136/6161792990","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdcbddc/2a54d839359d76b4_b.jpg","GoodsImgCount":"11","onSaleCount":39,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787117308953","title":"人卫版 考试达人 2021全国护师资格考试 随身记 2021新版 职称考试","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.57,"price":0.57,"shippingFee":4,"differencePrice":-4.57,"GoodsUrl":"https://book.kongfz.com/692632/8421322348","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcdfbba/af38ab15b897f2a2_b.jpg","GoodsImgCount":"1","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787545206647","title":"狩魔手记 No. 3:在光与暗之间","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":6,"shippingFee":8,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/80269/8337622370","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3306/02d1a0dc6ad04aec0f_b.jpg","GoodsImgCount":"6","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513245272","title":"中草药的美丽传说 读故事知中医丛书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.31,"price":8.81,"shippingFee":4.5,"differencePrice":-13.31,"GoodsUrl":"https://book.kongfz.com/263924/8359098604","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/accbccaa/71741a85ae819b1a_b.jpg","GoodsImgCount":"1","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787209091251","title":"明代朝鲜使臣胶东纪行诗探析","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/27544/2973684514","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3630/0322c3fee2285943c6_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787204010592","title":"八仙醉行剑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":64.7,"price":54.7,"shippingFee":10,"differencePrice":-64.7,"GoodsUrl":"https://book.kongfz.com/832982/7421669386","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22231533/acc445679116fa70_b.jpg","GoodsImgCount":"2","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111611455","title":"体验式零售樊文花3000家连锁店的奥秘 刘琼雄著 机械工业出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":0.4,"shippingFee":5,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/910533/8534925404","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedfbefa/e9108bf55a3c5726_b.jpg","GoodsImgCount":"1","onSaleCount":165,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787567529731","title":"美学是未来的教育学德育世界的探寻 檀传宝著 上海 华东师范大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":62,"price":57,"shippingFee":5,"differencePrice":-62,"GoodsUrl":"https://book.kongfz.com/910533/8594193674","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdfeffa/d771f7f1133412b9_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559840653","title":"法哲学沉思录(增订注释版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42.88,"price":32.88,"shippingFee":10,"differencePrice":-42.88,"GoodsUrl":"https://book.kongfz.com/795574/8482826703","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/2498932/25a228594e7c8698_b.jpg","GoodsImgCount":"1","onSaleCount":86,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501209880","title":"信主独一 伊斯兰教","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.740000000000002,"price":14.74,"shippingFee":5,"differencePrice":-19.740000000000002,"GoodsUrl":"https://book.kongfz.com/802508/8561749878","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/feedacfa/144d6e447f607a6f_b.jpg","GoodsImgCount":"1","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020064304","title":"刘白羽散文:插图珍藏版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/16713/7428025070","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1825943/089638a0dcdcc20c_b.jpg","GoodsImgCount":"3","onSaleCount":35,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787536030497","title":"非神化","quality":0,"qualityText":"","originalPrice":0,"totalPrice":17.97,"price":13.97,"shippingFee":4,"differencePrice":-17.97,"GoodsUrl":"https://book.kongfz.com/797722/8362753281","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cadeaadd/b275ab6824ca0dc7_b.jpg","GoodsImgCount":"4","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562488002","title":"工程造价确定与控制 第7版吴学伟 谭德精 郑文建 主编重庆大学出版社9787562488002","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.7,"price":3.7,"shippingFee":0,"differencePrice":-3.7,"GoodsUrl":"https://book.kongfz.com/366030/8613584644","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11311919/7028af8b53465ac6_b.jpg","GoodsImgCount":"1","onSaleCount":148,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540783884","title":"溺水者","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.5,"price":8,"shippingFee":2.5,"differencePrice":-10.5,"GoodsUrl":"https://book.kongfz.com/361618/7588004292","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfcbcdb/d4f4881569709583_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040458749","title":"2017年 全国硕士研究生招生考试法律硕士","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4,"price":1,"shippingFee":3,"differencePrice":-4,"GoodsUrl":"https://book.kongfz.com/684559/8441884801","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bacbeaac/97523a1d94c76d53_b.jpg","GoodsImgCount":"2","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214049544","title":"中华帝国的法律","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":16,"shippingFee":6,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/61222/8696597261","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceccaadf/3fa7aa8a06b334c7_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562440673","title":"会展项目策划与组织9787562440673","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.4,"price":5.4,"shippingFee":0,"differencePrice":-5.4,"GoodsUrl":"https://book.kongfz.com/797928/7133987476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/21491677/092f9249b4885775_b.jpg","GoodsImgCount":"1","onSaleCount":25,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807348566","title":"水利水电工程专业案例应试辅导与习题集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36.97,"price":33.17,"shippingFee":3.8,"differencePrice":-36.97,"GoodsUrl":"https://book.kongfz.com/717628/8773851320","imgBigUrl":"https://www0.kfzimg.com/G06/M00/91/5F/p4YBAFrJoHGALyMyAABxymwcVA4723_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560017181","title":"汉英口译入门","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.98,"price":5.48,"shippingFee":2.5,"differencePrice":-7.98,"GoodsUrl":"https://book.kongfz.com/749193/8497283264","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbbfadec/40d5813e2d448723_b.jpg","GoodsImgCount":"2","onSaleCount":65,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508690469","title":"切尔诺贝利的祭祷 斯韦特兰娜 亚历山德罗夫娜 阿列克谢耶维著 孙 中信出版集团 中信出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.6,"price":5.6,"shippingFee":5,"differencePrice":-10.6,"GoodsUrl":"https://book.kongfz.com/398369/8732751738","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecaebbb/61df20b5adc43022_b.jpg","GoodsImgCount":"1","onSaleCount":343,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538465365","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122177568","title":"3天完成超人气简单钩针编织披肩 围巾 毛衣","quality":0,"qualityText":"","originalPrice":0,"totalPrice":27.73,"price":22.73,"shippingFee":5,"differencePrice":-27.73,"GoodsUrl":"https://book.kongfz.com/798596/8841462997","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fecedfec/0acd92a7b4e82865_b.jpg","GoodsImgCount":"1","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802515062","title":"30天精通哲学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.65,"price":3.65,"shippingFee":4,"differencePrice":-7.65,"GoodsUrl":"https://book.kongfz.com/841736/7819318114","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffbadeae/97389454709a0395_b.jpg","GoodsImgCount":"1","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531339038","title":"小阿卡那王国的十二天 塔罗牌的冒险游戏 3 李榕 春风文艺出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41,"price":36,"shippingFee":5,"differencePrice":-41,"GoodsUrl":"https://book.kongfz.com/398369/8525948579","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdbdaaef/502feffcdc5a83f2_b.jpg","GoodsImgCount":"1","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802545137","title":"宗教团体教规制度汇编","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.3,"price":3.5,"shippingFee":3.8,"differencePrice":-7.3,"GoodsUrl":"https://book.kongfz.com/570268/4507336198","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aebfbafd/f0e5c62ff57592db_b.jpg","GoodsImgCount":"3","onSaleCount":78,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559830425","title":"致一百年以后的你:茨维塔耶娃诗选(布罗茨基和帕斯捷尔纳克推崇备至,虚伪年代里她发出了天上真理的声音)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":37.6,"price":37.6,"shippingFee":0,"differencePrice":-37.6,"GoodsUrl":"https://book.kongfz.com/464998/5836803688","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dadefded/38fcb773d15f75f9_b.jpg","GoodsImgCount":"3","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513276764","title":"正版中医经典能力等级考试学习备要 一二级 大学教材 对一二级全部条文中的关键知识点进行规范解读 经典条文全解中国中医药出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":72,"price":64,"shippingFee":8,"differencePrice":-72,"GoodsUrl":"https://book.kongfz.com/667710/8264576689","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/17848986/06d71c99a14262d1_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020070985","title":"名著名译插图本:格林童话全集","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.92,"price":4.92,"shippingFee":5,"differencePrice":-9.92,"GoodsUrl":"https://book.kongfz.com/481057/8714237544","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdeddecc/130f2902b9a8a4c3_b.jpg","GoodsImgCount":"1","onSaleCount":43,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787569901856","title":"论重要之事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":22,"shippingFee":8,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/665570/8689983587","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daaddebc/4d6909ac7a702e44_b.jpg","GoodsImgCount":"4","onSaleCount":56,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533073640","title":"中国石刻书法精粹冈山入楞伽经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":47.8,"price":42,"shippingFee":5.8,"differencePrice":-47.8,"GoodsUrl":"https://book.kongfz.com/1120159/8821041704","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdeccece/327c94577b5df77b_b.jpg","GoodsImgCount":"3","onSaleCount":84,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562418863","title":"电脑中文五笔字型编码字典","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6,"price":6,"shippingFee":0,"differencePrice":-6,"GoodsUrl":"https://book.kongfz.com/731554/6197072537","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdadbcae/8248e5748581be30_b.jpg","GoodsImgCount":"4","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530483565","title":"法式烘焙圣经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":18,"shippingFee":4,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/716704/8005098362","imgBigUrl":"https://www0.kfzimg.com/G06/M00/E0/B8/p4YBAFqY5ImAP-xTAAD-aKAGaq0152_b.jpg","GoodsImgCount":"0","onSaleCount":24,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111485681","title":"放空一下,大脑更有活力:发呆或深度睡眠的时间,正是大脑整理信息、巩固记忆的宝贵时刻","quality":0,"qualityText":"","originalPrice":0,"totalPrice":41.58,"price":39.98,"shippingFee":1.6,"differencePrice":-41.58,"GoodsUrl":"https://book.kongfz.com/457799/8898556222","imgBigUrl":"https://www0.kfzimg.com/G06/M00/61/B6/p4YBAFqctaaAZShRAAB7qAPX2I4591_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787511702463","title":"一个冬夜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.99,"price":1.01,"shippingFee":2.98,"differencePrice":-3.99,"GoodsUrl":"https://book.kongfz.com/761854/8282360559","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbefaaaa/bdd6bbbf29672624_b.jpg","GoodsImgCount":"2","onSaleCount":73,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801305312","title":"图解住宅禁忌","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":4,"shippingFee":10,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/289461/8750166897","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbfeada/ff4d3e78ae4f33e4_b.jpg","GoodsImgCount":"4","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559052407","title":"儿童权利宣言","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/302893/3001668407","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/390/4cdb424a175a6bc1_b.jpg","GoodsImgCount":"1","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539967486","title":"波吉亚家族","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42,"price":34,"shippingFee":8,"differencePrice":-42,"GoodsUrl":"https://book.kongfz.com/316589/8786458274","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecefce/858ca722b85e3531_b.jpg","GoodsImgCount":"11","onSaleCount":63,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115227409","title":"FPGA应用开发入门与典型实例","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24.9,"price":24.9,"shippingFee":0,"differencePrice":-24.9,"GoodsUrl":"https://book.kongfz.com/792228/8893341825","imgBigUrl":"https://www0.kfzimg.com/G06/M00/66/FF/p4YBAFql1cSAbYjSAABg-cl_KK8164_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559461674","title":"毛姆短篇小说全集江苏凤凰文艺出版社册第三册","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.9,"price":13.9,"shippingFee":2,"differencePrice":-15.9,"GoodsUrl":"https://book.kongfz.com/769034/8877458642","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecaaea/595a1d153417c057_b.jpg","GoodsImgCount":"4","onSaleCount":147,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787563801084","title":"如何正确购买股票","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.39,"price":0.39,"shippingFee":6,"differencePrice":-6.39,"GoodsUrl":"https://book.kongfz.com/732025/7658617884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aafdfdfa/3a4f774764fbc683_b.jpg","GoodsImgCount":"14","onSaleCount":6,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500303176","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560036908","title":"蓝宝伴侣:GRE词汇逆序突破肖静波 杨媚","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":10,"shippingFee":0,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/576646/8181293652","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeeefbdd/fc709d318be41ab9_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506313803","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544717991","title":"译林名著精选:童年《图片实拍》","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.49,"price":1.49,"shippingFee":2,"differencePrice":-3.49,"GoodsUrl":"https://book.kongfz.com/892872/8841398697","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eacfdfcc/665f0977eb140373_b.jpg","GoodsImgCount":"5","onSaleCount":344,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787811002201","title":"羽毛球教学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":75.72,"price":63.72,"shippingFee":12,"differencePrice":-75.72,"GoodsUrl":"https://book.kongfz.com/876767/7810979890","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/22552668/642a62ea85b3b7ad_b.jpg","GoodsImgCount":"2","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787533290221","title":"阳光姐姐小书房-补习班的毕业狗","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.59,"price":0.59,"shippingFee":3,"differencePrice":-3.59,"GoodsUrl":"https://book.kongfz.com/891713/7982111525","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bdcebace/2f1de291a31baeb2_b.jpg","GoodsImgCount":"4","onSaleCount":212,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553332925","title":"看晚风吹动香椿树","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":7,"shippingFee":7,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/906778/8175138950","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/17787432/b4ed61571e964018_b.jpg","GoodsImgCount":"4","onSaleCount":9,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535715807","title":"时间之箭:揭开时间最大奥秘之科旅程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":3.8,"shippingFee":0,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/437976/8789758974","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdbbedba/b68db3d7454fdc01_b.jpg","GoodsImgCount":"4","onSaleCount":639,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518426096","title":"非瘦不可","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":4,"shippingFee":6,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/191396/8547026612","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbadccb/53f868482c984b7e_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229011338","title":"夫妻按摩保健图解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":10,"shippingFee":5,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/3092/8222548065","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dffedfea/afe59603b8ebe5ee_b.jpg","GoodsImgCount":"6","onSaleCount":26,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787113276508","title":"股市稳定盈利——寻找最小阻力位9787113276508毕文锋中国铁道出","quality":0,"qualityText":"","originalPrice":0,"totalPrice":36.8,"price":34.3,"shippingFee":2.5,"differencePrice":-36.8,"GoodsUrl":"https://book.kongfz.com/1092759/8885035777","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebacebce/399a4692deda6697_b.jpg","GoodsImgCount":"1","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521719208","title":"通往衰败之路经济学如何掌控我们的生活","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/825106/7894333431","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcffaffb/546c29ed56f49d38_b.jpg","GoodsImgCount":"6","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787122339980","title":"抗癌秘验方(第3版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.38,"price":8.38,"shippingFee":3,"differencePrice":-11.38,"GoodsUrl":"https://book.kongfz.com/902124/8346316359","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcdbacbe/405f74ef1d91f332_b.jpg","GoodsImgCount":"8","onSaleCount":146,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300112275","title":"普通公司法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":160,"price":150,"shippingFee":10,"differencePrice":-160,"GoodsUrl":"https://book.kongfz.com/593645/8588413426","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deacbcff/f813861f1b55e16a_b.jpg","GoodsImgCount":"30","onSaleCount":29,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787551101455","title":"幼儿衔接训练营数学 10以内数的加减法","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.36,"price":0.36,"shippingFee":5,"differencePrice":-5.36,"GoodsUrl":"https://book.kongfz.com/805022/8818083745","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/effcbfda/26f92cfd9c8dd9a7_b.jpg","GoodsImgCount":"1","onSaleCount":150,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501965281","title":"透视课堂","quality":0,"qualityText":"","originalPrice":0,"totalPrice":38.879999999999995,"price":28.88,"shippingFee":10,"differencePrice":-38.879999999999995,"GoodsUrl":"https://book.kongfz.com/795093/8817748428","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edbddced/3cc78a67adce3057_b.jpg","GoodsImgCount":"14","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522615448","title":"系统架构设计师考试32小时通关","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.18,"price":16.18,"shippingFee":5,"differencePrice":-21.18,"GoodsUrl":"https://book.kongfz.com/893135/8183887786","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcdedeed/82c6861b1cb9f559_b.jpg","GoodsImgCount":"1","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535446732","title":"跟谁较劲","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.24,"price":2.74,"shippingFee":1.5,"differencePrice":-4.24,"GoodsUrl":"https://book.kongfz.com/774690/8186965131","imgBigUrl":"https://www0.kfzimg.com/G06/M00/D8/C3/p4YBAFqYxLeAD1cDAAC30cOaVPw558_b.jpg","GoodsImgCount":"1","onSaleCount":338,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787224085945","title":"白纪年","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":14,"shippingFee":8,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/608824/8429279676","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acfbdebf/bee101b98e926b96_b.jpg","GoodsImgCount":"10","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521754247","title":"价值投费3.0","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":20,"shippingFee":10,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/813529/7760121091","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/9937843/6f65ca503c24bca1_b.jpg","GoodsImgCount":"1","onSaleCount":137,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787115602602","title":"AI医学图像处理杨慧芳人民邮电出版社9787115602602","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.76,"price":29.76,"shippingFee":0,"differencePrice":-29.76,"GoodsUrl":"https://book.kongfz.com/248516/8801231646","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/000b6943df4e0b96_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534785375","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801716088","title":"中国现代小说经典文库:刘云若","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.01,"price":0.01,"shippingFee":3,"differencePrice":-3.01,"GoodsUrl":"https://book.kongfz.com/581989/6091380883","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddeadba/bad6dfa20af585fa_b.jpg","GoodsImgCount":"5","onSaleCount":727,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111673835","title":"汽车底盘振动与噪声控制","quality":0,"qualityText":"","originalPrice":0,"totalPrice":108,"price":96,"shippingFee":12,"differencePrice":-108,"GoodsUrl":"https://book.kongfz.com/594145/6738070561","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/beffefff/1b999c09e1bbfc57_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020037155","title":"欧·亨利短篇小说选。","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.89,"price":0.09,"shippingFee":4.8,"differencePrice":-4.89,"GoodsUrl":"https://book.kongfz.com/780405/7571655710","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeebeccd/81c7e5db13f25a44_b.jpg","GoodsImgCount":"4","onSaleCount":131,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561554272","title":"闽南话教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":6,"shippingFee":5,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/365590/6700057055","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbeedbc/ee350c61e535d96a_b.jpg","GoodsImgCount":"4","onSaleCount":87,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559725943","title":"汤汤奇幻童年故事本 注音版:美人树","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.64,"price":10.14,"shippingFee":6.5,"differencePrice":-16.64,"GoodsUrl":"https://book.kongfz.com/758962/8723946119","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afadbfae/be23dd9f6ed74436_b.jpg","GoodsImgCount":"5","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509116418","title":"拔罐疗法治百病(第3版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":6,"shippingFee":8,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/667587/5549578255","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daccdbde/eec7103f90685857_b.jpg","GoodsImgCount":"5","onSaleCount":55,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801797674","title":"周易正义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.9,"price":8.9,"shippingFee":5,"differencePrice":-13.9,"GoodsUrl":"https://book.kongfz.com/261116/8497958314","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdcfebef/ed2a4baa1dece5f9_b.jpg","GoodsImgCount":"1","onSaleCount":158,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787555021933","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500423379","title":"米诺托之恋 32开","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":2,"shippingFee":8,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/2731/8305886847","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbecedaf/fd432f72526a0677_b.jpg","GoodsImgCount":"3","onSaleCount":14,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506546294","title":"兵书与商战:《孙子兵法》在企业经营管理中的应用","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.11,"price":11.11,"shippingFee":3,"differencePrice":-14.11,"GoodsUrl":"https://book.kongfz.com/11070/5792723770","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfcafefb/4267f82702444e97_b.jpg","GoodsImgCount":"2","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802568228","title":"正版 {塑封}凤舞未央:吕雉传.壹[社版] 大爱无痕 9787802568228","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.439999999999998,"price":11.94,"shippingFee":4.5,"differencePrice":-16.439999999999998,"GoodsUrl":"https://book.kongfz.com/8094/8801323849","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceeeeafe/219b26a6d6d8fcd7_b.jpg","GoodsImgCount":"10","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787521424812","title":"《药性歌括四百味》详解","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":15,"shippingFee":8,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/260959/8653606389","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efddfbea/26a0c67edea8a345_b.jpg","GoodsImgCount":"3","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787200026429","title":"佛学精华 下","quality":0,"qualityText":"","originalPrice":0,"totalPrice":53.9,"price":45,"shippingFee":8.9,"differencePrice":-53.9,"GoodsUrl":"https://book.kongfz.com/303525/7008507926","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bddbacda/577a88c16787e620_b.jpg","GoodsImgCount":"15","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559665218","title":"深话浅说,把话说到点子上的超级沟通术!","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.3,"price":15.5,"shippingFee":2.8,"differencePrice":-18.3,"GoodsUrl":"https://book.kongfz.com/41819/8874019077","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/1578691/618e7aa77d18b321_b.jpg","GoodsImgCount":"4","onSaleCount":120,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787551144636","title":"这不是一本科学书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.78,"price":1.78,"shippingFee":5,"differencePrice":-6.78,"GoodsUrl":"https://book.kongfz.com/202798/8898900360","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cdbabbbe/11e45c6436a68d08_b.jpg","GoodsImgCount":"1","onSaleCount":97,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201131634","title":"精简 日式精要主义生活法则","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":3.1,"shippingFee":5,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/1207201/8801526319","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfcdbfe/9c2b3e7d1e41114a_b.jpg","GoodsImgCount":"1","onSaleCount":94,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787201198910","title":"【未翻阅】吕著中国通史:中国政治史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":6,"shippingFee":4,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/578827/8429230684","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/caecbfcf/e01cd053daf6e07a_b.jpg","GoodsImgCount":"2","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539617473","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108032577","title":"仙骨佛心:家具、紫砂与明清文人","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.4,"price":4.4,"shippingFee":10,"differencePrice":-14.4,"GoodsUrl":"https://book.kongfz.com/683738/7098697332","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeceefcb/027ba9058aa5f099_b.jpg","GoodsImgCount":"4","onSaleCount":80,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530948460","title":"西风独自凉","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.99,"price":0.99,"shippingFee":3,"differencePrice":-3.99,"GoodsUrl":"https://book.kongfz.com/903324/8732698209","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdecacaa/5829bc5de36da17a_b.jpg","GoodsImgCount":"5","onSaleCount":256,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787308133326","title":"一本书读懂财报 肖星著 浙江大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.73,"price":7.73,"shippingFee":5,"differencePrice":-12.73,"GoodsUrl":"https://book.kongfz.com/180897/8899723904","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faebfade/22273c2907c42499_b.jpg","GoodsImgCount":"1","onSaleCount":193,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565422034","title":"传媒经济","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29,"price":22,"shippingFee":7,"differencePrice":-29,"GoodsUrl":"https://book.kongfz.com/793471/8403961276","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cedabeae/107e1049b5db2e80_b.jpg","GoodsImgCount":"4","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509664728","title":"大学二级学院院长的角色认知与管理之道","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40.21,"price":36.21,"shippingFee":4,"differencePrice":-40.21,"GoodsUrl":"https://book.kongfz.com/502990/8262079169","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aacadfdd/74291c5b7c3535d5_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787518059195","title":"提高抗挫力培养内心强大的孩子","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":2,"shippingFee":8,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/642191/8020261360","imgBigUrl":"https://www0.kfzimg.com/G07/M00/F3/41/qoYBAFx_IDKAZ76lAAI2qNaQMek283_b.jpg","GoodsImgCount":"1","onSaleCount":56,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787305198632","title":"陶艺设计 陈卢鹏 南京大学出版社 9787305198632","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.98,"price":3.98,"shippingFee":0,"differencePrice":-3.98,"GoodsUrl":"https://book.kongfz.com/2845/8726272938","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcacebde/e3d61e23ccebbfc2_b.jpg","GoodsImgCount":"1","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787564800994","title":"学校艺术教育60年(1949-2009)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":23,"shippingFee":0,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/544739/4134318917","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbebddbc/11ba1c8ac23ca92d_b.jpg","GoodsImgCount":"9","onSaleCount":10,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787561457207","title":"隐形的尾巴系列:梦中的巨叶 彩图版中英对照","quality":0,"qualityText":"","originalPrice":0,"totalPrice":25,"price":25,"shippingFee":0,"differencePrice":-25,"GoodsUrl":"https://book.kongfz.com/545819/8248024889","imgBigUrl":"https://www0.kfzimg.com/G06/M00/CF/70/p4YBAFqo5jaAXl6NAABP0PiNKsA890_b.jpg","GoodsImgCount":"1","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787520202091","title":"儿童职业启蒙百科长大后我要做什么 陈昕编著 中国大百科全书出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.82,"price":9.82,"shippingFee":5,"differencePrice":-14.82,"GoodsUrl":"https://book.kongfz.com/398369/8780865875","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/deaebdef/cf5e69203d43afc8_b.jpg","GoodsImgCount":"1","onSaleCount":188,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534951978","title":"烘焙新手必备的第一本书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5600000000000005,"price":0.56,"shippingFee":4,"differencePrice":-4.5600000000000005,"GoodsUrl":"https://book.kongfz.com/660948/8726976124","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ebcbcfbd/d44f0b660d82a285_b.jpg","GoodsImgCount":"2","onSaleCount":304,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500410898","title":"社科学术文库:中国革命法制史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.07,"price":13.07,"shippingFee":6,"differencePrice":-19.07,"GoodsUrl":"https://book.kongfz.com/792848/8126466099","imgBigUrl":"https://www0.kfzimg.com/G06/M00/87/CE/p4YBAFrJd_eAVtUOAACH4Dc3UTs299_b.jpg","GoodsImgCount":"1","onSaleCount":74,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214222213","title":"西顿动物故事集/统编语文教材必读名著","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.43,"price":2.43,"shippingFee":3,"differencePrice":-5.43,"GoodsUrl":"https://book.kongfz.com/774181/8781126790","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cabdeeeb/4c70980aa56a6179_b.jpg","GoodsImgCount":"4","onSaleCount":20,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108028167","title":"西班牙","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.1,"price":7.1,"shippingFee":5,"differencePrice":-12.1,"GoodsUrl":"https://book.kongfz.com/802508/8630726160","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dafcfebf/38916c84832bb9e5_b.jpg","GoodsImgCount":"1","onSaleCount":79,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516764589","title":"整理收纳师培训实用教程","quality":0,"qualityText":"","originalPrice":0,"totalPrice":42.68,"price":34.68,"shippingFee":8,"differencePrice":-42.68,"GoodsUrl":"https://book.kongfz.com/158878/8133003913","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4893319/0fc6cd33a6998f78_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535460783","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515509433","title":"实体店这样做绝不输电商:实体店+互联网,这样运营更有效","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.21,"price":4.2,"shippingFee":0.01,"differencePrice":-4.21,"GoodsUrl":"https://book.kongfz.com/171447/8557690684","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efafdcda/e5451ef584b5dac0_b.jpg","GoodsImgCount":"1","onSaleCount":200,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508644660","title":"数据之巅:大数据革命,历史、现实与未来","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.8,"price":0.8,"shippingFee":3,"differencePrice":-3.8,"GoodsUrl":"https://book.kongfz.com/880498/8863679996","imgBigUrl":"https://www0.kfzimg.com/G06/M00/F0/78/p4YBAFqZNLWAH1kmAAGLQlVha0I822_b.jpg","GoodsImgCount":"1","onSaleCount":1923,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108035455","title":"游观美国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":4.2,"shippingFee":3,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/566350/8848525346","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcfdeeae/d8e0990506ae25ee_b.jpg","GoodsImgCount":"5","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515517018","title":"达·芬奇笔记","quality":0,"qualityText":"","originalPrice":0,"totalPrice":28.9,"price":25,"shippingFee":3.9,"differencePrice":-28.9,"GoodsUrl":"https://book.kongfz.com/293289/8863618280","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbdaabce/99e10484c9bb4d68_b.jpg","GoodsImgCount":"1","onSaleCount":82,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787538290554","title":"高中必备古诗文 第4次修订","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.54,"price":0.54,"shippingFee":3,"differencePrice":-3.54,"GoodsUrl":"https://book.kongfz.com/371891/8511078129","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cbadebaa/e65202c29d831318_b.jpg","GoodsImgCount":"3","onSaleCount":91,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208141384","title":"告别霸权 全球体系中的权力与影响力","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15.73,"price":10.73,"shippingFee":5,"differencePrice":-15.73,"GoodsUrl":"https://book.kongfz.com/907853/8590170185","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/adbbedeb/74860687d74261cc_b.jpg","GoodsImgCount":"1","onSaleCount":61,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787030520784","title":"内页干净 数字电子技术基础 第二版","quality":0,"qualityText":"","originalPrice":0,"totalPrice":22,"price":15,"shippingFee":7,"differencePrice":-22,"GoodsUrl":"https://book.kongfz.com/186710/8891553985","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceacecbf/5dc142c596b99bb7_b.jpg","GoodsImgCount":"5","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550017719","title":"答案之书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.32,"price":1.32,"shippingFee":3,"differencePrice":-4.32,"GoodsUrl":"https://book.kongfz.com/566350/8837190195","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aadedfee/a9c15bdf17802e77_b.jpg","GoodsImgCount":"5","onSaleCount":586,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787544282437","title":"点与线【正版书籍,实拍图发货,16点前订单当天发出-1112】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12,"price":2,"shippingFee":10,"differencePrice":-12,"GoodsUrl":"https://book.kongfz.com/1208551/8761113973","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceefdffa/fee05513763e9ffb_b.jpg","GoodsImgCount":"4","onSaleCount":77,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787550106383","title":"卖故事","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.38,"price":4.37,"shippingFee":0.01,"differencePrice":-4.38,"GoodsUrl":"https://book.kongfz.com/877749/8772134551","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/20696186/56f2b8bf0930afe3_b.jpg","GoodsImgCount":"3","onSaleCount":242,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508652801","title":"救命饮食Ⅱ:反思营养学","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19,"price":13,"shippingFee":6,"differencePrice":-19,"GoodsUrl":"https://book.kongfz.com/302512/8854227529","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/daefedee/aa1240d7fc51d6dc_b.jpg","GoodsImgCount":"9","onSaleCount":105,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530838846","title":"长效针灸","quality":0,"qualityText":"","originalPrice":0,"totalPrice":92.62,"price":81.12,"shippingFee":11.5,"differencePrice":-92.62,"GoodsUrl":"https://book.kongfz.com/1121862/8620201407","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/23602004/bc1be7f1013d5f16_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547400289","title":"恐龙宝贝 18失踪的公主.","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/240738/6964968829","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/49/01c16a6e44d6eefc_b.jpg","GoodsImgCount":"5","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787504936004","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787566422859","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802255913","title":"第十二张牌 林肯 莱姆系列之六","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.9,"price":2.9,"shippingFee":5,"differencePrice":-7.9,"GoodsUrl":"https://book.kongfz.com/261116/8727732660","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbffccc/dfc8550b211d9e53_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111331834","title":"(二手书)离散数学 冯伟森栾新成石兵 机械工业出版社 2011年03月01日 9787111331834","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.4,"price":9.4,"shippingFee":4,"differencePrice":-13.4,"GoodsUrl":"https://book.kongfz.com/704408/6180539887","imgBigUrl":"https://www0.kfzimg.com/G06/M00/91/AE/p4YBAFqeLhKAW5d5AADl92ZwcOg893_b.jpg","GoodsImgCount":"1","onSaleCount":19,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300096728","title":"民法典体系研究 王利明著 16开 中国人民大学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.610000000000001,"price":8.21,"shippingFee":2.4,"differencePrice":-10.610000000000001,"GoodsUrl":"https://book.kongfz.com/691158/8420929169","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bfbdcbac/d39298c4ffe420f0_b.jpg","GoodsImgCount":"1","onSaleCount":33,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534487484","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514857719","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787517057314","title":"中文版AutoCAD 2018从入门到精通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.04,"price":3.04,"shippingFee":2,"differencePrice":-5.04,"GoodsUrl":"https://book.kongfz.com/624177/8858791962","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eeabffeb/61322e6d9183c96c_b.jpg","GoodsImgCount":"2","onSaleCount":174,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559662897","title":"你可以链接任何人","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":3,"shippingFee":6,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/718390/8279878590","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cebadccd/f3d70455d1372df0_b.jpg","GoodsImgCount":"9","onSaleCount":214,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787539861753","title":"经典碑帖笔法临析大全:汉 张迁碑","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":25,"shippingFee":5,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/626307/8191067601","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ceecbcfd/5a4122d8aacde8e1_b.jpg","GoodsImgCount":"3","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214022448","title":"走出蒙昧","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.09,"price":2.09,"shippingFee":3,"differencePrice":-5.09,"GoodsUrl":"https://book.kongfz.com/880498/8552588955","imgBigUrl":"https://www0.kfzimg.com/G06/M00/4C/C2/p4YBAFqbzkiANU8yAABXKCNtm0I243_b.jpg","GoodsImgCount":"1","onSaleCount":100,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801820716","title":"034-最高人民法院关于审理未成年人刑事案件的若干规定——司法解释配套规定(30)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8,"price":3,"shippingFee":5,"differencePrice":-8,"GoodsUrl":"https://book.kongfz.com/773547/8882061995","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abcbedbe/3f86089883b36df9_b.jpg","GoodsImgCount":"3","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565603785","title":"高中地理知识清单第七次修订","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.9099999999999997,"price":0.11,"shippingFee":3.8,"differencePrice":-3.9099999999999997,"GoodsUrl":"https://book.kongfz.com/237705/8296401548","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/becedeca/85f3d8d0cf0507fc_b.jpg","GoodsImgCount":"1","onSaleCount":312,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300227931","title":"摇滚狂人:奥兹·奥斯本自传","quality":0,"qualityText":"","originalPrice":0,"totalPrice":357.93,"price":347.93,"shippingFee":10,"differencePrice":-357.93,"GoodsUrl":"https://book.kongfz.com/885269/8721211625","imgBigUrl":"https://www0.kfzimg.com/G06/M00/C6/CD/p4YBAFqYPm6AA58NAADmk-bczug630_b.jpg","GoodsImgCount":"1","onSaleCount":7,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787040165333","title":"服装缝制工艺","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.030000000000001,"price":4.03,"shippingFee":5,"differencePrice":-9.030000000000001,"GoodsUrl":"https://book.kongfz.com/234408/8617852599","imgBigUrl":"https://www0.kfzimg.com/G06/M00/49/E5/p4YBAFqklnyAOs0PAADPm0kfy34750_b.jpg","GoodsImgCount":"1","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787805260341","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787540756369","title":"我的教育思考:李镇西30年教育感悟精华","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10,"price":5,"shippingFee":5,"differencePrice":-10,"GoodsUrl":"https://book.kongfz.com/244916/7101323168","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbddcdee/0b130d050743b880_b.jpg","GoodsImgCount":"3","onSaleCount":85,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506318037","title":"庞中华书法百日通","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.8,"price":1.8,"shippingFee":5,"differencePrice":-6.8,"GoodsUrl":"https://book.kongfz.com/1207201/8872215438","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acadcfea/50504c6043d60888_b.jpg","GoodsImgCount":"1","onSaleCount":118,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534865725","title":"【正版库存书,无写划,当天发货】候气术-古人观念中天地人之纽带","quality":0,"qualityText":"","originalPrice":0,"totalPrice":49,"price":39,"shippingFee":10,"differencePrice":-49,"GoodsUrl":"https://book.kongfz.com/792783/8292451687","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdffeffa/1d238d1e8b570fc8_b.jpg","GoodsImgCount":"2","onSaleCount":12,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309141238","title":"媒介考古学:方法、路径和意涵","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.3,"price":37.8,"shippingFee":1.5,"differencePrice":-39.3,"GoodsUrl":"https://book.kongfz.com/772556/8643035154","imgBigUrl":"https://www0.kfzimg.com/G07/M00/74/9F/q4YBAFy9za6APejXAACbgxAfVOA618_b.jpg","GoodsImgCount":"1","onSaleCount":46,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807492078","title":"中国油灯","quality":0,"qualityText":"","originalPrice":0,"totalPrice":24,"price":19,"shippingFee":5,"differencePrice":-24,"GoodsUrl":"https://book.kongfz.com/3092/8404148550","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abdafddd/ae84e3b815c551f1_b.jpg","GoodsImgCount":"5","onSaleCount":28,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535558121","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787100047944","title":"现代汉语词典 大字本【第5版】","quality":0,"qualityText":"","originalPrice":0,"totalPrice":46.2,"price":43.2,"shippingFee":3,"differencePrice":-46.2,"GoodsUrl":"https://book.kongfz.com/567465/8684141730","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afeacdfc/27dbc7df6e4790d0_b.jpg","GoodsImgCount":"11","onSaleCount":47,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787214061652","title":"[正版现货实拍]左与右","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":25,"shippingFee":5,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/593972/8831688302","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fabcbffc/6acb11c332afb1ac_b.jpg","GoodsImgCount":"2","onSaleCount":34,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787565645136","title":"理想树2019新版 高考必刷题 化学合订本 67高考总复?习辅导用书","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.23,"price":0.23,"shippingFee":4,"differencePrice":-4.23,"GoodsUrl":"https://book.kongfz.com/841736/7806737988","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eacfdcfc/d53e57da439477b1_b.jpg","GoodsImgCount":"1","onSaleCount":170,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301327678","title":"手机摄影从入门到精通(视频教程版)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.96,"price":4.96,"shippingFee":3,"differencePrice":-7.96,"GoodsUrl":"https://book.kongfz.com/814259/7155878213","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/11956018/23ecdf560f51fc15_b.jpg","GoodsImgCount":"0","onSaleCount":151,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501242757","title":"稳行高处","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16.29,"price":11.29,"shippingFee":5,"differencePrice":-16.29,"GoodsUrl":"https://book.kongfz.com/202798/8790783794","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acdeeabf/f0e02fb82665f1a7_b.jpg","GoodsImgCount":"1","onSaleCount":42,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516147948","title":"雷州文化概论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.85,"price":5.35,"shippingFee":5.5,"differencePrice":-10.85,"GoodsUrl":"https://book.kongfz.com/673095/8836493176","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eadccdee/b6cdf1498eaa5a5d_b.jpg","GoodsImgCount":"1","onSaleCount":66,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787307196872","title":"西线空战:二战德国空军第26战斗机联队战史","quality":0,"qualityText":"","originalPrice":0,"totalPrice":34,"price":28,"shippingFee":6,"differencePrice":-34,"GoodsUrl":"https://book.kongfz.com/255987/6951927055","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcffded/00890ff233c0e961_b.jpg","GoodsImgCount":"8","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535729309","title":"中国湘菜湘点.地方菜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":6,"shippingFee":10,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/794521/8854071538","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddbfdcdd/ce5af34277bfbf6d_b.jpg","GoodsImgCount":"15","onSaleCount":21,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787103027660","title":"音乐学:历史、文献与写作","quality":0,"qualityText":"","originalPrice":0,"totalPrice":19.97,"price":17.97,"shippingFee":2,"differencePrice":-19.97,"GoodsUrl":"https://book.kongfz.com/877749/8009479476","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccadfcdd/59e0599bef87bcc2_b.jpg","GoodsImgCount":"2","onSaleCount":40,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787537402484","title":"枭雄百传第三部12世界政坛枭雄之一","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.5,"price":1.5,"shippingFee":3,"differencePrice":-4.5,"GoodsUrl":"https://book.kongfz.com/500139/6001151895","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffddfbcc/623f0323273297b1_b.jpg","GoodsImgCount":"4","onSaleCount":217,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787514803723","title":"幼儿文学百年经典:科学 和风卷","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.1,"price":6.6,"shippingFee":2.5,"differencePrice":-9.1,"GoodsUrl":"https://book.kongfz.com/836247/7706451696","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdcfebeb/2055a85b2f62f6cc_b.jpg","GoodsImgCount":"2","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505135482","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010223445","title":"共产党执政规律研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.09,"price":0.09,"shippingFee":5,"differencePrice":-5.09,"GoodsUrl":"https://book.kongfz.com/23607/8529134364","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ddcececa/931db1e7f06bbbb1_b.jpg","GoodsImgCount":"1","onSaleCount":324,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787506085892","title":"指月录","quality":0,"qualityText":"","originalPrice":0,"totalPrice":30,"price":24,"shippingFee":6,"differencePrice":-30,"GoodsUrl":"https://book.kongfz.com/715232/8775324286","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efffcbfb/ac5bb42fd1eb8cfd_b.jpg","GoodsImgCount":"8","onSaleCount":174,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787535457646","title":"蒙曼说隋(下):隋炀帝杨广","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14.4,"price":11.5,"shippingFee":2.9,"differencePrice":-14.4,"GoodsUrl":"https://book.kongfz.com/566350/8780637754","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dfaffafa/7c735695c0ad2658_b.jpg","GoodsImgCount":"8","onSaleCount":111,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787508617930","title":"一分钟百万富翁","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.5,"price":5,"shippingFee":5.5,"differencePrice":-10.5,"GoodsUrl":"https://book.kongfz.com/78763/8656091664","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fdeffaeb/f97188c16b7bdf05_b.jpg","GoodsImgCount":"4","onSaleCount":100,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787301317273","title":"中华茶文化概论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.58,"price":9.58,"shippingFee":0,"differencePrice":-9.58,"GoodsUrl":"https://book.kongfz.com/22758/8269768638","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3159/02b0e79a478be0806a_b.jpg","GoodsImgCount":"1","onSaleCount":92,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802011540","title":"书法碑帖 墨迹精印 隋 智永真草千字文 姚建杭 中国和平出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.9,"price":5.9,"shippingFee":5,"differencePrice":-10.9,"GoodsUrl":"https://book.kongfz.com/910533/8841066585","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/decdeecf/5b9eb240e4cf2f07_b.jpg","GoodsImgCount":"1","onSaleCount":156,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516927304","title":"传奇如谜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":32.29,"price":25.29,"shippingFee":7,"differencePrice":-32.29,"GoodsUrl":"https://book.kongfz.com/238778/8228231786","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/16915416/c05e7a1b0d97ccac_b.jpg","GoodsImgCount":"1","onSaleCount":15,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787208018907","title":"中国的奇迹:发展战略与经济改革","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.72,"price":1.72,"shippingFee":5,"differencePrice":-6.72,"GoodsUrl":"https://book.kongfz.com/890432/8720058621","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/eddecacc/fa7dcc44fce0b0a5_b.jpg","GoodsImgCount":"1","onSaleCount":130,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787110059753","title":"海洋","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9,"price":6,"shippingFee":3,"differencePrice":-9,"GoodsUrl":"https://book.kongfz.com/838443/8896001587","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dbbbbded/5ca2371ad0f6c234_b.jpg","GoodsImgCount":"1","onSaleCount":109,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531358305","title":"萧军萧红交游考释","quality":0,"qualityText":"","originalPrice":0,"totalPrice":14,"price":9.6,"shippingFee":4.4,"differencePrice":-14,"GoodsUrl":"https://book.kongfz.com/321650/8279664994","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3974/037bf1538f5fc99ac7_b.jpg","GoodsImgCount":"1","onSaleCount":83,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513335157","title":"最后的守护者","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.5,"price":32,"shippingFee":7.5,"differencePrice":-39.5,"GoodsUrl":"https://book.kongfz.com/161407/7322660044","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcbfcceb/aaaede1c711ebe7a_b.jpg","GoodsImgCount":"5","onSaleCount":11,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787802257313","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787801410016","title":"台湾史志","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.73,"price":1.73,"shippingFee":5,"differencePrice":-6.73,"GoodsUrl":"https://book.kongfz.com/798675/8040942996","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaaaefed/232c9fe6560dc0d3_b.jpg","GoodsImgCount":"1","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572606052","title":"拉塞-玛娅侦探所 第三辑 自行车迷案","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.890000000000001,"price":2.89,"shippingFee":2,"differencePrice":-4.890000000000001,"GoodsUrl":"https://book.kongfz.com/769044/8524727079","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faafecfc/2145ab50be5e1ccf_b.jpg","GoodsImgCount":"2","onSaleCount":229,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787572231353","title":"咖啡帝国","quality":0,"qualityText":"","originalPrice":0,"totalPrice":51,"price":36,"shippingFee":15,"differencePrice":-51,"GoodsUrl":"https://book.kongfz.com/649298/8649997321","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acbaefcf/9704f4aa5c669110_b.jpg","GoodsImgCount":"7","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787515807263","title":"茶铎八音","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7,"price":2,"shippingFee":5,"differencePrice":-7,"GoodsUrl":"https://book.kongfz.com/261116/8559980205","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/addcaffe/b756d1e8b0eeafb9_b.jpg","GoodsImgCount":"1","onSaleCount":106,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787562010326","title":"公司法论","quality":0,"qualityText":"","originalPrice":0,"totalPrice":29.9,"price":27.9,"shippingFee":2,"differencePrice":-29.9,"GoodsUrl":"https://book.kongfz.com/241290/8326980017","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfcfccbf/eed05bc7c12dd20f_b.jpg","GoodsImgCount":"4","onSaleCount":32,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787554513514","title":"记忆传授人:“记忆传授人”四部曲 1","quality":0,"qualityText":"","originalPrice":0,"totalPrice":15,"price":5,"shippingFee":10,"differencePrice":-15,"GoodsUrl":"https://book.kongfz.com/661692/8614596277","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcabcada/0013bde7267e5d37_b.jpg","GoodsImgCount":"3","onSaleCount":94,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787309168846","title":"婴幼儿保教综合实训","quality":0,"qualityText":"","originalPrice":0,"totalPrice":26.24,"price":24.24,"shippingFee":2,"differencePrice":-26.24,"GoodsUrl":"https://book.kongfz.com/472611/8823269026","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fadceaad/f662f7d243246515_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787531825494","title":"乌龙院大长篇漫画系列","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11,"price":5,"shippingFee":6,"differencePrice":-11,"GoodsUrl":"https://book.kongfz.com/410862/8714471607","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/aaafbdbb/2b9d0462e1b8b767_b.jpg","GoodsImgCount":"3","onSaleCount":13,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787807408550","title":"正版实拍 下厨记 III","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5.13,"price":0.13,"shippingFee":5,"differencePrice":-5.13,"GoodsUrl":"https://book.kongfz.com/400965/8873428467","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efdcafef/08f462f18045e276_b.jpg","GoodsImgCount":"1","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787209126441","title":"不购买的习惯 日 金子由纪子著 山东人民出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":11.2,"price":6.2,"shippingFee":5,"differencePrice":-11.2,"GoodsUrl":"https://book.kongfz.com/910533/8800769752","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcdaadad/ce4e50b49763be2f_b.jpg","GoodsImgCount":"1","onSaleCount":105,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787501172740","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787530652817","title":"小说月报:412期","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.1,"price":5.8,"shippingFee":2.3,"differencePrice":-8.1,"GoodsUrl":"https://book.kongfz.com/364403/4247581312","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/3367/02e16f42ee18f1dbd6_b.jpg","GoodsImgCount":"4","onSaleCount":58,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787218120232","title":"梁冬说庄子 养生主","quality":0,"qualityText":"","originalPrice":0,"totalPrice":9.8,"price":3.8,"shippingFee":6,"differencePrice":-9.8,"GoodsUrl":"https://book.kongfz.com/914189/8243318884","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abefeddf/2c6a08c3f4dc1ba2_b.jpg","GoodsImgCount":"9","onSaleCount":185,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787111439066","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787213112072","title":"财之道丛书·奥地利学派经济学简史:米塞斯的视角","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.4,"price":8,"shippingFee":10.4,"differencePrice":-18.4,"GoodsUrl":"https://book.kongfz.com/668091/8661535563","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fbbfadfd/b4493c0b0d8ea96a_b.jpg","GoodsImgCount":"10","onSaleCount":121,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787522500522","title":"正版现货桑梓誉重归名宗陈新森主编9787522500522新华仓库多仓直发","quality":0,"qualityText":"","originalPrice":0,"totalPrice":13.16,"price":9.16,"shippingFee":4,"differencePrice":-13.16,"GoodsUrl":"https://book.kongfz.com/170527/8156889048","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cddfebdd/32e201fc94025693_b.jpg","GoodsImgCount":"1","onSaleCount":52,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787020017232","title":"《发货快》忏悔录 [法]卢梭 著,范希衡 译 人民文学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":8.07,"price":7.57,"shippingFee":0.5,"differencePrice":-8.07,"GoodsUrl":"https://book.kongfz.com/156492/8384830037","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/4362605/38ec4061f3fe6f66_b.jpg","GoodsImgCount":"1","onSaleCount":138,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787229081799","title":"生态文明:人类历史发展的必然选择(32开平装 全1册)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18.41,"price":12.41,"shippingFee":6,"differencePrice":-18.41,"GoodsUrl":"https://book.kongfz.com/669893/8313786940","imgBigUrl":"https://www0.kfzimg.com/G06/M00/25/C9/p4YBAFsMoJSAPkWRAABSFJoSyoY034_b.jpg","GoodsImgCount":"1","onSaleCount":8,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500872535","title":"我们的青春","quality":0,"qualityText":"","originalPrice":0,"totalPrice":12.39,"price":6.4,"shippingFee":5.99,"differencePrice":-12.39,"GoodsUrl":"https://book.kongfz.com/468773/6807539323","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bedbcadb/3b900667369fa822_b.jpg","GoodsImgCount":"3","onSaleCount":62,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519445454","title":"2020年山西省普通高校专升本考试专用教材英语山西省在校专升本研究组/光明日报出版社9787519445454","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.9,"price":10.9,"shippingFee":0,"differencePrice":-10.9,"GoodsUrl":"https://book.kongfz.com/248516/8585444909","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/8042428/a64c0e9c50f98710_b.jpg","GoodsImgCount":"1","onSaleCount":36,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787559801791","title":"汉文佛教文献研究 佛教文献研究译丛","quality":0,"qualityText":"","originalPrice":0,"totalPrice":55,"price":45,"shippingFee":10,"differencePrice":-55,"GoodsUrl":"https://book.kongfz.com/403/8540586001","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cfbfdeaa/d8216b91b56cedb8_b.jpg","GoodsImgCount":"2","onSaleCount":31,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787302476160","title":"系统规划与管理师教程(全国计算机技术与软件专业技术资格(水平)考试指定用书)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":7.2,"price":2.2,"shippingFee":5,"differencePrice":-7.2,"GoodsUrl":"https://book.kongfz.com/398369/8197191369","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/baccedbc/5d9742e389b4a01e_b.jpg","GoodsImgCount":"1","onSaleCount":203,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787516810637","title":"儿童的人格教育","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.75,"price":1.75,"shippingFee":3,"differencePrice":-4.75,"GoodsUrl":"https://book.kongfz.com/783956/8696984436","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/faeadeea/927cdef692f8076a_b.jpg","GoodsImgCount":"1","onSaleCount":210,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787513930970","title":"特殊罪案调查组2","quality":0,"qualityText":"","originalPrice":0,"totalPrice":10.82,"price":5.82,"shippingFee":5,"differencePrice":-10.82,"GoodsUrl":"https://book.kongfz.com/1092446/8817399954","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bcbdaffb/eda37e39d3acd1ba_b.jpg","GoodsImgCount":"1","onSaleCount":156,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787547405826","title":"金刚经 心经 国学经典读本丛书 金刚经心经","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.65,"price":4.25,"shippingFee":2.4,"differencePrice":-6.65,"GoodsUrl":"https://book.kongfz.com/561672/8830865409","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/dcfcdaca/dc3cf0b7d7e039d5_b.jpg","GoodsImgCount":"1","onSaleCount":86,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787010218908","title":"夏商西周散文传播研究:基于先秦文献的考察","quality":0,"qualityText":"","originalPrice":0,"totalPrice":21.8,"price":16.8,"shippingFee":5,"differencePrice":-21.8,"GoodsUrl":"https://book.kongfz.com/475714/8882481687","imgBigUrl":"https://www0.kfzimg.com/sw/kfzimg/2344/01db6e7c5a748513a1_b.jpg","GoodsImgCount":"1","onSaleCount":30,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787560070216","title":"","quality":0,"qualityText":"","originalPrice":0,"totalPrice":0,"price":0,"shippingFee":0,"differencePrice":0,"GoodsUrl":"","imgBigUrl":"","GoodsImgCount":"","onSaleCount":0,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":0,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787108047052","title":"陈寅恪的最后二十年(修订本)(精装)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":40,"price":35,"shippingFee":5,"differencePrice":-40,"GoodsUrl":"https://book.kongfz.com/626307/8183197623","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/afdbbbfc/492dfd0042fef08c_b.jpg","GoodsImgCount":"3","onSaleCount":114,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787101140521","title":"造物记云南古茶园的秘密","quality":0,"qualityText":"","originalPrice":0,"totalPrice":39.7,"price":37.7,"shippingFee":2,"differencePrice":-39.7,"GoodsUrl":"https://book.kongfz.com/1214248/8773603177","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/cecbdbfd/384816fe4b359bb4_b.jpg","GoodsImgCount":"4","onSaleCount":45,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787505204324","title":"正方.反方.评方--历届大学生辩论会","quality":0,"qualityText":"","originalPrice":0,"totalPrice":5,"price":2,"shippingFee":3,"differencePrice":-5,"GoodsUrl":"https://book.kongfz.com/839152/8830821017","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/fcfefbed/6df83dc8f9f4eb3e_b.jpg","GoodsImgCount":"1","onSaleCount":71,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787107174261","title":"滥觞与辉煌:朱永新教育文集(卷二)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":6.92,"price":3.92,"shippingFee":3,"differencePrice":-6.92,"GoodsUrl":"https://book.kongfz.com/566350/8848531607","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/efededba/8793fe0e5f859d15_b.jpg","GoodsImgCount":"7","onSaleCount":38,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787300085425","title":"经验与理论:中国社会、经济与法律的实践历史研究","quality":0,"qualityText":"","originalPrice":0,"totalPrice":91,"price":85,"shippingFee":6,"differencePrice":-91,"GoodsUrl":"https://book.kongfz.com/26986/8505318233","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ffebaceb/5e665fe35d11e0d6_b.jpg","GoodsImgCount":"4","onSaleCount":41,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553743356","title":"跟着大厨学做宴客菜","quality":0,"qualityText":"","originalPrice":0,"totalPrice":4.99,"price":2.99,"shippingFee":2,"differencePrice":-4.99,"GoodsUrl":"https://book.kongfz.com/779125/8445844689","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/edecdbcb/1f663356d75b3fc1_b.jpg","GoodsImgCount":"1","onSaleCount":227,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787500925774","title":"陈式太极拳精义","quality":0,"qualityText":"","originalPrice":0,"totalPrice":18,"price":8,"shippingFee":10,"differencePrice":-18,"GoodsUrl":"https://book.kongfz.com/204681/8857864879","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/ccecdacf/a4fbff5bf6a42616_b.jpg","GoodsImgCount":"7","onSaleCount":69,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787553924571","title":"20世纪中国科学口述史·走自己的路——吴文俊口述自传(正版\\内页干净\\实物拍摄)","quality":0,"qualityText":"","originalPrice":0,"totalPrice":51,"price":45,"shippingFee":6,"differencePrice":-51,"GoodsUrl":"https://book.kongfz.com/218311/8625508085","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/acddbbcb/1d9a5ae19c383ddb_b.jpg","GoodsImgCount":"4","onSaleCount":18,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787534501043","title":"实用武当气功","quality":0,"qualityText":"","originalPrice":0,"totalPrice":16,"price":9,"shippingFee":7,"differencePrice":-16,"GoodsUrl":"https://book.kongfz.com/14581/8817086084","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/bbccbcbe/ead694ffe452f428_b.jpg","GoodsImgCount":"8","onSaleCount":17,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787509138052","title":"周耀庭讲小儿温病","quality":0,"qualityText":"","originalPrice":0,"totalPrice":23,"price":17,"shippingFee":6,"differencePrice":-23,"GoodsUrl":"https://book.kongfz.com/270515/8661563982","imgBigUrl":"https://www0.kfzimg.com/G07/M00/75/F2/q4YBAFvlRaeAYNaJAABkY-JAiVw250_b.jpg","GoodsImgCount":"1","onSaleCount":23,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0},{"isbn":"9787519122263","title":"【正版二手】大学素养语文第三版金振邦第3版9787519122263教育科学出版社","quality":0,"qualityText":"","originalPrice":0,"totalPrice":3.29,"price":3.29,"shippingFee":0,"differencePrice":-3.29,"GoodsUrl":"https://book.kongfz.com/783101/8471284217","imgBigUrl":"https://www0.kfzimg.com/sw/kfz-cos/kfzimg/abdbfefa/6189125599d2f3e6_b.jpg","GoodsImgCount":"6","onSaleCount":216,"soldCount":0,"shopAvgShippingTime":"","shopSuccessOrderRate":"","dataType":2,"shouldRetry":false,"platformId":0,"skuId":0}],"condition":85,"imageSelect":1,"userId":"1967112570379649025","taskId":"中心书库发布VB_0;BS_0;OMS_0;IllP_0;IA_0;BCS_2,999999;SCS_5,999999;userId_1967112570379649025;rand_1759227336656-3","way":"0"} +【2025-09-30 18:27:08】【返回参数】{"code":"200","success":true,"message":"执行成功"} +【2025-09-30 18:27:09】【日志结束,方法名称:centerBooks】【centerBooksAdd】中心书库发布商品 \ No newline at end of file diff --git a/file/log/centerBooksAdd_1983373997176135681_33.txt b/file/log/centerBooksAdd_1983373997176135681_33.txt new file mode 100644 index 0000000..79d5fd1 --- /dev/null +++ b/file/log/centerBooksAdd_1983373997176135681_33.txt @@ -0,0 +1,5 @@ + +【2026-05-28 15:01:10】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-05-28 15:01: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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":293,"fileName":"task_template_1779944336050.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/4bc95289-eeb0-4722-8531-3deee41a9729_task_template_1779944336050.xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2059892720069992449\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":"1983373997176135681","proportion":100,"addNum":0}],"shopIds":"2059539257909739521","synchronizationType":"1","bookCategory":"0"},"userId":"1983373997176135681"} +【2026-05-28 15:02:23】【返回参数】null +【2026-05-28 15:02:23】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods \ No newline at end of file diff --git a/file/log/centerBooksAdd_1_1.txt b/file/log/centerBooksAdd_1_1.txt new file mode 100644 index 0000000..ad31979 --- /dev/null +++ b/file/log/centerBooksAdd_1_1.txt @@ -0,0 +1,203 @@ + +【2025-09-18 18:03:25】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-18 18:03:26】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1968616845749116930","taskType":"1","shopIds":"1968345938572304386","shopNames":"棵韵KEOYURNE图书旗舰店","fileName":"excel表格上传:知书上货模版 - 副本.xlsx","dataNum":33,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"0","bookCategory":"0","shopIds":"1968345938572304386","data":{"total":33,"fileName":"知书上货模版 - 副本.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1} +【2025-09-18 18:04:13】【系统异常】【异常方法】addGoods +【2025-09-18 18:04:13】【系统异常】【异常内容】java.lang.RuntimeException: java.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:233) + 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.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx + at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:309) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:231) + ... 24 more +Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/b0bb2e99-ba12-440d-b4b2-306abcd2aef3_知书上货模版 - 副本.xlsx + at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:2018) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1610) + at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224) + at java.base/java.net.URL.openStream(URL.java:1161) + at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:303) + ... 25 more + +【2025-09-18 18:04:13】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-18 18:05:47】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-18 18:05:47】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1968617440169996290","taskType":"1","shopIds":"1968345938572304386","shopNames":"棵韵KEOYURNE图书旗舰店","fileName":"excel表格上传:知书上货模版.xlsx","dataNum":33,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"1","bookCategory":"0","shopIds":"1968345938572304386","data":{"total":33,"fileName":"知书上货模版.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/570eb2d9-9ec7-48d9-a4b0-eb7f5788c925_知书上货模版.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1} +【2025-09-18 18:08:07】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-09-18 18:08:07】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1968618027657789441","taskType":"1","shopIds":"1968345938572304386","shopNames":"棵韵KEOYURNE图书旗舰店","fileName":"excel表格上传:知书上货模版.xlsx","dataNum":33,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"0","listStatus":"1","bookCategory":"0","shopIds":"1968345938572304386","data":{"total":33,"fileName":"知书上货模版.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/aa38cb76-3464-4b93-8ffa-c378b025981e_知书上货模版.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1} +【2025-09-18 18:09:47】【返回参数】null +【2025-09-18 18:09:47】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-10-09 20:36:50】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-10-09 20:36:50】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1976265599406866434","taskType":"1","shopIds":"1976212171971805186","shopNames":"欲泽居家拖鞋专营店","fileName":"excel表格上传:1 (2).xlsx","dataNum":115788,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1976212171971805186","data":{"total":115788,"fileName":"1 (2).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx"},"imageSelect":"1","deleteNum":0},"userId":1} +【2025-10-09 20:37:27】【系统异常】【异常方法】addGoods +【2025-10-09 20:37:27】【系统异常】【异常内容】java.lang.RuntimeException: java.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:234) + 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.lang.RuntimeException: 读取Excel失败: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx + at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:309) + at org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(TaskServiceImpl.java:232) + ... 24 more +Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: https://book.center.file.buzhiyushu.cn/TaskExcel/f88e7c48-c4f7-4ac3-b00e-b9059912b4c0_1 (2).xlsx + at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:2018) + at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1610) + at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224) + at java.base/java.net.URL.openStream(URL.java:1161) + at org.dromara.zhishu.util.EasyExcelUtil.readExcelFromUrl(EasyExcelUtil.java:303) + ... 25 more + +【2025-10-09 20:37:27】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-10-14 14:16:18】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2025-10-14 14:16:18】【执行参数】{"taskBo":{"createDept":null,"createBy":null,"createTime":null,"updateBy":null,"updateTime":null,"id":"1977981773408706561","taskType":"1","shopIds":"1977668615057432578","shopNames":"云眠书籍专营店","fileName":"excel表格上传:1.xlsx","dataNum":58628,"taskStatus":"0","status":null,"threadId":null,"relationId":null},"map":{"taskType":"1","way":"2","listStatus":"1","bookCategory":"0","shopIds":"1977668615057432578","data":{"total":58628,"fileName":"1.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/f7d49467-3805-4f0f-b8b2-a30490b5fc87_1.xlsx"},"imageSelect":"1","deleteNum":0},"userId":1} +【2026-04-03 14:12:12】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:12:12】【执行参数】{"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":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/c54e1f5d-4a0d-46a7-9ca5-2333e9bba455_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039949064445775874\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 14:12:14】【返回参数】null +【2026-04-03 14:12:14】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:31:05】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:31:05】【执行参数】{"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":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ddb09ef2-3402-4a3a-84f7-5a498e09556e_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039953815631712258\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 14:31:08】【返回参数】null +【2026-04-03 14:31:08】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:37:40】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:37:40】【执行参数】{"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":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/ef416bf3-0f56-4adc-b950-be4c6343141d_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039955473279373313\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 14:37:43】【返回参数】null +【2026-04-03 14:37:43】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:42:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:42: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":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/96f302c4-ec51-4144-97af-875389c2a769_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039956688440545282\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 14:42:33】【返回参数】null +【2026-04-03 14:42:33】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:50:33】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 14:50:33】【执行参数】{"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":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/276af74c-8e55-41e5-9e62-5faee13ff42e_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"1","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039958713328881665\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 14:51:52】【返回参数】null +【2026-04-03 14:51:52】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:01:56】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:01:56】【执行参数】{"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":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/0a4466b1-28de-42fb-a926-4cc221a9016e_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039961581154881538\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 15:31:30】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:31: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":1,"proportion":100,"addNum":0}],"data":{"total":40,"fileName":"4.2上传发布(1).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/64be1f86-09df-41e0-a87a-c116eb2d838d_4.2上传发布(1).xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039969020432515073\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 15:32:55】【返回参数】null +【2026-04-03 15:32:55】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:37:19】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:37:19】【执行参数】{"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":51,"fileName":"4.3上传发布.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/7144a800-d9d3-4bb4-b385-75494669d824_4.3上传发布.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039970485242855425\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 15:38:14】【返回参数】null +【2026-04-03 15:38:14】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:42:15】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:42:15】【执行参数】{"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":1,"proportion":100,"addNum":0}],"data":{"total":51,"fileName":"4.3上传发布.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/228912ff-8e20-4881-8e3f-8db839b520da_4.3上传发布.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039971725540491265\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 15:42:16】【系统异常】【异常方法】addGoods +【2026-04-03 15:42:16】【系统异常】【异常内容】org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error on POST request for "http://36.212.20.113:8182/api/goods/simple": "{"code":500,"message":"系统内部错误","success":false}" + at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:102) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:189) + 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:264) + 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:569) + 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:569) + 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:840) + +【2026-04-03 15:42:16】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:45:04】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-04-03 15:45: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":1,"proportion":100,"addNum":0}],"data":{"total":51,"fileName":"4.3上传发布.xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/5d89e6b8-7fb4-4840-8817-beeaf1e19951_4.3上传发布.xlsx"},"imageSelect":"1","deleteNum":0,"shopIds":"2039603208249057282","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"2","createResStr":"{\"code\":\"200\",\"data\":\"2039972434512084994\",\"msg\":\"成功\"}\n"},"userId":1} +【2026-04-03 15:45:10】【系统异常】【异常方法】addGoods +【2026-04-03 15:45:10】【系统异常】【异常内容】org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error on POST request for "http://36.212.20.113:8182/api/goods/simple": "{"code":500,"message":"系统内部错误","success":false}" + at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:102) + at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:189) + 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:264) + 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:569) + 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:569) + 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:840) + +【2026-04-03 15:45:10】【日志结束,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-06-04 17:34:51】【日志开始,方法名称:addGoods】【centerBooksAdd】中心书库发布商品发布方法addGoods +【2026-06-04 17:34:51】【执行参数】{"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,"way":"0"},"map":{"bookCategoryAppoint":0,"data":{"total":34237,"fileName":"漫游鲸童书奥莱店(更新价格库存).xlsx","url":"https://book.center.file.buzhiyushu.cn/TaskExcel/433e6243-db36-4fb3-9bf9-bea1242c9f48_漫游鲸童书奥莱店(更新价格库存).xlsx"},"imageSelect":"1","deleteNum":0,"listStatus":"0","way":"0","createResStr":"{\"code\":\"200\",\"data\":\"2062468107744514049\",\"msg\":\"成功\"}\n","taskType":"1","priceAdjustments":[{"userId":1,"proportion":100,"addNum":0}],"shopIds":"2062044901082611714","synchronizationType":"1","bookCategory":"0"},"userId":1} \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..24f163c --- /dev/null +++ b/pom.xml @@ -0,0 +1,520 @@ + + + 4.0.0 + + org.dromara + ruoyi-vue-plus + ${revision} + + ZhiShu + https://gitee.com/dromara/RuoYi-Vue-Plus + Dromara RuoYi-Vue-Plus多租户管理系统 + + + 5.3.0 + 3.4.2 + UTF-8 + UTF-8 + 17 + 3.5.16 + 2.8.4 + 0.15.0 + 4.0.3 + 2.3 + 1.40.0 + 3.5.10 + 3.9.1 + 5.8.35 + 3.4.1 + 3.44.0 + 2.2.7 + 4.3.1 + 1.3.0 + 1.4.6 + 0.2.0 + 1.18.36 + 1.76 + 1.16.7 + + 2.7.0 + + + 2.28.22 + 0.31.3 + + 3.3.3 + + 1.2.83 + + 8.7.2-20250101 + + 1.6.6 + + + 3.2.2 + 3.2.2 + 3.11.0 + 3.1.2 + 1.3.0 + + + + + local + + + local + info + ruoyi + 123456 + + + + dev + + + dev + info + ruoyi + 123456 + + + + true + + + + prod + + prod + warn + ruoyi + 123456 + + + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + cn.hutool + hutool-bom + ${hutool.version} + pom + import + + + + + org.dromara.warm + warm-flow-mybatis-plus-sb3-starter + ${warm-flow.version} + + + org.dromara.warm + warm-flow-plugin-ui-sb-web + ${warm-flow.version} + + + + + me.zhyd.oauth + JustAuth + ${justauth.version} + + + + + org.dromara + ruoyi-common-bom + ${revision} + pom + import + + + + org.springdoc + springdoc-openapi-starter-webmvc-api + ${springdoc.version} + + + + com.github.therapi + therapi-runtime-javadoc + ${therapi-javadoc.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + com.alibaba + easyexcel + ${easyexcel.version} + + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + + cn.dev33 + sa-token-spring-boot3-starter + ${satoken.version} + + + + cn.dev33 + sa-token-jwt + ${satoken.version} + + + cn.hutool + hutool-all + + + + + cn.dev33 + sa-token-core + ${satoken.version} + + + + + com.baomidou + dynamic-datasource-spring-boot3-starter + ${dynamic-ds.version} + + + + org.mybatis + mybatis + ${mybatis.version} + + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-jsqlparser + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-annotation + ${mybatis-plus.version} + + + + + p6spy + p6spy + ${p6spy.version} + + + + + software.amazon.awssdk + s3 + ${aws.sdk.version} + + + + software.amazon.awssdk.crt + aws-crt + ${aws.crt.version} + + + + software.amazon.awssdk + s3-transfer-manager + ${aws.sdk.version} + + + + org.dromara.sms4j + sms4j-spring-boot-starter + ${sms4j.version} + + + + de.codecentric + spring-boot-admin-starter-server + ${spring-boot-admin.version} + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + + + com.aizuda + snail-job-client-starter + ${snailjob.version} + + + + com.aizuda + snail-job-client-job-core + ${snailjob.version} + + + + com.aizuda + snail-job-client-retry-core + ${snail-job.version} + + + + org.bouncycastle + bcprov-jdk15to18 + ${bouncycastle.version} + + + + io.github.linpeilie + mapstruct-plus-spring-boot-starter + ${mapstruct-plus.version} + + + + + org.lionsoul + ip2region + ${ip2region.version} + + + + commons-io + commons-io + 2.15.0 + + + + com.alibaba + fastjson + ${fastjson.version} + + + + org.dromara + ruoyi-system + ${revision} + + + + org.dromara + ruoyi-zhishu + ${revision} + + + + org.dromara + ruoyi-job + ${revision} + + + + org.dromara + ruoyi-generator + ${revision} + + + + org.dromara + ruoyi-demo + ${revision} + + + + + org.dromara + ruoyi-workflow + ${revision} + + + + + + + ruoyi-admin + ruoyi-common + ruoyi-extend + ruoyi-modules + + pom + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + com.github.therapi + therapi-runtime-javadoc-scribe + ${therapi-javadoc.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + io.github.linpeilie + mapstruct-plus-processor + ${mapstruct-plus.version} + + + org.projectlombok + lombok-mapstruct-binding + ${mapstruct-plus.lombok.version} + + + + -parameters + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + -Dfile.encoding=UTF-8 + + ${profiles.active} + + exclude + + true + + + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + src/main/resources + + false + + + src/main/resources + + + application* + bootstrap* + banner* + + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + false + + + + + + + diff --git a/ruoyi-admin/Dockerfile b/ruoyi-admin/Dockerfile new file mode 100644 index 0000000..b489ab5 --- /dev/null +++ b/ruoyi-admin/Dockerfile @@ -0,0 +1,30 @@ +# 贝尔实验室 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/server/logs \ + /ruoyi/server/temp \ + /ruoyi/skywalking/agent + +WORKDIR /ruoyi/server + +ENV SERVER_PORT=8080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" + +EXPOSE ${SERVER_PORT} + +ADD ./target/ruoyi-admin.jar ./app.jar +# 工作流字体文件 +ADD ./zhFonts/ /usr/share/fonts/zhFonts/ + +SHELL ["/bin/bash", "-c"] + +ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ + # 应用名称 如果想区分集群节点监控 改成不同的名称即可 + #-Dskywalking.agent.service_name=ruoyi-server \ + #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \ + -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ + -jar app.jar + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml new file mode 100644 index 0000000..6c1fa0e --- /dev/null +++ b/ruoyi-admin/pom.xml @@ -0,0 +1,181 @@ + + + + ruoyi-vue-plus + org.dromara + ${revision} + + 4.0.0 + jar + ruoyi-admin + + + web服务入口 + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.mysql + mysql-connector-j + + + + + + + + + + + + + + + + + + + + + + + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-social + + + + org.dromara + ruoyi-common-ratelimiter + + + + org.dromara + ruoyi-common-mail + + + + org.dromara + ruoyi-system + + + + org.dromara + ruoyi-zhishu + + + + org.dromara + ruoyi-job + + + + + org.dromara + ruoyi-generator + + + + + org.dromara + ruoyi-demo + + + + + org.dromara + ruoyi-workflow + + + + de.codecentric + spring-boot-admin-starter-client + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + + + + + + + + commons-logging + commons-logging + 1.2 + + + + com.google.code.gson + gson + 2.8.5 + + + + + + + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + ${project.artifactId} + + + + + + diff --git a/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java b/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java new file mode 100644 index 0000000..066a683 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java @@ -0,0 +1,18 @@ +package org.dromara; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author Lion Li + */ +public class DromaraServletInitializer extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(DromaraApplication.class); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java new file mode 100644 index 0000000..2c1a8ef --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -0,0 +1,507 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.*; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.*; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.social.config.properties.SocialLoginConfigProperties; +import org.dromara.common.social.config.properties.SocialProperties; +import org.dromara.common.social.utils.SocialUtils; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.*; +import org.dromara.web.domain.vo.LoginTenantVo; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.domain.vo.TenantListVo; +import org.dromara.web.domain.vo.WxLoginVo; +import org.dromara.web.domain.vo.dto.UserLoginDTO; +import org.dromara.web.domain.vo.dto.WxRegisterDTO; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.dromara.web.service.SysRegisterService; +import org.dromara.zhishu.service.SignGeneratorService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.RedirectView; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 认证 + * + * @author Lion Li + */ +@Slf4j +@SaIgnore +@RequiredArgsConstructor +@RestController +@RequestMapping("/auth") +@CrossOrigin(origins = "https://erp.newadmin.buzhiyushu.cn",maxAge = 3600) +public class AuthController { + + private final SocialProperties socialProperties; + private final SysLoginService loginService; + private final SysRegisterService registerService; + private final ISysConfigService configService; + private final ISysTenantService tenantService; + private final ISysSocialService socialUserService; + private final ISysClientService clientService; + private final ScheduledExecutorService scheduledExecutorService; + private final ISysUserService userService; + private final SignGeneratorService signGeneratorService; + @Value("${wechat.appid}") + private String appid; + + @Value("${wechat.secret}") + private String secret; + + @Value("${wechat.jscode2session-url}") + private String loginUrl; + + + /** + * 登录方法 + * + * @param body 登录信息 + * @return 结果 + */ + //@ApiEncrypt + @PostMapping("/login") + public R login(@RequestBody String body) { +// System.out.println("body:" + body); + LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class); + long timestamp1 = System.currentTimeMillis() / 1000; + String sign = null; + if (loginBody != null) { + sign = signGeneratorService.generateCallbackSign(loginBody.getLogin_code(), timestamp1, "erp_callback_sk_7f8a9b2c4d5e6f1a3b7c9d2e4f5a6b8c"); + } + + + ValidatorUtils.validate(loginBody); + // 授权类型和客户端id + String clientId = loginBody.getClientId(); + String grantType = loginBody.getGrantType(); +// System.out.println("===============" + grantType); + SysClientVo client = clientService.queryByClientId(clientId); +// System.out.println(client); + // 查询不到 client 或 client 内不包含 grantType + if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { + log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); + return R.fail(MessageUtils.message("auth.grant.type.error")); + } else if (SystemConstants.NORMAL.equals(client.getStatus())) { + return R.fail(MessageUtils.message("auth.grant.type.blocked")); + } + // 校验租户 + loginService.checkTenant(loginBody.getTenantId()); + // 登录 + LoginVo loginVo = IAuthStrategy.login(body, client, grantType); + + if (!StringUtils.isEmpty(loginBody.getLogin_code())){ + // 调用 ERP 回调 API + try { + //入口层 + String callbackUrl = "https://wallet.api.buzhiyushu.cn/api/oauth/erp/callback"; + URL url = new URL(callbackUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + connection.setRequestProperty("Accept", "application/json"); + + // URL编码所有参数值 + StringBuilder postData = new StringBuilder(); + postData.append("login_code=").append(URLEncoder.encode( + String.valueOf(loginBody.getLogin_code()), "UTF-8")); + postData.append("&erp_user_id=").append(URLEncoder.encode( + String.valueOf(LoginHelper.getUserId()), "UTF-8")); + + postData.append("&erp_token=").append(URLEncoder.encode( + String.valueOf(loginVo.getAccessToken()), "UTF-8")); + postData.append("&erp_username=").append(URLEncoder.encode( + String.valueOf(userService.selectUserById(LoginHelper.getUserId()).getUserName()), "UTF-8")); + postData.append("×tamp=").append(URLEncoder.encode( + String.valueOf(timestamp1), "UTF-8")); + postData.append("&sign=").append(URLEncoder.encode( + String.valueOf(sign), "UTF-8")); + + // 打印请求信息用于调试 + log.info("发送请求到: {}, 参数: {}", callbackUrl, postData.toString()); + + byte[] postDataBytes = postData.toString().getBytes(StandardCharsets.UTF_8); + connection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length)); + + try (OutputStream os = connection.getOutputStream()) { + os.write(postDataBytes); + os.flush(); + } + + int responseCode = connection.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK) { + log.error("ERP 回调 API 调用失败,状态码: {}", responseCode); + + // 读取错误信息 + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8))) { + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + log.error("错误响应: {}", response.toString()); + } + } else { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + log.info("ERP 回调 API 调用成功,响应: {}", response.toString()); + } + } + connection.disconnect(); + } catch (Exception e) { + log.error("调用 ERP 回调 API 时发生异常", e); + } + } + + Long userId = LoginHelper.getUserId(); + scheduledExecutorService.schedule(() -> { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage("欢迎登录知书图书助理后台管理系统"); + dto.setUserIds(List.of(userId)); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); +// System.out.println("000000000000" + loginVo); + return R.ok(loginVo); + } + + @PostMapping("/interFaceLogin") + public R interFaceLogin(InterfaceLoginBody loginBody){ +// System.out.println("body:" + loginBody); + String clientId = loginBody.getClientId(); + SysClientVo client = clientService.queryByClientId(clientId); + String phoneNumber = loginBody.getPhoneNumber(); + String password = loginBody.getPassword(); + SysUserVo userVo = userService.selectUserByPhonenumber(phoneNumber); + if (userVo == null) { + log.error("用户手机号 {} 未找到对应的用户记录", phoneNumber); + throw new ServiceException("用户未找到对应的用户记录"); + } + // 验证密码是否正确 + if (!BCrypt.checkpw(password, userVo.getPassword())) { + log.error("用户密码不正确"); + throw new ServiceException("用户密码不正确"); + } + LoginUser loginUser = loginService.buildLoginUser(userVo); + 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()); + // 生成token + LoginHelper.login(loginUser, model); + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + loginVo.setPhoneNumber(phoneNumber); + loginVo.setNickName(loginUser.getNickname()); + loginVo.setUserId(userVo.getUserId()); + return R.ok(loginVo); + } + + + /** + * 获取跳转URL + * + * @param source 登录来源 + * @return 结果 + */ + @GetMapping("/binding/{source}") + public R authBinding(@PathVariable("source") String source, + @RequestParam String tenantId, @RequestParam String domain) { + SocialLoginConfigProperties obj = socialProperties.getType().get(source); + if (ObjectUtil.isNull(obj)) { + return R.fail(source + "平台账号暂不支持"); + } + AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties); + Map map = new HashMap<>(); + map.put("tenantId", tenantId); + map.put("domain", domain); + map.put("state", AuthStateUtils.createState()); + String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8)); + return R.ok("操作成功", authorizeUrl); + } + + /** + * 前端回调绑定授权(需要token) + * + * @param loginBody 请求体 + * @return 结果 + */ + @PostMapping("/social/callback") + public R socialCallback(@RequestBody SocialLoginBody loginBody) { + // 校验token + StpUtil.checkLogin(); + // 获取第三方登录信息 + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + AuthUser authUserData = response.getData(); + // 判断授权响应是否成功 + if (!response.ok()) { + return R.fail(response.getMsg()); + } + loginService.socialRegister(authUserData); + return R.ok(); + } + + + /** + * 取消授权(需要token) + * + * @param socialId socialId + */ + @DeleteMapping(value = "/unlock/{socialId}") + public R unlockSocial(@PathVariable Long socialId) { + // 校验token + StpUtil.checkLogin(); + Boolean rows = socialUserService.deleteWithValidById(socialId); + return rows ? R.ok() : R.fail("取消授权失败"); + } + + + /** + * 退出登录 + */ + @PostMapping("/logout") + public R logout() { + loginService.logout(); + return R.ok("退出成功"); + } + + /** + * 用户注册 + */ +// @ApiEncrypt + @PostMapping("/register") + @SaIgnore + public R register(@Validated @RequestBody RegisterBody user) { +// if (!configService.selectRegisterEnabled(user.getTenantId())) { +// return R.fail("当前系统没有开启注册功能!"); +// } + registerService.register(user); + return R.ok(); + } + + /** + * 登录页面租户下拉框 + * + * @return 租户列表 + */ + @GetMapping("/tenant/list") + public R tenantList(HttpServletRequest request) throws Exception { + // 返回对象 + LoginTenantVo result = new LoginTenantVo(); + boolean enable = TenantHelper.isEnable(); + result.setTenantEnabled(enable); + // 如果未开启租户这直接返回 + if (!enable) { + return R.ok(result); + } + + List tenantList = tenantService.queryList(new SysTenantBo()); + List voList = MapstructUtils.convert(tenantList, TenantListVo.class); + try { + // 如果只超管返回所有租户 + if (LoginHelper.isSuperAdmin()) { + result.setVoList(voList); + return R.ok(result); + } + } catch (NotLoginException ignored) { + } + + // 获取域名 + String host; + String referer = request.getHeader("referer"); + if (StringUtils.isNotBlank(referer)) { + // 这里从referer中取值是为了本地使用hosts添加虚拟域名,方便本地环境调试 + host = referer.split("//")[1].split("/")[0]; + } else { + host = new URL(request.getRequestURL().toString()).getHost(); + } + // 根据域名进行筛选 + List list = StreamUtils.filter(voList, vo -> + StringUtils.equalsIgnoreCase(vo.getDomain(), host)); + result.setVoList(CollUtil.isNotEmpty(list) ? list : voList); + return R.ok(result); + } + + @SneakyThrows + @PostMapping("/wxLogin") + public ResponseEntity wxLogin(@Valid @RequestBody UserLoginDTO userLoginDTO) { + String code = userLoginDTO.getCode(); + try { + String requestUrl = loginUrl + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code"; + URL url = new URL(requestUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + StringBuilder response = new StringBuilder(); + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + + JSONObject jsonObject = JSONObject.parseObject(response.toString()); + if (jsonObject.containsKey("openid") && jsonObject.containsKey("session_key")) { + String openid = jsonObject.getString("openid"); + String sessionKey = jsonObject.getString("session_key"); + String token = generateToken(openid, sessionKey); + WxLoginVo loginVo = new WxLoginVo(); + loginVo.setOpenid(openid); + loginVo.setToken(token); + return ResponseEntity.ok(loginVo); + } else { + return ResponseEntity.badRequest().build(); + } + } catch (IOException e) { + return ResponseEntity.internalServerError().build(); + } + } + + private String generateToken(String openid, String sessionKey) { + return openid + "_" + sessionKey; + } + + @PostMapping("/wxRegister") + @SaIgnore + public R wxRegister(@RequestBody WxRegisterDTO wxRegisterDTO) { + registerService.WxRegister(wxRegisterDTO); + return R.ok(); + } + + @PostMapping("/getUserName") + @SaIgnore + public List getUserName() { + return userService.selectUserName(); + } + + @GetMapping("/autoLogin") + @SaIgnore + public ModelAndView autoLoginGet(@RequestParam("userId") Long userId, HttpServletResponse response) throws IOException { +// System.out.println("开始自动登录流程 - 用户ID: " + userId); + // 1. 查询用户 + SysUserVo user = userService.selectUserByUserId(userId); + System.out.println("获取用户信息结果: " + (user != null ? "成功" : "失败")); +// System.out.println("用户信息: " + user); + // 2. 构建LoginUser + LoginUser loginUser = loginService.buildLoginUser(user); + loginUser.setClientKey("pc"); + loginUser.setDeviceType("pc"); + SaLoginModel model = new SaLoginModel(); + model.setDevice("pc"); + model.setTimeout(604800); + model.setActiveTimeout(1800); + model.setExtra(LoginHelper.CLIENT_KEY, "e5cd7e4891bf95d1d19206ce24a7b32e"); + LoginHelper.login(loginUser, model); + String token = StpUtil.getTokenValue(); + Cookie cookie = new Cookie("satoken", token); + cookie.setPath("/"); + cookie.setMaxAge(604800); + response.addCookie(cookie); + response.setHeader("Authorization", "Bearer " + token); +// System.out.println("登录完成,token: " + StpUtil.getTokenValue()); + System.out.println("====进行跳转"); + System.out.println("准备跳转到首页"); + return new ModelAndView(new RedirectView("https://api.buzhiyushu.cn/reigsn?token=" + token)); + } + + @GetMapping("/test") + @SaIgnore + public ModelAndView test(HttpServletResponse response) throws IOException { + System.out.println("开始测试登录流程"); + + Long userId = 1L; + // 1. 查询用户 + // 1. 查询用户 + SysUserVo user = userService.selectUserByUserId(userId); + System.out.println("获取用户信息结果: " + (user != null ? "成功" : "失败")); +// System.out.println("用户信息: " + user); + // 2. 构建LoginUser + LoginUser loginUser = loginService.buildLoginUser(user); + loginUser.setClientKey("pc"); + loginUser.setDeviceType("pc"); + SaLoginModel model = new SaLoginModel(); + model.setDevice("pc"); + model.setTimeout(604800); + model.setActiveTimeout(1800); + model.setExtra(LoginHelper.CLIENT_KEY, "e5cd7e4891bf95d1d19206ce24a7b32e"); + LoginHelper.login(loginUser, model); + + String token = StpUtil.getTokenValue(); + Cookie cookie = new Cookie("satoken", token); + cookie.setPath("/"); + cookie.setMaxAge(604800); + response.addCookie(cookie); + response.setHeader("Authorization", "Bearer " + token); +// System.out.println("登录完成,token: " + StpUtil.getTokenValue()); + System.out.println("====进行跳转"); + System.out.println("准备跳转到首页"); + return new ModelAndView(new RedirectView("https://erp.buzhiyushu.cn/index?token=" + token)); + } + + + + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java new file mode 100644 index 0000000..7338d3c --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java @@ -0,0 +1,139 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import jakarta.validation.constraints.NotBlank; +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.domain.R; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.mail.config.properties.MailProperties; +import org.dromara.common.mail.utils.MailUtils; +import org.dromara.common.ratelimiter.annotation.RateLimiter; +import org.dromara.common.ratelimiter.enums.LimitType; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.common.web.enums.CaptchaType; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.web.domain.vo.CaptchaVo; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.Duration; +import java.util.LinkedHashMap; + +/** + * 验证码操作处理 + * + * @author Lion Li + */ +@SaIgnore +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +@CrossOrigin(origins = "https://erp.newadmin.buzhiyushu.cn",maxAge = 3600) +public class CaptchaController { + + private final CaptchaProperties captchaProperties; + private final MailProperties mailProperties; + + /** + * 短信验证码 + * + * @param phonenumber 用户手机号 + */ + @RateLimiter(key = "#phonenumber", time = 60, count = 1) + @GetMapping("/resource/sms/code") + public R smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { + String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + // 验证码模板id 自行处理 (查数据库或写死均可) + String templateId = ""; + LinkedHashMap map = new LinkedHashMap<>(1); + map.put("code", code); + SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); + SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map); + if (!smsResponse.isSuccess()) { + log.error("验证码短信发送异常 => {}", smsResponse); + return R.fail(smsResponse.getData().toString()); + } + return R.ok(); + } + + /** + * 邮箱验证码 + * + * @param email 邮箱 + */ + @RateLimiter(key = "#email", time = 60, count = 1) + @GetMapping("/resource/email/code") + public R emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { + if (!mailProperties.getEnabled()) { + return R.fail("当前系统没有开启邮箱功能!"); + } + String key = GlobalConstants.CAPTCHA_CODE_KEY + email; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + try { + MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。"); + } catch (Exception e) { + log.error("验证码短信发送异常 => {}", e.getMessage()); + return R.fail(e.getMessage()); + } + return R.ok(); + } + + /** + * 生成验证码 + */ + @RateLimiter(time = 60, count = 10, limitType = LimitType.IP) + @GetMapping("/auth/code") + @SaIgnore + public R getCode() { + CaptchaVo captchaVo = new CaptchaVo(); + boolean captchaEnabled = captchaProperties.getEnable(); + if (!captchaEnabled) { + captchaVo.setCaptchaEnabled(false); + return R.ok(captchaVo); + } + // 保存验证码信息 + String uuid = IdUtil.simpleUUID(); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; + // 生成验证码 + CaptchaType captchaType = captchaProperties.getType(); + boolean isMath = CaptchaType.MATH == captchaType; + Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); + CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); + AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); + captcha.setGenerator(codeGenerator); + captcha.createCode(); + // 如果是数学验证码,使用SpEL表达式处理验证码结果 + String code = captcha.getCode(); + if (isMath) { + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); + code = exp.getValue(String.class); + } + RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + captchaVo.setUuid(uuid); + captchaVo.setImg(captcha.getImageBase64()); + return R.ok(captchaVo); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java new file mode 100644 index 0000000..0a83ace --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java @@ -0,0 +1,25 @@ +package org.dromara.web.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 登录租户对象 + * + * @author Michelle.Chung + */ +@Data +public class LoginTenantVo { + + /** + * 租户开关 + */ + private Boolean tenantEnabled; + + /** + * 租户对象列表 + */ + private List voList; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java new file mode 100644 index 0000000..db9c271 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java @@ -0,0 +1,31 @@ +package org.dromara.web.domain.vo; + +import org.dromara.system.domain.vo.SysTenantVo; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +/** + * 租户列表 + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysTenantVo.class) +public class TenantListVo { + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 域名 + */ + private String domain; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/WxLoginVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/WxLoginVo.java new file mode 100644 index 0000000..8a0b85f --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/WxLoginVo.java @@ -0,0 +1,12 @@ +package org.dromara.web.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class WxLoginVo { + private Long id; + private String openid; + private String token; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/dto/WxRegisterDTO.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/dto/WxRegisterDTO.java new file mode 100644 index 0000000..e3927fc --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/dto/WxRegisterDTO.java @@ -0,0 +1,16 @@ +package org.dromara.web.domain.vo.dto; + +import lombok.Data; +import org.dromara.common.core.domain.model.LoginBody; + +@Data +public class WxRegisterDTO extends LoginBody { + private String username; + private String password; + private String userType; + + /** + * 邀请码 + */ + private String inviteCode; +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java new file mode 100644 index 0000000..07595e0 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java @@ -0,0 +1,165 @@ +package org.dromara.web.listener; + +import cn.dev33.satoken.config.SaTokenConfig; +import cn.dev33.satoken.listener.SaTokenListener; +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.domain.dto.UserOnlineDTO; +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.ip.AddressUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +/** + * 用户行为 侦听器的实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Component +@Slf4j +public class UserActionListener implements SaTokenListener { + + private final SaTokenConfig tokenConfig; + private final SysLoginService loginService; + + /** + * 每次登录时触发 + */ + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) { + UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = ServletUtils.getClientIP(); + UserOnlineDTO dto = new UserOnlineDTO(); + dto.setIpaddr(ip); + dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + dto.setBrowser(userAgent.getBrowser().getName()); + dto.setOs(userAgent.getOs().getName()); + dto.setLoginTime(System.currentTimeMillis()); + dto.setTokenId(tokenValue); + String username = (String) loginModel.getExtra(LoginHelper.USER_NAME_KEY); + String tenantId = (String) loginModel.getExtra(LoginHelper.TENANT_KEY); + dto.setUserName(username); + dto.setClientKey((String) loginModel.getExtra(LoginHelper.CLIENT_KEY)); + dto.setDeviceType(loginModel.getDevice()); + dto.setDeptName((String) loginModel.getExtra(LoginHelper.DEPT_NAME_KEY)); + TenantHelper.dynamic(tenantId, () -> { + if(tokenConfig.getTimeout() == -1) { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); + } else { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout())); + } + }); + // 记录登录日志 + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(Constants.LOGIN_SUCCESS); + logininforEvent.setMessage(MessageUtils.message("user.login.success")); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + // 更新登录信息 + loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip); + log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次注销时触发 + */ + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被踢下线时触发 + */ + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被顶下线时触发 + */ + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被封禁时触发 + */ + @Override + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { + } + + /** + * 每次被解封时触发 + */ + @Override + public void doUntieDisable(String loginType, Object loginId, String service) { + } + + /** + * 每次打开二级认证时触发 + */ + @Override + public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCloseSafe(String loginType, String tokenValue, String service) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCreateSession(String id) { + } + + /** + * 每次注销Session时触发 + */ + @Override + public void doLogoutSession(String id) { + } + + /** + * 每次Token续期时触发 + */ + @Override + public void doRenewTimeout(String tokenValue, Object loginId, long timeout) { + } +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java new file mode 100644 index 0000000..424fd78 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java @@ -0,0 +1,49 @@ +package org.dromara.web.service; + + +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.web.domain.vo.LoginVo; + +/** + * 授权策略 + * + * @author Michelle.Chung + */ +public interface IAuthStrategy { + + String BASE_NAME = "AuthStrategy"; + + /** + * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @param grantType 授权类型 + * @return 登录验证信息 + */ + static LoginVo login(String body, SysClientVo client, String grantType) { + // 授权类型和客户端id + if(grantType.equals("social")) { + grantType = "password"; + } + String beanName = grantType + BASE_NAME; + if (!SpringUtils.containsBean(beanName)) { + throw new ServiceException("授权类型不正确!"); + } + IAuthStrategy instance = SpringUtils.getBean(beanName); + return instance.login(body, client); + } + + /** + * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @return 登录验证信息 + */ + LoginVo login(String body, SysClientVo client); + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java new file mode 100644 index 0000000..41a802b --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -0,0 +1,251 @@ +package org.dromara.web.service; + +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.lang.Opt; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.lock.annotation.Lock4j; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthUser; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.dto.PostDTO; +import org.dromara.common.core.domain.dto.RoleDTO; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.*; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.exception.TenantException; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.*; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.Date; +import java.util.List; +import java.util.function.Supplier; + +/** + * 登录校验方法 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLoginService { + + @Value("${user.password.maxRetryCount}") + private Integer maxRetryCount; + + @Value("${user.password.lockTime}") + private Integer lockTime; + + private final ISysTenantService tenantService; + private final ISysPermissionService permissionService; + private final ISysSocialService sysSocialService; + private final ISysRoleService roleService; + private final ISysDeptService deptService; + private final ISysPostService postService; + private final SysUserMapper userMapper; + + + /** + * 绑定第三方用户 + * + * @param authUserData 授权响应实体 + */ + @Lock4j + public void socialRegister(AuthUser authUserData) { + String authId = authUserData.getSource() + authUserData.getUuid(); + // 第三方用户信息 + SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class); + BeanUtil.copyProperties(authUserData.getToken(), bo); + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + bo.setAuthId(authId); + bo.setOpenId(authUserData.getUuid()); + bo.setUserName(authUserData.getUsername()); + bo.setNickName(authUserData.getNickname()); + List checkList = sysSocialService.selectByAuthId(authId); + if (CollUtil.isNotEmpty(checkList)) { + throw new ServiceException("此三方账号已经被绑定!"); + } + // 查询是否已经绑定用户 + SysSocialBo params = new SysSocialBo(); + params.setUserId(userId); + params.setSource(bo.getSource()); + List list = sysSocialService.queryList(params); + if (CollUtil.isEmpty(list)) { + // 没有绑定用户, 新增用户信息 + sysSocialService.insertByBo(bo); + } else { + // 更新用户信息 + bo.setId(list.get(0).getId()); + sysSocialService.updateByBo(bo); + // 如果要绑定的平台账号已经被绑定过了 是否抛异常自行决断 + // throw new ServiceException("此平台账号已经被绑定!"); + } + } + + + /** + * 退出登录 + */ + public void logout() { + try { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + return; + } + if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { + // 超级管理员 登出清除动态租户 + TenantHelper.clearDynamic(); + } + recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + } catch (NotLoginException ignored) { + } finally { + try { + StpUtil.logout(); + } catch (NotLoginException ignored) { + } + } + } + + /** + * 记录登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + */ + public 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 LoginUser buildLoginUser(SysUserVo user) { + LoginUser loginUser = new LoginUser(); + Long userId = user.getUserId(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(userId); + loginUser.setDeptId(user.getDeptId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setMenuPermission(permissionService.getMenuPermission(userId)); + loginUser.setRolePermission(permissionService.getRolePermission(userId)); + if (ObjectUtil.isNotNull(user.getDeptId())) { + Opt deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById); + loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); + loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); + } + List roles = roleService.selectRolesByUserId(userId); + List posts = postService.selectPostsByUserId(userId); + loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); + loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class)); + return loginUser; + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId, String ip) { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(ip); + sysUser.setLoginDate(DateUtils.getNowDate()); + sysUser.setUpdateBy(userId); + DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser)); + } + + /** + * 登录校验 + */ + public void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) { + String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; + String loginFail = Constants.LOGIN_FAIL; + + // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip) + int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); + // 锁定时间内登录 则踢出 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } + + if (supplier.get()) { + // 错误次数递增 + errorNumber++; + RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); + // 达到规定错误次数 则锁定登录 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } else { + // 未达到规定错误次数 + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); + throw new UserException(loginType.getRetryLimitCount(), errorNumber); + } + } + + // 登录成功 清空错误次数 + RedisUtils.deleteObject(errorKey); + } + + /** + * 校验租户 + * + * @param tenantId 租户ID + */ + public void checkTenant(String tenantId) { + if (!TenantHelper.isEnable()) { + return; + } + if (StringUtils.isBlank(tenantId)) { + throw new TenantException("tenant.number.not.blank"); + } + if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + return; + } + SysTenantVo tenant = tenantService.queryByTenantId(tenantId); + if (ObjectUtil.isNull(tenant)) { + log.info("登录租户:{} 不存在.", tenantId); + throw new TenantException("tenant.not.exists"); + } else if (SystemConstants.DISABLE.equals(tenant.getStatus())) { + log.info("登录租户:{} 已被停用.", tenantId); + throw new TenantException("tenant.blocked"); + } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) + && new Date().after(tenant.getExpireTime())) { + log.info("登录租户:{} 已超过有效期.", tenantId); + throw new TenantException("tenant.expired"); + } + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java new file mode 100644 index 0000000..11b9eee --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java @@ -0,0 +1,185 @@ +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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.pdd.pop.sdk.common.util.JsonUtil; +import io.swagger.v3.core.util.Json; +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.PasswordLoginBody; +import org.dromara.common.core.enums.LoginType; +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.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.common.web.config.properties.CaptchaProperties; +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.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +/** + * 密码认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("password" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class PasswordAuthStrategy implements IAuthStrategy { + + private final CaptchaProperties captchaProperties; + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); +// String username = loginBody.getUsername(); + String phoneNumber=loginBody.getPhoneNumber(); + String password = loginBody.getPassword(); + String code = loginBody.getCode(); + String uuid = loginBody.getUuid(); + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { +// validateCaptcha(tenantId, username, code, uuid); + validateCaptcha(tenantId, phoneNumber, code, uuid); + } + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { +// SysUserVo user = loadUserByUsername(username); + SysUserVo user = loadUserByPhone(phoneNumber); + + +// loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); + loginService.checkLogin(LoginType.PASSWORD, tenantId, phoneNumber, () -> !BCrypt.checkpw(password, user.getPassword())); + // 此处可根据登录用户的数据不同 自行创建 loginUser + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + // 登录其他 + Map newLoginMap = new HashMap(); + newLoginMap.put("username",phoneNumber); + newLoginMap.put("password",password); + newLoginMap.put("about_id",loginUser.getUserId().toString()); + String res = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/login/128",newLoginMap); + Map resMap = JsonUtil.transferToObj(res,Map.class); + if (resMap.get("msg") != null && resMap.get("msg").equals("用户不存在")){ + Map employeeMap = new HashMap(); + employeeMap.put("username",phoneNumber); + employeeMap.put("password",password); + employeeMap.put("about_id",loginUser.getUserId().toString()); + employeeMap.put("fid","0"); + employeeMap.put("name",phoneNumber); + employeeMap.put("phone",phoneNumber); + employeeMap.put("from","ERP"); + String employeeRes = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/employee/reg",employeeMap); + Map employeeResMap = JsonUtil.transferToObj(employeeRes,Map.class); + if (employeeResMap.get("message") != null && employeeResMap.get("message").equals("添加成功")){ + res = InterfaceUtils.postForm(UrlUtil.getNewWarehouse(),"/api/login/128",newLoginMap); + resMap = JsonUtil.transferToObj(res,Map.class); + + if (resMap.get("msg") != null && resMap.get("msg").equals("登录成功")){ + Map data = (Map) resMap.get("data"); + loginUser.setWarehouseLoginUser(data); + } + } + }else if (resMap.get("msg") != null && resMap.get("msg").equals("登录成功")){ + if (resMap.get("msg") != null && resMap.get("msg").equals("登录成功")){ + Map data = (Map) resMap.get("data"); + loginUser.setWarehouseLoginUser(data); + } + } + + + 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; + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + private 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) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!code.equalsIgnoreCase(captcha)) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + private SysUserVo loadUserByUsername(String username) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, username)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", username); + throw new UserException("user.not.exists", username); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", username); + throw new UserException("user.blocked", username); + } + return user; + } + +// 新增方法 + private SysUserVo loadUserByPhone(String username) { +// SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, username)); + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getPhonenumber, username)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", username); + throw new UserException("user.not.exists", username); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", username); + throw new UserException("user.blocked", username); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java new file mode 100644 index 0000000..419dbd6 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java @@ -0,0 +1,131 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.SaLoginModel; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpUtil; +import cn.hutool.http.Method; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.SocialLoginBody; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.social.config.properties.SocialProperties; +import org.dromara.common.social.utils.SocialUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysSocialService; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +/** + * 第三方授权策略 + * + * @author thiszhc is 三三 + */ +@Slf4j +@Service("social" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SocialAuthStrategy implements IAuthStrategy { + + private final SocialProperties socialProperties; + private final ISysSocialService sysSocialService; + private final SysUserMapper userMapper; + private final SysLoginService loginService; + + /** + * 登录-第三方授权登录 + * + * @param body 登录信息 + * @param client 客户端信息 + */ + @Override + public LoginVo login(String body, SysClientVo client) { + SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class); + ValidatorUtils.validate(loginBody); + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + if (!response.ok()) { + throw new ServiceException(response.getMsg()); + } + AuthUser authUserData = response.getData(); + if ("GITEE".equals(authUserData.getSource())) { + // 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖 + HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus") + .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) + .executeAsync(); + HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus") + .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken())) + .executeAsync(); + } + + List list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid()); + if (CollUtil.isEmpty(list)) { + throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!"); + } + SysSocialVo social; + if (TenantHelper.isEnable()) { + Optional opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId())); + if (opt.isEmpty()) { + throw new ServiceException("对不起,你没有权限登录当前租户!"); + } + social = opt.get(); + } else { + social = list.get(0); + } + LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> { + SysUserVo user = loadUser(social.getUserId()); + // 此处可根据登录用户的数据不同 自行创建 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 SysUserVo loadUser(Long userId) { + SysUserVo user = userMapper.selectVoById(userId); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", ""); + throw new UserException("user.not.exists", ""); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", ""); + throw new UserException("user.blocked", ""); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java new file mode 100644 index 0000000..33adc49 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java @@ -0,0 +1,153 @@ +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 me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.request.AuthWechatMiniProgramRequest; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.XcxLoginBody; +import org.dromara.common.core.domain.model.XcxLoginUser; +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("xcx" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class XcxAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final ISysUserService userService; + @Override + public LoginVo login(String body, SysClientVo client) { + XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class); + ValidatorUtils.validate(loginBody); + // xcxCode 为 小程序调用 wx.login 授权后获取 + String xcxCode = loginBody.getXcxCode(); + // 多个小程序识别使用 + String appid = loginBody.getAppid(); + // 参数校验 + if (StringUtils.isBlank(appid) || StringUtils.isBlank(xcxCode)) { + throw new ServiceException("appid 或 xcxCode 不能为空"); + } + // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid + AuthRequest authRequest = new AuthWechatMiniProgramRequest(AuthConfig.builder() + .clientId(appid).clientSecret("c691dea9dfde1da7ae51c34f5a6d3d53") + .ignoreCheckRedirectUri(true).ignoreCheckState(true).build()); + AuthCallback authCallback = new AuthCallback(); + authCallback.setCode(xcxCode); + AuthResponse resp = authRequest.login(authCallback); + String openid, unionId; + if (resp.ok()) { + AuthToken token = resp.getData().getToken(); + openid = token.getOpenId(); + // 微信小程序只有关联到微信开放平台下之后才能获取到 unionId,因此unionId不一定能返回。 + unionId = token.getUnionId(); + // 把 openId 存到对应用户中 + log.info("登录成功,openid: {}, unionId: {}", openid, unionId); + } else { + log.error("微信小程序登录失败,错误信息: {}", resp.getMsg()); + throw new ServiceException(resp.getMsg()); + } + + // 把openId存到对应用户中 + String phoneNumber = loginBody.getPhoneNumber(); + String password = loginBody.getPassword(); + SysUserVo user1 = userService.selectUserByPhonenumber(phoneNumber); +// System.out.println("============="+user1); + if (user1 == null) { + log.error("用户手机号 {} 未找到对应的用户记录", phoneNumber); + throw new ServiceException("用户未找到对应的用户记录"); + } + + // 验证密码是否正确 + if (!BCrypt.checkpw(password, user1.getPassword())) { + log.error("用户密码不正确"); + throw new ServiceException("用户密码不正确"); + } + + // 检查 openId 是否为 null 或者不等于传入的 openid + String existingOpenId = user1.getOpenId(); + if (existingOpenId == null || !existingOpenId.equals(openid)) { + // 如果 openId 不匹配,则更新数据库中的 openId + userService.insertUserOpenId(openid, user1.getPhonenumber()); + } + + + // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 + SysUserVo user = loadUserByOpenid(openid,loginBody.getPhoneNumber()); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + XcxLoginUser loginUser = new XcxLoginUser(); + 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()); + loginUser.setOpenid(openid); + 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()); + loginVo.setOpenid(openid); + loginVo.setPhoneNumber(phoneNumber); + loginVo.setNickName(loginUser.getNickname()); + loginVo.setUserId(user1.getUserId()); + return loginVo; + } + + private SysUserVo loadUserByOpenid(String openid, String phoneNumber) { + // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 + // todo 自行实现 userService.selectUserByOpenid(openid); + SysUserVo user = userService.selectUserByOpenid(openid,phoneNumber); +// SysUserVo user = new SysUserVo(); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", openid); + // todo 用户不存在 业务逻辑自行实现 + + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", openid); + // todo 用户已被停用 业务逻辑自行实现 + } + return user; + + } + + + +} diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml new file mode 100644 index 0000000..4f5820f --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -0,0 +1,290 @@ +--- # 监控中心配置 +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: true + # 设置默认的数据源或者数据源组,默认值即为 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://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 + 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 + 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: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + 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:1898/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://localhost:8095 + history-shop-god-s-excel-file-path: D:\ShopGoodsData\HistoryGoodsData + new-shop-god-s-excel-file-path: D:\ShopGoodsData\NewShopGoodsData + changed-shop-god-s-excel-file-path: D:\ShopGoodsData\ChangedShopGoodsData + error-shop-god-s-excel-file-path: D:\ShopGoodsData\ErrorShopGoodsData \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml new file mode 100644 index 0000000..968d9c0 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application.yml @@ -0,0 +1,317 @@ +# 项目相关配置 +ruoyi: + # 名称 + name: ZhiShu + # 版本 + version: ${revision} + # 版权年份 + copyrightYear: 2024 + # 配置IP地址 +# ipurl: localhost:81 + ipurl: erp.buzhiyushu.cn + +# 邀请码配置 +invite: + url: + # 邀请码链接前缀,需要修改为实际的前端注册页面地址 + prefix: https://erp.buzhiyushu.cn/register?code= + +captcha: + enable: true + # 页面 <参数设置> 可开启关闭 验证码校验 + # 验证码类型 math 数组计算 char 字符验证 + type: MATH + # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 + category: CIRCLE + # 数字验证码位数 + numberLength: 1 + # 字符验证码长度 + charLength: 4 + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8080 + servlet: + # 应用的访问路径 + context-path: / + # undertow 配置 + undertow: + # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的zhishu/shopOrder/listByOrderSn + max-http-post-size: -1 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 + # 每块buffer的空间大小,越小的空间被利用越充分 + buffer-size: 512 + # 是否分配的直接内存 + direct-buffers: true + threads: + # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 + io: 8 + # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 + worker: 256 + +# 日志配置 +logging: + level: + org.dromara: @logging.level@ + org.springframework: info + org.mybatis.spring.mapper: error + org.apache.fury: warn + config: classpath:logback-plus.xml + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 5 + # 密码锁定时间(默认10分钟) + lockTime: 10 + +# Spring配置 +spring: + application: + name: ${ruoyi.name} + threads: + # 开启虚拟线程 仅jdk21可用 + virtual: + enabled: false + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: @profiles.active@ + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 30MB + # 设置总上传的文件大小 + max-request-size: 100MB + mvc: + # 设置静态资源路径 防止所有请求都去查静态资源 + static-path-pattern: /static/** + format: + date-time: yyyy-MM-dd HH:mm:ss + jackson: + # 日期格式化 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + # 格式化输出 + indent_output: false + # 忽略无法转换的对象 + fail_on_empty_beans: false + deserialization: + # 允许对象忽略json中不存在的属性 + fail_on_unknown_properties: false + +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + +# security配置 +security: + # 排除路径 + excludes: + - /*.html + - /**/*.html + - /**/*.css + - /**/*.js + - /favicon.ico + - /error + - /*/api-docs + - /*/api-docs/** + - /warm-flow-ui/token-name + +# 多租户配置 +tenant: + # 是否开启 + enable: true + # 排除表 + excludes: + - sys_menu + - sys_tenant + - sys_tenant_package + - sys_role_dept + - sys_role_menu + - sys_user_post + - sys_user_role + - sys_client + - sys_oss_config + - t_district + - t_invite_codes + +# MyBatisPlus配置 +# https://baomidou.com/config/ +mybatis-plus: + # 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效 + enableLogicDelete: true + # 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper + mapperPackage: org.dromara.**.mapper + # 对应的 XML 文件位置 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: org.dromara.**.domain + global-config: + dbConfig: + # 主键类型 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID + # 如需改为自增 需要将数据库表全部设置为自增 + idType: ASSIGN_ID + # 是否开启MyBatis Plus sql执行日志 +# configuration: +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + +# 数据加密 +mybatis-encryptor: + # 是否开启加密 + enable: false + # 默认加密算法 + algorithm: BASE64 + # 编码方式 BASE64/HEX。默认BASE64 + encode: BASE64 + # 安全秘钥 对称算法的秘钥 如:AES,SM4 + password: + # 公私钥 非对称算法的公私钥 如:SM2,RSA + publicKey: + privateKey: + +# api接口加密 +api-decrypt: + # 是否开启全局接口加密 + enabled: true + # AES 加密头标识 + headerFlag: encrypt-key + # 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 + # 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= + publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ== + # 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 + # 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== + privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= + +springdoc: + api-docs: + # 是否开启接口文档 + enabled: true +# swagger-ui: +# # 持久化认证数据 +# persistAuthorization: true + info: + # 标题 + title: '标题:${ruoyi.name}多租户管理系统_接口文档' + # 描述 + description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' + # 版本 + version: '版本号: ${ruoyi.version}' + # 作者信息 + contact: + name: Lion Li + email: crazylionli@163.com + url: https://gitee.com/dromara/RuoYi-Vue-Plus + components: + # 鉴权方式配置 + security-schemes: + apiKey: + type: APIKEY + in: HEADER + name: ${sa-token.token-name} + #这里定义了两个分组,可定义多个,也可以不定义 + group-configs: + - group: 1.演示模块 + packages-to-scan: org.dromara.demo + - group: 2.通用模块 + packages-to-scan: org.dromara.web + - group: 3.系统模块 + packages-to-scan: org.dromara.system + - group: 4.代码生成模块 + packages-to-scan: org.dromara.generator + - group: 5.工作流模块 + packages-to-scan: org.dromara.workflow + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludeUrls: + - /system/notice + - /warm-flow/save-xml + +# 全局线程池相关配置 +# 如使用JDK21请直接使用虚拟线程 不要开启此配置 +thread-pool: + # 是否开启线程池 + enabled: false + # 队列最大长度 + queueCapacity: 128 + # 线程池维护线程所允许的空闲时间 + keepAliveSeconds: 300 + +--- # 分布式锁 lock4j 全局配置 +lock4j: + # 获取分布式锁超时时间,默认为 3000 毫秒 + acquire-timeout: 3000 + # 分布式锁的超时时间,默认为 30 秒 + expire: 30000 + +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: ALWAYS + logfile: + external-file: ./logs/sys-console.log + +--- # 默认/推荐使用sse推送 +sse: + enabled: true + path: /resource/sse + +--- # websocket +websocket: + # 如果关闭 需要和前端开关一起关闭 + enabled: false + # 路径 + path: /resource/websocket + # 设置访问源地址 + allowedOrigins: '*' + +--- # warm-flow工作流配置 +warm-flow: + # 是否开启工作流,默认true + enabled: true + # 是否开启设计器ui + ui: true + # 默认Authorization,如果有多个token,用逗号分隔 + token-name: ${sa-token.token-name},clientid + + +pdd: + app: + clientId: 203c5a7ba8bd4b8488d5e26f93052642 + clientSecret: 892ffaa86e12b7a3d8d2942b669d9aa520ad8179 + +kongfz: + appId: 12345 + appSecret: 4d9829df96cc9ec60b2754453e88fe3e68b187a1407c72774667aaf2b457c12a + accessToken: your_access_token_here +wechat: + appid: wx703b8fb6c3da692a + secret: c691dea9dfde1da7ae51c34f5a6d3d53 + jscode2session-url: https://api.weixin.qq.com/sns/jscode2session + +forest: + max-connections: 2000 # 连接池最大连接数 + connect-timeout: 6000 # 连接超时时间,单位为毫秒 + read-timeout: 6000 # 数据读取超时时间,单位为毫秒 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..cce11c8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,61 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +auth.grant.type.error=认证权限类型错误 +auth.grant.type.blocked=认证权限类型已禁用 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序[code]不能为空 +social.source.not.blank=第三方登录平台[source]不能为空 +social.code.not.blank=第三方登录平台[code]不能为空 +social.state.not.blank=第三方登录平台[state]不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..cce11c8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,61 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +auth.grant.type.error=认证权限类型错误 +auth.grant.type.blocked=认证权限类型已禁用 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 +xcx.code.not.blank=小程序[code]不能为空 +social.source.not.blank=第三方登录平台[source]不能为空 +social.code.not.blank=第三方登录平台[code]不能为空 +social.state.not.blank=第三方登录平台[state]不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-admin/src/main/resources/mapper/zhishu/BookBaseInfoMapper.xml b/ruoyi-admin/src/main/resources/mapper/zhishu/BookBaseInfoMapper.xml new file mode 100644 index 0000000..2687d35 --- /dev/null +++ b/ruoyi-admin/src/main/resources/mapper/zhishu/BookBaseInfoMapper.xml @@ -0,0 +1,21 @@ + + + + + + UPDATE book_base_info + SET + vio_book = #{vioBook}, + book_set = #{bookSet}, + onenum_mbooks = #{onenumMbooks}, + ill_publisher = #{illPublisher}, + ill_author=#{illAuthor}, + update_time = NOW() + WHERE id IN + + #{ids} + + + diff --git a/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java new file mode 100644 index 0000000..dba2323 --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java @@ -0,0 +1,45 @@ +package org.dromara.test; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * 断言单元测试案例 + * + * @author Lion Li + */ +@DisplayName("断言单元测试案例") +public class AssertUnitTest { + + @DisplayName("测试 assertEquals 方法") + @Test + public void testAssertEquals() { + Assertions.assertEquals("666", new String("666")); + Assertions.assertNotEquals("666", new String("666")); + } + + @DisplayName("测试 assertSame 方法") + @Test + public void testAssertSame() { + Object obj = new Object(); + Object obj1 = obj; + Assertions.assertSame(obj, obj1); + Assertions.assertNotSame(obj, obj1); + } + + @DisplayName("测试 assertTrue 方法") + @Test + public void testAssertTrue() { + Assertions.assertTrue(true); + Assertions.assertFalse(true); + } + + @DisplayName("测试 assertNull 方法") + @Test + public void testAssertNull() { + Assertions.assertNull(null); + Assertions.assertNotNull(null); + } + +} diff --git a/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java b/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java new file mode 100644 index 0000000..1db51df --- /dev/null +++ b/ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java @@ -0,0 +1,72 @@ +package org.dromara.test; + +import org.dromara.common.core.enums.UserType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +/** + * 带参数单元测试案例 + * + * @author Lion Li + */ +@DisplayName("带参数单元测试案例") +public class ParamUnitTest { + + @DisplayName("测试 @ValueSource 注解") + @ParameterizedTest + @ValueSource(strings = {"t1", "t2", "t3"}) + public void testValueSource(String str) { + System.out.println(str); + } + + @DisplayName("测试 @NullSource 注解") + @ParameterizedTest + @NullSource + public void testNullSource(String str) { + System.out.println(str); + } + + @DisplayName("测试 @EnumSource 注解") + @ParameterizedTest + @EnumSource(UserType.class) + public void testEnumSource(UserType type) { + System.out.println(type.getUserType()); + } + + @DisplayName("测试 @MethodSource 注解") + @ParameterizedTest + @MethodSource("getParam") + public void testMethodSource(String str) { + System.out.println(str); + } + + public static Stream getParam() { + List list = new ArrayList<>(); + list.add("t1"); + list.add("t2"); + list.add("t3"); + return list.stream(); + } + + @BeforeEach + public void testBeforeEach() { + System.out.println("@BeforeEach =================="); + } + + @AfterEach + public void testAfterEach() { + System.out.println("@AfterEach =================="); + } + + +} diff --git a/ruoyi-admin/zhFonts/.uuid b/ruoyi-admin/zhFonts/.uuid new file mode 100644 index 0000000..cee5cdd --- /dev/null +++ b/ruoyi-admin/zhFonts/.uuid @@ -0,0 +1 @@ +3f2ee348-0303-40ca-bf03-03f48d2d2141 \ No newline at end of file diff --git a/ruoyi-admin/zhFonts/fonts.dir b/ruoyi-admin/zhFonts/fonts.dir new file mode 100644 index 0000000..fed9544 --- /dev/null +++ b/ruoyi-admin/zhFonts/fonts.dir @@ -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/pom.xml b/ruoyi-common/pom.xml new file mode 100644 index 0000000..2930fd0 --- /dev/null +++ b/ruoyi-common/pom.xml @@ -0,0 +1,46 @@ + + + + ruoyi-vue-plus + org.dromara + ${revision} + + 4.0.0 + + + ruoyi-common-bom + ruoyi-common-social + ruoyi-common-core + ruoyi-common-doc + ruoyi-common-excel + ruoyi-common-idempotent + ruoyi-common-job + ruoyi-common-log + ruoyi-common-mail + ruoyi-common-mybatis + ruoyi-common-oss + ruoyi-common-ratelimiter + ruoyi-common-redis + ruoyi-common-satoken + ruoyi-common-security + ruoyi-common-sms + ruoyi-common-web + ruoyi-common-translation + ruoyi-common-sensitive + ruoyi-common-json + ruoyi-common-encrypt + ruoyi-common-tenant + ruoyi-common-websocket + ruoyi-common-sse + + + ruoyi-common + pom + + + common 通用模块 + + + diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml new file mode 100644 index 0000000..24acb08 --- /dev/null +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -0,0 +1,185 @@ + + + 4.0.0 + + org.dromara + ruoyi-common-bom + ${revision} + pom + + + ruoyi-common-bom common依赖项 + + + + 5.3.0 + + + + + + + org.dromara + ruoyi-common-core + ${revision} + + + + + org.dromara + ruoyi-common-doc + ${revision} + + + + + org.dromara + ruoyi-common-excel + ${revision} + + + + + org.dromara + ruoyi-common-idempotent + ${revision} + + + + + org.dromara + ruoyi-common-job + ${revision} + + + + + org.dromara + ruoyi-common-log + ${revision} + + + + + org.dromara + ruoyi-common-mail + ${revision} + + + + + org.dromara + ruoyi-common-mybatis + ${revision} + + + + + org.dromara + ruoyi-common-oss + ${revision} + + + + + org.dromara + ruoyi-common-ratelimiter + ${revision} + + + + + org.dromara + ruoyi-common-redis + ${revision} + + + + + org.dromara + ruoyi-common-satoken + ${revision} + + + + + org.dromara + ruoyi-common-security + ${revision} + + + + + org.dromara + ruoyi-common-sms + ${revision} + + + + org.dromara + ruoyi-common-social + ${revision} + + + + + org.dromara + ruoyi-common-web + ${revision} + + + + + org.dromara + ruoyi-common-translation + ${revision} + + + + + org.dromara + ruoyi-common-sensitive + ${revision} + + + + + org.dromara + ruoyi-common-json + ${revision} + + + + + org.dromara + ruoyi-common-encrypt + ${revision} + + + + + org.dromara + ruoyi-common-tenant + ${revision} + + + + + org.dromara + ruoyi-common-websocket + ${revision} + + + + + org.dromara + ruoyi-common-sse + ${revision} + + + + + + diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml new file mode 100644 index 0000000..ad37e90 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/pom.xml @@ -0,0 +1,99 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-core + + + ruoyi-common-core 核心模块 + + + + + + org.springframework + spring-context-support + + + + + org.springframework + spring-web + + + + + org.springframework.boot + spring-boot-starter-validation + + + + org.springframework.boot + spring-boot-starter-aop + + + + + org.apache.commons + commons-lang3 + + + + + jakarta.servlet + jakarta.servlet-api + + + + cn.hutool + hutool-core + + + + cn.hutool + hutool-http + + + + cn.hutool + hutool-extra + + + + org.projectlombok + lombok + + + + + org.springframework.boot + spring-boot-configuration-processor + + + + org.springframework.boot + spring-boot-properties-migrator + runtime + + + + io.github.linpeilie + mapstruct-plus-spring-boot-starter + + + + + org.lionsoul + ip2region + + + + + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java new file mode 100644 index 0000000..d9f70e4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java @@ -0,0 +1,17 @@ +package org.dromara.common.core.config; + +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableAsync; + +/** + * 程序注解配置 + * + * @author Lion Li + */ +@AutoConfiguration +@EnableAspectJAutoProxy +@EnableAsync(proxyTargetClass = true) +public class ApplicationConfig { + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java new file mode 100644 index 0000000..d357d3d --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/RuoYiConfig.java @@ -0,0 +1,38 @@ +package org.dromara.common.core.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 读取项目相关配置 + * + * @author Lion Li + */ + +@Data +@Component +@ConfigurationProperties(prefix = "ruoyi") +public class RuoYiConfig { + + /** + * 项目名称 + */ + private String name; + + /** + * 版本 + */ + private String version; + + /** + * 版权年份 + */ + private String copyrightYear; + + /** + * 后台调用前台url + */ + private String ipurl; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java new file mode 100644 index 0000000..2630485 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java @@ -0,0 +1,87 @@ +package org.dromara.common.core.config; + +import jakarta.annotation.PreDestroy; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.dromara.common.core.config.properties.ThreadPoolProperties; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.Threads; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.core.task.VirtualThreadTaskExecutor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 线程池配置 + * + * @author Lion Li + **/ +@Slf4j +@AutoConfiguration +@EnableConfigurationProperties(ThreadPoolProperties.class) +public class ThreadPoolConfig { + + /** + * 核心线程数 = cpu 核心数 + 1 + */ + private final int core = Runtime.getRuntime().availableProcessors() + 1; + + private ScheduledExecutorService scheduledExecutorService; + + @Bean(name = "threadPoolTaskExecutor") + @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") + public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(core); + executor.setMaxPoolSize(core * 2); + executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); + executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + return executor; + } + + /** + * 执行周期性或定时任务 + */ + @Bean(name = "scheduledExecutorService") + protected ScheduledExecutorService scheduledExecutorService() { + // daemon 必须为 true + BasicThreadFactory.Builder builder = new BasicThreadFactory.Builder().daemon(true); + if (SpringUtils.isVirtual()) { + builder.namingPattern("virtual-schedule-pool-%d").wrappedFactory(new VirtualThreadTaskExecutor().getVirtualThreadFactory()); + } else { + builder.namingPattern("schedule-pool-%d"); + } + ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core, + builder.build(), + new ThreadPoolExecutor.CallerRunsPolicy()) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + Threads.printException(r, t); + } + }; + this.scheduledExecutorService = scheduledThreadPoolExecutor; + return scheduledThreadPoolExecutor; + } + + /** + * 销毁事件 + */ + @PreDestroy + public void destroy() { + try { + log.info("====关闭后台任务任务线程池===="); + Threads.shutdownAndAwaitTermination(scheduledExecutorService); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java new file mode 100644 index 0000000..45c5bd1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java @@ -0,0 +1,40 @@ +package org.dromara.common.core.config; + +import jakarta.validation.Validator; +import org.hibernate.validator.HibernateValidator; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.MessageSource; +import org.springframework.context.annotation.Bean; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; + +import java.util.Properties; + +/** + * 校验框架配置类 + * + * @author Lion Li + */ +@AutoConfiguration +public class ValidatorConfig { + + /** + * 配置校验框架 快速返回模式 + */ + @Bean + public Validator validator(MessageSource messageSource) { + try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) { + // 国际化 + factoryBean.setValidationMessageSource(messageSource); + // 设置使用 HibernateValidator 校验器 + factoryBean.setProviderClass(HibernateValidator.class); + Properties properties = new Properties(); + // 设置 快速异常返回 + properties.setProperty("hibernate.validator.fail_fast", "true"); + factoryBean.setValidationProperties(properties); + // 加载配置 + factoryBean.afterPropertiesSet(); + return factoryBean.getValidator(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ZhishuConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ZhishuConfig.java new file mode 100644 index 0000000..e1b23e9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ZhishuConfig.java @@ -0,0 +1,58 @@ +package org.dromara.common.core.config; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import org.dromara.common.core.factory.YmlPropertySourceFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +/** + * @author: Sheldon Jia + * @ClassName: LoginConfig + * @Description: 登录功能配置项 + * @date: 2025/05/04 + */ +@Data +@Component +@ConfigurationProperties(prefix = "zhishu") +// @PropertySource(value = "classpath:base-${spring.profiles.active:dev}.yml", factory = YmlPropertySourceFactory.class) +public class ZhishuConfig { + + /** + * url + */ + private String url; + + /** + * filterUrl + */ + private String filterUrl; + + /** + * kfz服务地址 + */ + private String kfzServiceUrl; + + /** + * 历史商品Excel文件目录地址 + */ + private String historyShopGodSExcelFilePath; + + /** + * 新增商品Excel文件暂存目录地址 + */ + private String newShopGodSExcelFilePath; + + /** + * 变更商品Excel文件暂存目录地址 + */ + private String changedShopGodSExcelFilePath; + + /** + * 异常商品Excel文件暂存目录地址 + */ + private String errorShopGodSExcelFilePath; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java new file mode 100644 index 0000000..820564f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/properties/ThreadPoolProperties.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.config.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 线程池 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "thread-pool") +public class ThreadPoolProperties { + + /** + * 是否开启线程池 + */ + private boolean enabled; + + /** + * 队列最大长度 + */ + private int queueCapacity; + + /** + * 线程池维护线程所允许的空闲时间 + */ + private int keepAliveSeconds; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java new file mode 100644 index 0000000..ceb8370 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.constant; + +/** + * 缓存的key 常量 + * + * @author Lion Li + */ +public interface CacheConstants { + + /** + * 在线用户 redis key + */ + String ONLINE_TOKEN_KEY = "online_tokens:"; + + /** + * 参数管理 cache key + */ + String SYS_CONFIG_KEY = "sys_config:"; + + /** + * 字典管理 cache key + */ + String SYS_DICT_KEY = "sys_dict:"; + + /** + * 登录账户密码错误次数 redis key + */ + String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java new file mode 100644 index 0000000..273c734 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java @@ -0,0 +1,76 @@ +package org.dromara.common.core.constant; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public interface Constants { + + /** + * UTF-8 字符集 + */ + String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + String GBK = "GBK"; + + /** + * www主域 + */ + String WWW = "www."; + + /** + * http请求 + */ + String HTTP = "http://"; + + /** + * https请求 + */ + String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + String FAIL = "1"; + + /** + * 登录成功 + */ + String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + String LOGOUT = "Logout"; + + /** + * 注册 + */ + String REGISTER = "Register"; + + /** + * 登录失败 + */ + String LOGIN_FAIL = "Error"; + + /** + * 验证码有效期(分钟) + */ + Integer CAPTCHA_EXPIRATION = 2; + + /** + * 顶级父级id + */ + Long TOP_PARENT_ID = 0L; + +} + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java new file mode 100644 index 0000000..85566e8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java @@ -0,0 +1,93 @@ +package org.dromara.common.core.constant; + +/** + * 返回状态码 + * + * @author Lion Li + */ +public interface HttpStatus { + /** + * 操作成功 + */ + int SUCCESS = 200; + + /** + * 对象创建成功 + */ + int CREATED = 201; + + /** + * 请求已经被接受 + */ + int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + int MOVED_PERM = 301; + + /** + * 重定向 + */ + int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + int BAD_REQUEST = 400; + + /** + * 未授权 + */ + int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + int ERROR = 500; + + /** + * 接口未实现 + */ + int NOT_IMPLEMENTED = 501; + + /** + * 系统警告消息 + */ + int WARN = 601; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java new file mode 100644 index 0000000..55240bb --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java @@ -0,0 +1,75 @@ +package org.dromara.common.core.constant; + +/** + * 系统常量信息 + * + * @author Lion Li + */ +public interface SystemConstants { + + /** + * 正常状态 + */ + String NORMAL = "0"; + + /** + * 异常状态 + */ + String DISABLE = "1"; + + /** + * 是否为系统默认(是) + */ + String YES = "Y"; + + /** + * 是否为系统默认(否) + */ + String NO = "N"; + + /** + * 是否菜单外链(是) + */ + String YES_FRAME = "0"; + + /** + * 是否菜单外链(否) + */ + String NO_FRAME = "1"; + + /** + * 菜单类型(目录) + */ + String TYPE_DIR = "M"; + + /** + * 菜单类型(菜单) + */ + String TYPE_MENU = "C"; + + /** + * 菜单类型(按钮) + */ + String TYPE_BUTTON = "F"; + + /** + * Layout组件标识 + */ + String LAYOUT = "Layout"; + + /** + * ParentView组件标识 + */ + String PARENT_VIEW = "ParentView"; + + /** + * InnerLink组件标识 + */ + String INNER_LINK = "InnerLink"; + + /** + * 超级管理员ID + */ + Long SUPER_ADMIN_ID = 1L; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java new file mode 100644 index 0000000..33ce0cf --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java @@ -0,0 +1,35 @@ +package org.dromara.common.core.constant; + +/** + * 租户常量信息 + * + * @author Lion Li + */ +public interface TenantConstants { + + /** + * 超级管理员ID + */ + Long SUPER_ADMIN_ID = 1L; + + /** + * 超级管理员角色 roleKey + */ + String SUPER_ADMIN_ROLE_KEY = "superadmin"; + + /** + * 租户管理员角色 roleKey + */ + String TENANT_ADMIN_ROLE_KEY = "admin"; + + /** + * 租户管理员角色名称 + */ + String TENANT_ADMIN_ROLE_NAME = "管理员"; + + /** + * 默认租户ID + */ + String DEFAULT_TENANT_ID = "000000"; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java new file mode 100644 index 0000000..be85805 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java @@ -0,0 +1,110 @@ +package org.dromara.common.core.domain; + +import org.dromara.common.core.constant.HttpStatus; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class R implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 成功 + */ + public static final int SUCCESS = 200; + + /** + * 失败 + */ + public static final int FAIL = 500; + + private int code; + + private String msg; + + private T data; + + public static R ok() { + return restResult(null, SUCCESS, "操作成功"); + } + + public static R ok(T data) { + return restResult(data, SUCCESS, "操作成功"); + } + + public static R ok(String msg) { + return restResult(null, SUCCESS, msg); + } + + public static R ok(String msg, T data) { + return restResult(data, SUCCESS, msg); + } + + public static R fail() { + return restResult(null, FAIL, "操作失败"); + } + + public static R fail(String msg) { + return restResult(null, FAIL, msg); + } + + public static R fail(T data) { + return restResult(data, FAIL, "操作失败"); + } + + public static R fail(String msg, T data) { + return restResult(data, FAIL, msg); + } + + public static R fail(int code, String msg) { + return restResult(null, code, msg); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static R warn(String msg) { + return restResult(null, HttpStatus.WARN, msg); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static R warn(String msg, T data) { + return restResult(data, HttpStatus.WARN, msg); + } + + private static R restResult(T data, int code, String msg) { + R r = new R<>(); + r.setCode(code); + r.setData(data); + r.setMsg(msg); + return r; + } + + public static Boolean isError(R ret) { + return !isSuccess(ret); + } + + public static Boolean isSuccess(R ret) { + return R.SUCCESS == ret.getCode(); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java new file mode 100644 index 0000000..2e63f8a --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java @@ -0,0 +1,71 @@ +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.List; +import java.util.Map; +import java.util.Objects; + +/** + * 办理任务请求对象 + * + * @author may + */ +@Data +public class CompleteTaskDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 抄送人员 + */ + private List flowCopyList; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 办理意见 + */ + private String message; + + /** + * 消息通知 + */ + private String notice; + + /** + * 流程变量 + */ + private Map variables; + + /** + * 扩展变量(此处为逗号分隔的ossId) + */ + private String ext; + + 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/FlowCopyDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java new file mode 100644 index 0000000..2f20b21 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 抄送 + * + * @author may + */ +@Data +public class FlowCopyDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户id + */ + private Long userId; + + /** + * 用户名称 + */ + private String userName; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java new file mode 100644 index 0000000..463821c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.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; + +/** + * OSS对象 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class OssDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 对象存储主键 + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java new file mode 100644 index 0000000..aea8e7a --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java @@ -0,0 +1,42 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 角色 + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class RoleDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 角色ID + */ + private Long roleId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色权限 + */ + private String roleKey; + + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + private String dataScope; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java new file mode 100644 index 0000000..9bcbd12 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.domain.dto; + + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 启动流程返回对象 + * + * @author Lion Li + */ +@Data +public class StartProcessReturnDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + private Long processInstanceId; + + /** + * 任务id + */ + private Long taskId; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java new file mode 100644 index 0000000..85893e1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java @@ -0,0 +1,101 @@ +package org.dromara.common.core.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 任务受让人 + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class TaskAssigneeDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 总大小 + */ + private Long total = 0L; + + /** + * + */ + private List list; + + public TaskAssigneeDTO(Long total, List list) { + this.total = total; + this.list = list; + } + + /** + * 将源列表转换为 TaskHandler 列表 + * + * @param 通用类型 + * @param sourceList 待转换的源列表 + * @param storageId 提取 storageId 的函数 + * @param handlerCode 提取 handlerCode 的函数 + * @param handlerName 提取 handlerName 的函数 + * @param groupName 提取 groupName 的函数 + * @param createTimeMapper 提取 createTime 的函数 + * @return 转换后的 TaskHandler 列表 + */ + public static List convertToHandlerList( + List sourceList, + Function storageId, + Function handlerCode, + Function handlerName, + Function groupName, + Function createTimeMapper) { + return sourceList.stream() + .map(item -> new TaskHandler( + String.valueOf(storageId.apply(item)), + handlerCode.apply(item), + handlerName.apply(item), + groupName != null ? String.valueOf(groupName.apply(item)) : null, + createTimeMapper.apply(item) + )).collect(Collectors.toList()); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class TaskHandler { + + /** + * 主键 + */ + private String storageId; + + /** + * 权限编码 + */ + private String handlerCode; + + /** + * 权限名称 + */ + private String handlerName; + + /** + * 权限分组 + */ + private String groupName; + + /** + * 创建时间 + */ + private Date createTime; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java new file mode 100644 index 0000000..43d8c3c --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java @@ -0,0 +1,72 @@ +package org.dromara.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 当前在线会话 + * + * @author ruoyi + */ + +@Data +@NoArgsConstructor +public class UserOnlineDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 会话编号 + */ + private String tokenId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 用户名称 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地址 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java new file mode 100644 index 0000000..33bc6e5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java @@ -0,0 +1,44 @@ +package org.dromara.common.core.domain.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 流程办理监听 + * + * @author may + */ +@Data +public class ProcessTaskEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 审批节点编码 + */ + private String nodeCode; + + /** + * 任务id + */ + private Long taskId; + + /** + * 业务id + */ + private String businessId; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java new file mode 100644 index 0000000..ffde8c6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 邮件登录对象 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class EmailLoginBody extends LoginBody { + + /** + * 邮箱 + */ + @NotBlank(message = "{user.email.not.blank}") + @Email(message = "{user.email.not.valid}") + private String email; + + /** + * 邮箱code + */ + @NotBlank(message = "{email.code.not.blank}") + private String emailCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/InterfaceLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/InterfaceLoginBody.java new file mode 100644 index 0000000..3ca771a --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/InterfaceLoginBody.java @@ -0,0 +1,14 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class InterfaceLoginBody extends LoginBody { + + /** + * 用户密码 + */ + private String password; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java new file mode 100644 index 0000000..846ae33 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java @@ -0,0 +1,66 @@ +package org.dromara.common.core.domain.model; + +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户登录对象 + * + * @author Lion Li + */ + +@Data +public class LoginBody implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 客户端id + */ + @NotBlank(message = "{auth.clientid.not.blank}") + private String clientId; + + /** + * 授权类型 + */ + @NotBlank(message = "{auth.grant.type.not.blank}") + private String grantType; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 验证码 + */ + private String code; + + /** + * 唯一标识 + */ + private String uuid; + + private String phoneNumber; + + /** + * 用户名 + */ + private String userName; + + /** + * longinCode + */ + private String login_code; + + /** + * token + */ + private String token; +} + + diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java new file mode 100644 index 0000000..0ae3205 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java @@ -0,0 +1,153 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.core.domain.dto.PostDTO; +import org.dromara.common.core.domain.dto.RoleDTO; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 登录用户身份权限 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class LoginUser implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 部门类别编码 + */ + private String deptCategory; + + /** + * 部门名 + */ + private String deptName; + + /** + * 用户唯一标识 + */ + private String token; + + /** + * 用户类型 + */ + private String userType; + + /** + * 登录时间 + */ + private Long loginTime; + + /** + * 过期时间 + */ + private Long expireTime; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 菜单权限 + */ + private Set menuPermission; + + /** + * 角色权限 + */ + private Set rolePermission; + + /** + * 用户名 + */ + private String username; + + /** + * 用户昵称 + */ + private String nickname; + + /** + * 角色对象 + */ + private List roles; + + /** + * 岗位对象 + */ + private List posts; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 新仓库系统登录信息 + */ + private Map warehouseLoginUser; + /** + * 获取登录id + */ + public String getLoginId() { + if (userType == null) { + throw new IllegalArgumentException("用户类型不能为空"); + } + if (userId == null) { + throw new IllegalArgumentException("用户ID不能为空"); + } + return userType + ":" + userId; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java new file mode 100644 index 0000000..a878348 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java @@ -0,0 +1,29 @@ +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 SmsLoginBody extends LoginBody { + + /** + * 手机号 + */ + @NotBlank(message = "{user.phonenumber.not.blank}") + private String phonenumber; + + /** + * 短信code + */ + @NotBlank(message = "{sms.code.not.blank}") + private String smsCode; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java new file mode 100644 index 0000000..0d1b121 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java @@ -0,0 +1,35 @@ +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 SocialLoginBody extends LoginBody { + + /** + * 第三方登录平台 + */ + @NotBlank(message = "{social.source.not.blank}") + private String source; + + /** + * 第三方登录code + */ + @NotBlank(message = "{social.code.not.blank}") + private String socialCode; + + /** + * 第三方登录socialState + */ + @NotBlank(message = "{social.state.not.blank}") + private String socialState; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java new file mode 100644 index 0000000..0cbed2f --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java @@ -0,0 +1,56 @@ +package org.dromara.common.core.domain.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 任务受让人 + * + * @author AprilWind + */ +@Data +@NoArgsConstructor +public class TaskAssigneeBody implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 权限编码 + */ + private String handlerCode; + + /** + * 权限名称 + */ + private String handlerName; + + /** + * 权限分组 + */ + private String groupId; + + /** + * 开始时间 + */ + private String beginTime; + + /** + * 结束时间 + */ + private String endTime; + + /** + * 当前页 + */ + private Integer pageNum = 1; + + /** + * 每页显示条数 + */ + private Integer pageSize = 10; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java new file mode 100644 index 0000000..dbadfc2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对一套 用户体系 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DeviceType { + + /** + * pc端 + */ + PC("pc"), + + /** + * app端 + */ + APP("app"), + + /** + * 小程序端 + */ + XCX("xcx"), + + /** + * social第三方端 + */ + SOCIAL("social"); + + private final String device; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java new file mode 100644 index 0000000..f9cac66 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java @@ -0,0 +1,44 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum LoginType { + + /** + * 密码登录 + */ + PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), + + /** + * 短信登录 + */ + SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), + + /** + * 邮箱登录 + */ + EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"), + + /** + * 小程序登录 + */ + XCX("", ""); + + /** + * 登录重试超出限制提示 + */ + final String retryLimitExceed; + + /** + * 登录重试限制计数提示 + */ + final String retryLimitCount; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java new file mode 100644 index 0000000..be7e44d --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java @@ -0,0 +1,30 @@ +package org.dromara.common.core.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 用户状态 + * + * @author ruoyi + */ +@Getter +@AllArgsConstructor +public enum UserStatus { + /** + * 正常 + */ + OK("0", "正常"), + /** + * 停用 + */ + DISABLE("1", "停用"), + /** + * 删除 + */ + DELETED("2", "删除"); + + private final String code; + private final String info; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java new file mode 100644 index 0000000..69e4753 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.enums; + +import org.dromara.common.core.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对多套 用户体系 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum UserType { + + /** + * pc端 + */ + SYS_USER("sys_user"), + + /** + * app端 + */ + APP_USER("app_user"); + + private final String userType; + + public static UserType getUserType(String str) { + for (UserType value : values()) { + if (StringUtils.contains(str, value.getUserType())) { + return value; + } + } + throw new RuntimeException("'UserType' not found By " + str); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java new file mode 100644 index 0000000..e9dc6ec --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java @@ -0,0 +1,59 @@ +package org.dromara.common.core.exception; + +import lombok.*; + +import java.io.Serial; + +/** + * 业务异常 + * + * @author ruoyi + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +public final class ServiceException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + */ + private String detailMessage; + + public ServiceException(String message) { + this.message = message; + } + + public ServiceException(String message, Integer code) { + this.message = message; + this.code = code; + } + + @Override + public String getMessage() { + return message; + } + + public ServiceException setMessage(String message) { + this.message = message; + return this; + } + + public ServiceException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java new file mode 100644 index 0000000..a76e16d --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java @@ -0,0 +1,62 @@ +package org.dromara.common.core.exception; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.io.Serial; + +/** + * sse 特制异常 + * + * @author LionLi + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@AllArgsConstructor +public final class SseException extends RuntimeException { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + */ + private String detailMessage; + + public SseException(String message) { + this.message = message; + } + + public SseException(String message, Integer code) { + this.message = message; + this.code = code; + } + + @Override + public String getMessage() { + return message; + } + + public SseException setMessage(String message) { + this.message = message; + return this; + } + + public SseException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java new file mode 100644 index 0000000..af98124 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.file; + +import java.io.Serial; + +/** + * 文件名称超长限制异常类 + * + * @author ruoyi + */ +public class FileNameLengthLimitExceededException extends FileException { + + @Serial + private static final long serialVersionUID = 1L; + + public FileNameLengthLimitExceededException(int defaultFileNameLength) { + super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java new file mode 100644 index 0000000..1eb8d40 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.file; + +import java.io.Serial; + +/** + * 文件名大小限制异常类 + * + * @author ruoyi + */ +public class FileSizeLimitExceededException extends FileException { + + @Serial + private static final long serialVersionUID = 1L; + + public FileSizeLimitExceededException(long defaultMaxSize) { + super("upload.exceed.maxSize", new Object[]{defaultMaxSize}); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java new file mode 100644 index 0000000..43824e0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.user; + +import java.io.Serial; + +/** + * 验证码错误异常类 + * + * @author ruoyi + */ +public class CaptchaException extends UserException { + + @Serial + private static final long serialVersionUID = 1L; + + public CaptchaException() { + super("user.jcaptcha.error"); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java new file mode 100644 index 0000000..f4b8cac --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.exception.user; + +import java.io.Serial; + +/** + * 验证码失效异常类 + * + * @author ruoyi + */ +public class CaptchaExpireException extends UserException { + + @Serial + private static final long serialVersionUID = 1L; + + public CaptchaExpireException() { + super("user.jcaptcha.expire"); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java new file mode 100644 index 0000000..024fed6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java @@ -0,0 +1,20 @@ +package org.dromara.common.core.exception.user; + +import org.dromara.common.core.exception.base.BaseException; + +import java.io.Serial; + +/** + * 用户信息异常类 + * + * @author ruoyi + */ +public class UserException extends BaseException { + + @Serial + private static final long serialVersionUID = 1L; + + public UserException(String code, Object... args) { + super("user", code, args, null); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java new file mode 100644 index 0000000..7328c69 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java @@ -0,0 +1,18 @@ +package org.dromara.common.core.service; + +/** + * 通用 参数配置服务 + * + * @author Lion Li + */ +public interface ConfigService { + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + String getConfigValue(String configKey); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java new file mode 100644 index 0000000..f93d177 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.DeptDTO; + +import java.util.List; + +/** + * 通用 部门服务 + * + * @author Lion Li + */ +public interface DeptService { + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + String selectDeptNameByIds(String deptIds); + + /** + * 根据部门ID查询部门负责人 + * + * @param deptId 部门ID,用于指定需要查询的部门 + * @return 返回该部门的负责人ID + */ + Long selectDeptLeaderById(Long deptId); + + /** + * 查询部门 + * + * @return 部门列表 + */ + List selectDeptsByList(); + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java new file mode 100644 index 0000000..1a52de0 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java @@ -0,0 +1,29 @@ +package org.dromara.common.core.service; + +import org.dromara.common.core.domain.dto.OssDTO; + +import java.util.List; + +/** + * 通用 OSS服务 + * + * @author Lion Li + */ +public interface OssService { + + /** + * 通过ossId查询对应的url + * + * @param ossIds ossId串逗号分隔 + * @return url串逗号分隔 + */ + String selectUrlByIds(String ossIds); + + /** + * 通过ossId查询列表 + * + * @param ossIds ossId串逗号分隔 + * @return 列表 + */ + List selectByIds(String ossIds); +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java new file mode 100644 index 0000000..41d4e83 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java @@ -0,0 +1,10 @@ +package org.dromara.common.core.service; + +/** + * 通用 岗位服务 + * + * @author AprilWind + */ +public interface PostService { + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java new file mode 100644 index 0000000..ba62c82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java @@ -0,0 +1,10 @@ +package org.dromara.common.core.service; + +/** + * 通用 角色服务 + * + * @author AprilWind + */ +public interface RoleService { + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java new file mode 100644 index 0000000..1221755 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java @@ -0,0 +1,299 @@ +package org.dromara.common.core.utils; + +import org.apache.commons.lang3.time.DateFormatUtils; +import org.dromara.common.core.enums.FormatsType; +import org.dromara.common.core.exception.ServiceException; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.*; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * 时间工具类 + * + * @author ruoyi + */ +public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + private static final String[] PARSE_PATTERNS = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + + @Deprecated + private DateUtils() { + } + + /** + * 获取当前日期和时间 + * + * @return 当前日期和时间的 Date 对象表示 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取当前日期的字符串表示,格式为YYYY-MM-DD + * + * @return 当前日期的字符串表示 + */ + public static String getDate() { + return dateTimeNow(FormatsType.YYYY_MM_DD); + } + + /** + * 获取当前日期的字符串表示,格式为yyyyMMdd + * + * @return 当前日期的字符串表示 + */ + public static String getCurrentDate() { + return DateFormatUtils.format(new Date(), FormatsType.YYYYMMDD.getTimeFormat()); + } + + /** + * 获取当前日期的路径格式字符串,格式为"yyyy/MM/dd" + * + * @return 当前日期的路径格式字符串 + */ + public static String datePath() { + Date now = new Date(); + return DateFormatUtils.format(now, FormatsType.YYYY_MM_DD_SLASH.getTimeFormat()); + } + + /** + * 获取当前时间的字符串表示,格式为YYYY-MM-DD HH:MM:SS + * + * @return 当前时间的字符串表示 + */ + public static String getTime() { + return dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS); + } + + /** + * 获取当前时间的字符串表示,格式为 "HH:MM:SS" + * + * @return 当前时间的字符串表示,格式为 "HH:MM:SS" + */ + public static String getTimeWithHourMinuteSecond() { + return dateTimeNow(FormatsType.HH_MM_SS); + } + + /** + * 获取当前日期和时间的字符串表示,格式为YYYYMMDDHHMMSS + * + * @return 当前日期和时间的字符串表示 + */ + public static String dateTimeNow() { + return dateTimeNow(FormatsType.YYYYMMDDHHMMSS); + } + + public static String dataYMD(){ + return dateTimeNow(FormatsType.YYYY_MM_DD); + } + + /** + * 获取当前日期和时间的指定格式的字符串表示 + * + * @param format 日期时间格式,例如"YYYY-MM-DD HH:MM:SS" + * @return 当前日期和时间的字符串表示 + */ + public static String dateTimeNow(final FormatsType format) { + return parseDateToStr(format, new Date()); + } + + /** + * 将指定日期格式化为 YYYY-MM-DD 格式的字符串 + * + * @param date 要格式化的日期对象 + * @return 格式化后的日期字符串 + */ + public static String formatDate(final Date date) { + return parseDateToStr(FormatsType.YYYY_MM_DD, date); + } + + /** + * 将指定日期格式化为 YYYY-MM-DD HH:MM:SS 格式的字符串 + * + * @param date 要格式化的日期对象 + * @return 格式化后的日期时间字符串 + */ + public static String formatDateTime(final Date date) { + return parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, date); + } + + /** + * 将指定日期按照指定格式进行格式化 + * + * @param format 要使用的日期时间格式,例如"YYYY-MM-DD HH:MM:SS" + * @param date 要格式化的日期对象 + * @return 格式化后的日期时间字符串 + */ + public static String parseDateToStr(final FormatsType format, final Date date) { + return new SimpleDateFormat(format.getTimeFormat()).format(date); + } + + /** + * 将指定格式的日期时间字符串转换为 Date 对象 + * + * @param format 要解析的日期时间格式,例如"YYYY-MM-DD HH:MM:SS" + * @param ts 要解析的日期时间字符串 + * @return 解析后的 Date 对象 + * @throws RuntimeException 如果解析过程中发生异常 + */ + public static Date parseDateTime(final FormatsType format, final String ts) { + try { + return new SimpleDateFormat(format.getTimeFormat()).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * 将对象转换为日期对象 + * + * @param str 要转换的对象,通常是字符串 + * @return 转换后的日期对象,如果转换失败或输入为null,则返回null + */ + public static Date parseDate(Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), PARSE_PATTERNS); + } catch (ParseException e) { + return null; + } + } + + /** + * 获取服务器启动时间 + * + * @return 服务器启动时间的 Date 对象表示 + */ + public static Date getServerStartDate() { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算两个日期之间的天数差(以毫秒为单位) + * + * @param date1 第一个日期 + * @param date2 第二个日期 + * @return 两个日期之间的天数差的绝对值 + */ + public static int differentDaysByMillisecond(Date date1, Date date2) { + return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); + } + + /** + * 计算两个日期之间的时间差,并以天、小时和分钟的格式返回 + * + * @param endDate 结束日期 + * @param nowDate 当前日期 + * @return 表示时间差的字符串,格式为"天 小时 分钟" + */ + public static String getDatePoor(Date endDate, Date nowDate) { + long diffInMillis = endDate.getTime() - nowDate.getTime(); + long day = TimeUnit.MILLISECONDS.toDays(diffInMillis); + long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24; + long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60; + return String.format("%d天 %d小时 %d分钟", day, hour, min); + } + + /** + * 计算两个时间点的差值(天、小时、分钟、秒),当值为0时不显示该单位 + * + * @param endDate 结束时间 + * @param nowDate 当前时间 + * @return 时间差字符串,格式为 "x天 x小时 x分钟 x秒",若为 0 则不显示 + */ + public static String getTimeDifference(Date endDate, Date nowDate) { + long diffInMillis = endDate.getTime() - nowDate.getTime(); + long day = TimeUnit.MILLISECONDS.toDays(diffInMillis); + long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24; + long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60; + long sec = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60; + // 构建时间差字符串,条件是值不为0才显示 + StringBuilder result = new StringBuilder(); + if (day > 0) { + result.append(String.format("%d天 ", day)); + } + if (hour > 0) { + result.append(String.format("%d小时 ", hour)); + } + if (min > 0) { + result.append(String.format("%d分钟 ", min)); + } + if (sec > 0) { + result.append(String.format("%d秒", sec)); + } + return result.length() > 0 ? result.toString().trim() : "0秒"; + } + + /** + * 将 LocalDateTime 对象转换为 Date 对象 + * + * @param temporalAccessor 要转换的 LocalDateTime 对象 + * @return 转换后的 Date 对象 + */ + public static Date toDate(LocalDateTime temporalAccessor) { + ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** + * 将 LocalDate 对象转换为 Date 对象 + * + * @param temporalAccessor 要转换的 LocalDate 对象 + * @return 转换后的 Date 对象 + */ + public static Date toDate(LocalDate temporalAccessor) { + LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0)); + ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** + * 校验日期范围 + * + * @param startDate 开始日期 + * @param endDate 结束日期 + * @param maxValue 最大时间跨度的限制值 + * @param unit 时间跨度的单位,可选择 "DAYS"、"HOURS" 或 "MINUTES" + */ + public static void validateDateRange(Date startDate, Date endDate, int maxValue, TimeUnit unit) { + // 校验结束日期不能早于开始日期 + if (endDate.before(startDate)) { + throw new ServiceException("结束日期不能早于开始日期"); + } + + // 计算时间跨度 + long diffInMillis = endDate.getTime() - startDate.getTime(); + + // 根据单位转换时间跨度 + long diff = switch (unit) { + case DAYS -> TimeUnit.MILLISECONDS.toDays(diffInMillis); + case HOURS -> TimeUnit.MILLISECONDS.toHours(diffInMillis); + case MINUTES -> TimeUnit.MILLISECONDS.toMinutes(diffInMillis); + default -> throw new IllegalArgumentException("不支持的时间单位"); + }; + + // 校验时间跨度不超过最大限制 + if (diff > maxValue) { + throw new ServiceException("最大时间跨度为 " + maxValue + " " + unit.toString().toLowerCase()); + } + } + + /** + * 获取当前时间+1天的时间 + * @return + */ + public static Date getNextDay() { + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return DateUtils.parseDateTime(FormatsType.YYYY_MM_DD_HH_MM_SS,df.format(new Date().getTime()+1*24*3600*1000)); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java new file mode 100644 index 0000000..48dfc08 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java @@ -0,0 +1,33 @@ +package org.dromara.common.core.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 获取i18n资源文件 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MessageUtils { + + private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class); + + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) { + try { + return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale()); + } catch (NoSuchMessageException e) { + return code; + } + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java new file mode 100644 index 0000000..bd1aab8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java @@ -0,0 +1,289 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.convert.Convert; +import cn.hutool.extra.servlet.JakartaServletUtil; +import cn.hutool.http.HttpStatus; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedCaseInsensitiveMap; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.io.IOException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * 客户端工具类,提供获取请求参数、响应处理、头部信息等常用操作 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ServletUtils extends JakartaServletUtil { + + /** + * 获取指定名称的 String 类型的请求参数 + * + * @param name 参数名 + * @return 参数值 + */ + public static String getParameter(String name) { + return getRequest().getParameter(name); + } + + /** + * 获取指定名称的 String 类型的请求参数,若参数不存在,则返回默认值 + * + * @param name 参数名 + * @param defaultValue 默认值 + * @return 参数值或默认值 + */ + public static String getParameter(String name, String defaultValue) { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取指定名称的 Integer 类型的请求参数 + * + * @param name 参数名 + * @return 参数值 + */ + public static Integer getParameterToInt(String name) { + return Convert.toInt(getRequest().getParameter(name)); + } + + /** + * 获取指定名称的 Integer 类型的请求参数,若参数不存在,则返回默认值 + * + * @param name 参数名 + * @param defaultValue 默认值 + * @return 参数值或默认值 + */ + public static Integer getParameterToInt(String name, Integer defaultValue) { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取指定名称的 Boolean 类型的请求参数 + * + * @param name 参数名 + * @return 参数值 + */ + public static Boolean getParameterToBool(String name) { + return Convert.toBool(getRequest().getParameter(name)); + } + + /** + * 获取指定名称的 Boolean 类型的请求参数,若参数不存在,则返回默认值 + * + * @param name 参数名 + * @param defaultValue 默认值 + * @return 参数值或默认值 + */ + public static Boolean getParameterToBool(String name, Boolean defaultValue) { + return Convert.toBool(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取所有请求参数(以 Map 的形式返回) + * + * @param request 请求对象{@link ServletRequest} + * @return 请求参数的 Map,键为参数名,值为参数值数组 + */ + public static Map getParams(ServletRequest request) { + final Map map = request.getParameterMap(); + return Collections.unmodifiableMap(map); + } + + /** + * 获取所有请求参数(以 Map 的形式返回,值为字符串形式的拼接) + * + * @param request 请求对象{@link ServletRequest} + * @return 请求参数的 Map,键为参数名,值为拼接后的字符串 + */ + public static Map getParamMap(ServletRequest request) { + Map params = new HashMap<>(); + for (Map.Entry entry : getParams(request).entrySet()) { + params.put(entry.getKey(), StringUtils.join(entry.getValue(), StringUtils.SEPARATOR)); + } + return params; + } + + /** + * 获取当前 HTTP 请求对象 + * + * @return 当前 HTTP 请求对象 + */ + public static HttpServletRequest getRequest() { + try { + return getRequestAttributes().getRequest(); + } catch (Exception e) { + return null; + } + } + + /** + * 获取当前 HTTP 响应对象 + * + * @return 当前 HTTP 响应对象 + */ + public static HttpServletResponse getResponse() { + try { + return getRequestAttributes().getResponse(); + } catch (Exception e) { + return null; + } + } + + /** + * 获取当前请求的 HttpSession 对象 + *

+ * 如果当前请求已经关联了一个会话(即已经存在有效的 session ID), + * 则返回该会话对象;如果没有关联会话,则会创建一个新的会话对象并返回。 + *

+ * HttpSession 用于存储会话级别的数据,如用户登录信息、购物车内容等, + * 可以在多个请求之间共享会话数据 + * + * @return 当前请求的 HttpSession 对象 + */ + public static HttpSession getSession() { + return getRequest().getSession(); + } + + /** + * 获取当前请求的请求属性 + * + * @return {@link ServletRequestAttributes} 请求属性对象 + */ + public static ServletRequestAttributes getRequestAttributes() { + try { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } catch (Exception e) { + return null; + } + } + + /** + * 获取指定请求头的值,如果头部为空则返回空字符串 + * + * @param request 请求对象 + * @param name 头部名称 + * @return 头部值 + */ + public static String getHeader(HttpServletRequest request, String name) { + String value = request.getHeader(name); + if (StringUtils.isEmpty(value)) { + return StringUtils.EMPTY; + } + return urlDecode(value); + } + + /** + * 获取所有请求头的 Map,键为头部名称,值为头部值 + * + * @param request 请求对象 + * @return 请求头的 Map + */ + public static Map getHeaders(HttpServletRequest request) { + Map map = new LinkedCaseInsensitiveMap<>(); + Enumeration enumeration = request.getHeaderNames(); + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + String key = enumeration.nextElement(); + String value = request.getHeader(key); + map.put(key, value); + } + } + return map; + } + + /** + * 将字符串渲染到客户端(以 JSON 格式返回) + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + */ + public static void renderString(HttpServletResponse response, String string) { + try { + response.setStatus(HttpStatus.HTTP_OK); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); + response.getWriter().print(string); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 判断当前请求是否为 Ajax 异步请求 + * + * @param request 请求对象 + * @return 是否为 Ajax 请求 + */ + public static boolean isAjaxRequest(HttpServletRequest request) { + + // 判断 Accept 头部是否包含 application/json + String accept = request.getHeader("accept"); + if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) { + return true; + } + + // 判断 X-Requested-With 头部是否包含 XMLHttpRequest + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) { + return true; + } + + // 判断 URI 后缀是否为 .json 或 .xml + String uri = request.getRequestURI(); + if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) { + return true; + } + + // 判断请求参数 __ajax 是否为 json 或 xml + String ajax = request.getParameter("__ajax"); + return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml"); + } + + /** + * 获取客户端 IP 地址 + * + * @return 客户端 IP 地址 + */ + public static String getClientIP() { + return getClientIP(getRequest()); + } + + /** + * 对内容进行 URL 编码 + * + * @param str 内容 + * @return 编码后的内容 + */ + public static String urlEncode(String str) { + return URLEncoder.encode(str, StandardCharsets.UTF_8); + } + + /** + * 对内容进行 URL 解码 + * + * @param str 内容 + * @return 解码后的内容 + */ + public static String urlDecode(String str) { + return URLDecoder.decode(str, StandardCharsets.UTF_8); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java new file mode 100644 index 0000000..169c6e2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java @@ -0,0 +1,67 @@ +package org.dromara.common.core.utils; + +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.thread.Threading; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +/** + * spring工具类 + * + * @author Lion Li + */ +@Component +public final class SpringUtils extends SpringUtil { + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + */ + public static boolean containsBean(String name) { + return getBeanFactory().containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 + * 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().isSingleton(name); + } + + /** + * @return Class 注册对象的类型 + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getAliases(name); + } + + /** + * 获取aop代理对象 + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) getBean(invoker.getClass()); + } + + + /** + * 获取spring上下文 + */ + public static ApplicationContext context() { + return getApplicationContext(); + } + + public static boolean isVirtual() { + return Threading.VIRTUAL.isActive(getBean(Environment.class)); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java new file mode 100644 index 0000000..1342deb --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java @@ -0,0 +1,283 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * stream 流工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StreamUtils { + + /** + * 将collection过滤 + * + * @param collection 需要转化的集合 + * @param function 过滤方法 + * @return 过滤后的list + */ + public static List filter(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + return collection.stream().filter(function).collect(Collectors.toList()); + } + + /** + * 找到流中满足条件的第一个元素 + * + * @param collection 需要查询的集合 + * @param function 过滤方法 + * @return 找到符合条件的第一个元素,没有则返回null + */ + public static E findFirst(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return null; + } + return collection.stream().filter(function).findFirst().orElse(null); + } + + /** + * 找到流中任意一个满足条件的元素 + * + * @param collection 需要查询的集合 + * @param function 过滤方法 + * @return 找到符合条件的任意一个元素,没有则返回null + */ + public static Optional findAny(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return Optional.empty(); + } + return collection.stream().filter(function).findAny(); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function) { + return join(collection, function, StringUtils.SEPARATOR); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @param delimiter 拼接符 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function, CharSequence delimiter) { + if (CollUtil.isEmpty(collection)) { + return StringUtils.EMPTY; + } + return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); + } + + /** + * 将collection排序 + * + * @param collection 需要转化的集合 + * @param comparing 排序方法 + * @return 排序后的list + */ + public static List sorted(Collection collection, Comparator comparing) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList()); + } + + /** + * 将collection转化为类型不变的map
+ * {@code Collection ----> Map} + * + * @param collection 需要转化的集合 + * @param key V类型转化为K类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @return 转化后的map + */ + public static Map toIdentityMap(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l)); + } + + /** + * 将Collection转化为map(value类型与collection的泛型不同)
+ * {@code Collection -----> Map } + * + * @param collection 需要转化的集合 + * @param key E类型转化为K类型的lambda方法 + * @param value E类型转化为V类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @param map中的value类型 + * @return 转化后的map + */ + public static Map toMap(Collection collection, Function key, Function value) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l)); + } + + /** + * 将collection按照规则(比如有相同的班级id)分类成map
+ * {@code Collection -------> Map> } + * + * @param collection 需要分类的集合 + * @param key 分类的规则 + * @param collection中的泛型 + * @param map中的key类型 + * @return 分类后的map + */ + public static Map> groupByKey(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map>> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 集合元素类型 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @return 分类后的map + */ + public static Map>> groupBy2Key(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @param collection中的泛型 + * @return 分类后的map + */ + public static Map> group2Map(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) { + return MapUtil.newHashMap(); + } + return collection + .stream().filter(Objects::nonNull) + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); + } + + /** + * 将collection转化为List集合,但是两者的泛型不同
+ * {@code Collection ------> List } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为list泛型的lambda表达式 + * @param collection中的泛型 + * @param List中的泛型 + * @return 转化后的list + */ + public static List toList(Collection collection, Function function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题 + .collect(Collectors.toList()); + } + + /** + * 将collection转化为Set集合,但是两者的泛型不同
+ * {@code Collection ------> Set } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为set泛型的lambda表达式 + * @param collection中的泛型 + * @param Set中的泛型 + * @return 转化后的Set + */ + public static Set toSet(Collection collection, Function function) { + if (CollUtil.isEmpty(collection) || function == null) { + return CollUtil.newHashSet(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + + /** + * 合并两个相同key类型的map + * + * @param map1 第一个需要合并的 map + * @param map2 第二个需要合并的 map + * @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况 + * @param map中的key类型 + * @param 第一个 map的value类型 + * @param 第二个 map的value类型 + * @param 最终map的value类型 + * @return 合并后的map + */ + public static Map merge(Map map1, Map map2, BiFunction merge) { + if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) { + return MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map1)) { + map1 = MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map2)) { + map2 = MapUtil.newHashMap(); + } + Set key = new HashSet<>(); + key.addAll(map1.keySet()); + key.addAll(map2.keySet()); + Map map = new HashMap<>(); + for (K t : key) { + X x = map1.get(t); + Y y = map2.get(t); + V z = merge.apply(x, y); + if (z != null) { + map.put(t, z); + } + } + return map; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java new file mode 100644 index 0000000..1663eef --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java @@ -0,0 +1,406 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import org.springframework.util.AntPathMatcher; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 字符串工具类 + * + * @author Lion Li + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + public static final String SEPARATOR = ","; + + public static final String SLASH = "/"; + + @Deprecated + private StringUtils() { + } + + /** + * 获取参数不为空值 + * + * @param str defaultValue 要判断的value + * @return value 返回值 + */ + public static String blankToDefault(String str, String defaultValue) { + return StrUtil.blankToDefault(str, defaultValue); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return StrUtil.isEmpty(str); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return StrUtil.trim(str); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + return substring(str, start, str.length()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + return StrUtil.sub(str, start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is {} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + return StrUtil.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) { + return Validator.isUrl(link); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static Set str2Set(String str, String sep) { + return new HashSet<>(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList<>(); + if (isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && isBlank(string)) { + continue; + } + if (trim) { + string = trim(string); + } + list.add(string); + } + + return list; + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences); + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) { + return StrUtil.toUnderlineCase(str); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + return StrUtil.equalsAnyIgnoreCase(str, strs); + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + return StrUtil.upperFirst(StrUtil.toCamelCase(name)); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + return StrUtil.toCamelCase(s); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || CollUtil.isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static String padl(final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static String padl(final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + sb.append(String.valueOf(c).repeat(size - len)); + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + sb.append(String.valueOf(c).repeat(Math.max(0, size))); + } + return sb.toString(); + } + + /** + * 切分字符串(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @return 分割后的数据列表 + */ + public static List splitList(String str) { + return splitTo(str, Convert::toStr); + } + + /** + * 切分字符串 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @return 分割后的数据列表 + */ + public static List splitList(String str, String separator) { + return splitTo(str, separator, Convert::toStr); + } + + /** + * 切分字符串自定义转换(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, Function mapper) { + return splitTo(str, SEPARATOR, mapper); + } + + /** + * 切分字符串自定义转换 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, String separator, Function mapper) { + if (isBlank(str)) { + return new ArrayList<>(0); + } + return StrUtil.split(str, separator) + .stream() + .filter(Objects::nonNull) + .map(mapper) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + /** + * 不区分大小写检查 CharSequence 是否以指定的前缀开头。 + * + * @param str 要检查的 CharSequence 可能为 null + * @param prefixs 要查找的前缀可能为 null + * @return 是否包含 + */ + public static boolean startWithAnyIgnoreCase(CharSequence str, CharSequence... prefixs) { + // 判断是否是以指定字符串开头 + for (CharSequence prefix : prefixs) { + if (StringUtils.startsWithIgnoreCase(str, prefix)) { + return true; + } + } + return false; + } + + public static String getFirstCharToUpper(String input) { + if (input == null || input.isEmpty()) { + return ""; // 如果字符串为空或长度为0,返回空字符串 + } + // 获取第一个字符并转为大写 + return String.valueOf(input.charAt(0)).toUpperCase(); + } + + /** + * 裁剪字符串,保留指定长度的字符(中文占2个字符,其他占1个字符) + * + * @param input 输入字符串 + * @param maxLength 最大字符长度 + * @return 裁剪后的字符串 + */ + public static String truncateString(String input, int maxLength) { + if (input == null || maxLength <= 0) { + return ""; + } + int length = 0; + StringBuilder result = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + // 判断是否为中文字符 + if (isChinese(c)) { + length += 2; + } else { + length += 1; + } + // 如果超过最大长度,则停止 + if (length > maxLength) { + break; + } + result.append(c); + } + + return result.toString(); + } + + /** + * 判断字符是否为中文字符 + * + * @param c 字符 + * @return 是否为中文字符 + */ + public static boolean isChinese(char c) { + Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); + + if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS + + || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS + + || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A + + || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION + + || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION + + || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { + return true; + + } + return false; + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java new file mode 100644 index 0000000..2ab42cb --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java @@ -0,0 +1,96 @@ +package org.dromara.common.core.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.parser.NodeParser; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.reflect.ReflectUtils; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 扩展 hutool TreeUtil 封装系统树构建 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TreeBuildUtils extends TreeUtil { + + /** + * 根据前端定制差异化字段 + */ + public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); + + /** + * 构建树形结构 + * + * @param 输入节点的类型 + * @param 节点ID的类型 + * @param list 节点列表,其中包含了要构建树形结构的所有节点 + * @param nodeParser 解析器,用于将输入节点转换为树节点 + * @return 构建好的树形结构列表 + */ + public static List> build(List list, NodeParser nodeParser) { + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + K k = ReflectUtils.invokeGetter(list.get(0), "parentId"); + return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser); + } + + /** + * 构建树形结构 + * + * @param 输入节点的类型 + * @param 节点ID的类型 + * @param parentId 顶级节点 + * @param list 节点列表,其中包含了要构建树形结构的所有节点 + * @param nodeParser 解析器,用于将输入节点转换为树节点 + * @return 构建好的树形结构列表 + */ + public static List> build(List list, K parentId, NodeParser nodeParser) { + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser); + } + + /** + * 获取节点列表中所有节点的叶子节点 + * + * @param 节点ID的类型 + * @param nodes 节点列表 + * @return 包含所有叶子节点的列表 + */ + public static List> getLeafNodes(List> nodes) { + if (CollUtil.isEmpty(nodes)) { + return CollUtil.newArrayList(); + } + return nodes.stream() + .flatMap(TreeBuildUtils::extractLeafNodes) + .collect(Collectors.toList()); + } + + /** + * 获取指定节点下的所有叶子节点 + * + * @param 节点ID的类型 + * @param node 要查找叶子节点的根节点 + * @return 包含所有叶子节点的列表 + */ + private static Stream> extractLeafNodes(Tree node) { + if (!node.hasChild()) { + return Stream.of(node); + } else { + // 递归调用,获取所有子节点的叶子节点 + return node.getChildren().stream() + .flatMap(TreeBuildUtils::extractLeafNodes); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java new file mode 100644 index 0000000..06b8fd6 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java @@ -0,0 +1,35 @@ +package org.dromara.common.core.utils; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Set; + +/** + * Validator 校验框架工具 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ValidatorUtils { + + private static final Validator VALID = SpringUtils.getBean(Validator.class); + + /** + * 对给定对象进行参数校验,并根据指定的校验组进行校验 + * + * @param object 要进行校验的对象 + * @param groups 校验组 + * @throws ConstraintViolationException 如果校验不通过,则抛出参数校验异常 + */ + public static void validate(T object, Class... groups) { + Set> validate = VALID.validate(object, groups); + if (!validate.isEmpty()) { + throw new ConstraintViolationException("参数校验异常", validate); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java new file mode 100644 index 0000000..23fa2cf --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java @@ -0,0 +1,40 @@ +package org.dromara.common.core.utils.file; + +/** + * 媒体类型工具类 + * + * @author ruoyi + */ +public class MimeTypeUtils { + public static final String IMAGE_PNG = "image/png"; + + public static final String IMAGE_JPG = "image/jpg"; + + public static final String IMAGE_JPEG = "image/jpeg"; + + public static final String IMAGE_BMP = "image/bmp"; + + public static final String IMAGE_GIF = "image/gif"; + + public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"}; + + public static final String[] FLASH_EXTENSION = {"swf", "flv"}; + + public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb"}; + + public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"}; + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + // 图片 + "bmp", "gif", "jpg", "jpeg", "png", + // word excel powerpoint + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + // 压缩文件 + "rar", "zip", "gz", "bz2", + // 视频格式 + "mp4", "avi", "rmvb", + // pdf + "pdf"}; + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java new file mode 100644 index 0000000..3f7cd57 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java @@ -0,0 +1,33 @@ +package org.dromara.common.core.utils.ip; + +import cn.hutool.core.net.NetUtil; +import cn.hutool.http.HtmlUtil; +import org.dromara.common.core.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * 获取地址类 + * + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AddressUtils { + + // 未知地址 + public static final String UNKNOWN = "XX XX"; + + public static String getRealAddressByIP(String ip) { + if (StringUtils.isBlank(ip)) { + return UNKNOWN; + } + // 内网不查询 + ip = StringUtils.contains(ip, "0:0:0:0:0:0:0:1") ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip); + if (NetUtil.isInnerIP(ip)) { + return "内网IP"; + } + return RegionUtils.getCityInfo(ip); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java new file mode 100644 index 0000000..6dde129 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java @@ -0,0 +1,31 @@ +package org.dromara.common.core.utils.regex; + + +import cn.hutool.core.util.ReUtil; +import org.dromara.common.core.constant.RegexConstants; + +/** + * 正则相关工具类 + * + * @author Feng + */ +public final class RegexUtils extends ReUtil { + + /** + * 从输入字符串中提取匹配的部分,如果没有匹配则返回默认值 + * + * @param input 要提取的输入字符串 + * @param regex 用于匹配的正则表达式,可以使用 {@link RegexConstants} 中定义的常量 + * @param defaultInput 如果没有匹配时返回的默认值 + * @return 如果找到匹配的部分,则返回匹配的部分,否则返回默认值 + */ + public static String extractFromString(String input, String regex, String defaultInput) { + try { + String str = ReUtil.get(regex, input, 1); + return str == null ? defaultInput : str; + } catch (Exception e) { + return defaultInput; + } + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java new file mode 100644 index 0000000..c0dda20 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java @@ -0,0 +1,105 @@ +package org.dromara.common.core.utils.regex; + +import cn.hutool.core.exceptions.ValidateException; +import cn.hutool.core.lang.Validator; +import org.dromara.common.core.factory.RegexPatternPoolFactory; + +import java.util.regex.Pattern; + +/** + * 正则字段校验器 + * 主要验证字段非空、是否为满足指定格式等 + * + * @author Feng + */ +public class RegexValidator extends Validator { + + /** + * 字典类型必须以字母开头,且只能为(小写字母,数字,下滑线) + */ + public static final Pattern DICTIONARY_TYPE = RegexPatternPoolFactory.DICTIONARY_TYPE; + + /** + * 身份证号码(后6位) + */ + public static final Pattern ID_CARD_LAST_6 = RegexPatternPoolFactory.ID_CARD_LAST_6; + + /** + * QQ号码 + */ + public static final Pattern QQ_NUMBER = RegexPatternPoolFactory.QQ_NUMBER; + + /** + * 邮政编码 + */ + public static final Pattern POSTAL_CODE = RegexPatternPoolFactory.POSTAL_CODE; + + /** + * 注册账号 + */ + public static final Pattern ACCOUNT = RegexPatternPoolFactory.ACCOUNT; + + /** + * 密码:包含至少8个字符,包括大写字母、小写字母、数字和特殊字符 + */ + public static final Pattern PASSWORD = RegexPatternPoolFactory.PASSWORD; + + /** + * 通用状态(0表示正常,1表示停用) + */ + public static final Pattern STATUS = RegexPatternPoolFactory.STATUS; + + + /** + * 检查输入的账号是否匹配预定义的规则 + * + * @param value 要验证的账号 + * @return 如果账号符合规则,返回 true;否则,返回 false。 + */ + public static boolean isAccount(CharSequence value) { + return isMatchRegex(ACCOUNT, value); + } + + /** + * 验证输入的账号是否符合规则,如果不符合,则抛出 ValidateException 异常 + * + * @param value 要验证的账号 + * @param errorMsg 验证失败时抛出的异常消息 + * @param CharSequence 的子类型 + * @return 如果验证通过,返回输入的账号 + * @throws ValidateException 如果验证失败 + */ + public static T validateAccount(T value, String errorMsg) throws ValidateException { + if (!isAccount(value)) { + throw new ValidateException(errorMsg); + } + return value; + } + + /** + * 检查输入的状态是否匹配预定义的规则 + * + * @param value 要验证的状态 + * @return 如果状态符合规则,返回 true;否则,返回 false。 + */ + public static boolean isStatus(CharSequence value) { + return isMatchRegex(STATUS, value); + } + + /** + * 验证输入的状态是否符合规则,如果不符合,则抛出 ValidateException 异常 + * + * @param value 要验证的状态 + * @param errorMsg 验证失败时抛出的异常消息 + * @param CharSequence 的子类型 + * @return 如果验证通过,返回输入的状态 + * @throws ValidateException 如果验证失败 + */ + public static T validateStatus(T value, String errorMsg) throws ValidateException { + if (!isStatus(value)) { + throw new ValidateException(errorMsg); + } + return value; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java new file mode 100644 index 0000000..77c5040 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java @@ -0,0 +1,9 @@ +package org.dromara.common.core.validate; + +/** + * 校验分组 edit + * + * @author Lion Li + */ +public interface EditGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java new file mode 100644 index 0000000..02a0ac2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java @@ -0,0 +1,9 @@ +package org.dromara.common.core.validate; + +/** + * 校验分组 query + * + * @author Lion Li + */ +public interface QueryGroup { +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java new file mode 100644 index 0000000..923c423 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java @@ -0,0 +1,37 @@ +package org.dromara.common.core.validate.enumd; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; + +/** + * 自定义枚举校验注解实现 + * + * @author 秋辞未寒 + * @date 2024-12-09 + */ +public class EnumPatternValidator implements ConstraintValidator { + + private EnumPattern annotation;; + + @Override + public void initialize(EnumPattern annotation) { + ConstraintValidator.super.initialize(annotation); + this.annotation = annotation; + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + if (StringUtils.isNotBlank(value)) { + String fieldName = annotation.fieldName(); + for (Object e : annotation.type().getEnumConstants()) { + if (value.equals(ReflectUtils.invokeGetter(e, fieldName))) { + return true; + } + } + } + return false; + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java new file mode 100644 index 0000000..9c32563 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java @@ -0,0 +1,21 @@ +package org.dromara.common.core.xss; + +import cn.hutool.core.util.ReUtil; +import cn.hutool.http.HtmlUtil; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +/** + * 自定义xss校验注解实现 + * + * @author Lion Li + */ +public class XssValidator implements ConstraintValidator { + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value); + } + +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..3395e73 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,6 @@ +org.dromara.common.core.config.ApplicationConfig +org.dromara.common.core.config.AsyncConfig +org.dromara.common.core.config.RuoYiConfig +org.dromara.common.core.config.ThreadPoolConfig +org.dromara.common.core.config.ValidatorConfig +org.dromara.common.core.utils.SpringUtils diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java new file mode 100644 index 0000000..069ef9a --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java @@ -0,0 +1,126 @@ +package org.dromara.common.doc.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.doc.config.properties.SpringDocProperties; +import org.dromara.common.doc.handler.OpenApiHandler; +import org.springdoc.core.configuration.SpringDocConfiguration; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.OpenApiCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.properties.SpringDocConfigProperties; +import org.springdoc.core.providers.JavadocProvider; +import org.springdoc.core.service.OpenAPIService; +import org.springdoc.core.service.SecurityService; +import org.springdoc.core.utils.PropertyResolverUtils; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.web.ServerProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * Swagger 文档配置 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@AutoConfiguration(before = SpringDocConfiguration.class) +@EnableConfigurationProperties(SpringDocProperties.class) +@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true) +public class SpringDocConfig { + + private final ServerProperties serverProperties; + + @Bean + @ConditionalOnMissingBean(OpenAPI.class) + public OpenAPI openApi(SpringDocProperties properties) { + OpenAPI openApi = new OpenAPI(); + // 文档基本信息 + SpringDocProperties.InfoProperties infoProperties = properties.getInfo(); + Info info = convertInfo(infoProperties); + openApi.info(info); + // 扩展文档信息 + openApi.externalDocs(properties.getExternalDocs()); + openApi.tags(properties.getTags()); + openApi.paths(properties.getPaths()); + openApi.components(properties.getComponents()); + Set keySet = properties.getComponents().getSecuritySchemes().keySet(); + List list = new ArrayList<>(); + SecurityRequirement securityRequirement = new SecurityRequirement(); + keySet.forEach(securityRequirement::addList); + list.add(securityRequirement); + openApi.security(list); + + return openApi; + } + + private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) { + Info info = new Info(); + info.setTitle(infoProperties.getTitle()); + info.setDescription(infoProperties.getDescription()); + info.setContact(infoProperties.getContact()); + info.setLicense(infoProperties.getLicense()); + info.setVersion(infoProperties.getVersion()); + return info; + } + + /** + * 自定义 openapi 处理器 + */ + @Bean + public OpenAPIService openApiBuilder(Optional openAPI, + SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomisers, + Optional> serverBaseUrlCustomisers, Optional javadocProvider) { + return new OpenApiHandler(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomisers, serverBaseUrlCustomisers, javadocProvider); + } + + /** + * 对已经生成好的 OpenApi 进行自定义操作 + */ + @Bean + public OpenApiCustomizer openApiCustomizer() { + String contextPath = serverProperties.getServlet().getContextPath(); + String finalContextPath; + if (StringUtils.isBlank(contextPath) || "/".equals(contextPath)) { + finalContextPath = ""; + } else { + finalContextPath = contextPath; + } + // 对所有路径增加前置上下文路径 + return openApi -> { + Paths oldPaths = openApi.getPaths(); + if (oldPaths instanceof PlusPaths) { + return; + } + PlusPaths newPaths = new PlusPaths(); + oldPaths.forEach((k, v) -> newPaths.addPathItem(finalContextPath + k, v)); + openApi.setPaths(newPaths); + }; + } + + /** + * 单独使用一个类便于判断 解决springdoc路径拼接重复问题 + * + * @author Lion Li + */ + static class PlusPaths extends Paths { + + public PlusPaths() { + super(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java new file mode 100644 index 0000000..eae3b4c --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java @@ -0,0 +1,94 @@ +package org.dromara.common.doc.config.properties; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.ExternalDocumentation; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.tags.Tag; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; + +import java.util.List; + +/** + * swagger 配置属性 + * + * @author Lion Li + */ +@Data +@ConfigurationProperties(prefix = "springdoc") +public class SpringDocProperties { + + /** + * 文档基本信息 + */ + @NestedConfigurationProperty + private InfoProperties info = new InfoProperties(); + + /** + * 扩展文档地址 + */ + @NestedConfigurationProperty + private ExternalDocumentation externalDocs; + + /** + * 标签 + */ + private List tags = null; + + /** + * 路径 + */ + @NestedConfigurationProperty + private Paths paths = null; + + /** + * 组件 + */ + @NestedConfigurationProperty + private Components components = null; + + /** + *

+ * 文档的基础属性信息 + *

+ * + * @see io.swagger.v3.oas.models.info.Info + * + * 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来 + */ + @Data + public static class InfoProperties { + + /** + * 标题 + */ + private String title = null; + + /** + * 描述 + */ + private String description = null; + + /** + * 联系人信息 + */ + @NestedConfigurationProperty + private Contact contact = null; + + /** + * 许可证 + */ + @NestedConfigurationProperty + private License license = null; + + /** + * 版本 + */ + private String version = null; + + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java new file mode 100644 index 0000000..56b7369 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java @@ -0,0 +1,253 @@ +package org.dromara.common.doc.handler; + +import cn.hutool.core.io.IoUtil; +import io.swagger.v3.core.jackson.TypeNameResolver; +import io.swagger.v3.core.util.AnnotationsUtils; +import io.swagger.v3.oas.annotations.tags.Tags; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.properties.SpringDocConfigProperties; +import org.springdoc.core.providers.JavadocProvider; +import org.springdoc.core.service.OpenAPIService; +import org.springdoc.core.service.SecurityService; +import org.springdoc.core.utils.PropertyResolverUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.core.annotation.AnnotatedElementUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.method.HandlerMethod; + +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 自定义 openapi 处理器 + * 对源码功能进行修改 增强使用 + */ +@Slf4j +@SuppressWarnings("all") +public class OpenApiHandler extends OpenAPIService { + + /** + * The Basic error controller. + */ + private static Class basicErrorController; + + /** + * The Security parser. + */ + private final SecurityService securityParser; + + /** + * The Mappings map. + */ + private final Map mappingsMap = new HashMap<>(); + + /** + * The Springdoc tags. + */ + private final Map springdocTags = new HashMap<>(); + + /** + * The Open api builder customisers. + */ + private final Optional> openApiBuilderCustomisers; + + /** + * The server base URL customisers. + */ + private final Optional> serverBaseUrlCustomizers; + + /** + * The Spring doc config properties. + */ + private final SpringDocConfigProperties springDocConfigProperties; + + /** + * The Cached open api map. + */ + private final Map cachedOpenAPI = new HashMap<>(); + + /** + * The Property resolver utils. + */ + private final PropertyResolverUtils propertyResolverUtils; + + /** + * The javadoc provider. + */ + private final Optional javadocProvider; + + /** + * The Context. + */ + private ApplicationContext context; + + /** + * The Open api. + */ + private OpenAPI openAPI; + + /** + * The Is servers present. + */ + private boolean isServersPresent; + + /** + * The Server base url. + */ + private String serverBaseUrl; + + /** + * Instantiates a new Open api builder. + * + * @param openAPI the open api + * @param securityParser the security parser + * @param springDocConfigProperties the spring doc config properties + * @param propertyResolverUtils the property resolver utils + * @param openApiBuilderCustomizers the open api builder customisers + * @param serverBaseUrlCustomizers the server base url customizers + * @param javadocProvider the javadoc provider + */ + public OpenApiHandler(Optional openAPI, SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomizers, + Optional> serverBaseUrlCustomizers, + Optional javadocProvider) { + super(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); + if (openAPI.isPresent()) { + this.openAPI = openAPI.get(); + if (this.openAPI.getComponents() == null) + this.openAPI.setComponents(new Components()); + if (this.openAPI.getPaths() == null) + this.openAPI.setPaths(new Paths()); + if (!CollectionUtils.isEmpty(this.openAPI.getServers())) + this.isServersPresent = true; + } + this.propertyResolverUtils = propertyResolverUtils; + this.securityParser = securityParser; + this.springDocConfigProperties = springDocConfigProperties; + this.openApiBuilderCustomisers = openApiBuilderCustomizers; + this.serverBaseUrlCustomizers = serverBaseUrlCustomizers; + this.javadocProvider = javadocProvider; + if (springDocConfigProperties.isUseFqn()) + TypeNameResolver.std.setUseFqn(true); + } + + @Override + public Operation buildTags(HandlerMethod handlerMethod, Operation operation, OpenAPI openAPI, Locale locale) { + + Set tags = new HashSet<>(); + Set tagsStr = new HashSet<>(); + + buildTagsFromMethod(handlerMethod.getMethod(), tags, tagsStr, locale); + buildTagsFromClass(handlerMethod.getBeanType(), tags, tagsStr, locale); + + if (!CollectionUtils.isEmpty(tagsStr)) + tagsStr = tagsStr.stream() + .map(str -> propertyResolverUtils.resolve(str, locale)) + .collect(Collectors.toSet()); + + if (springdocTags.containsKey(handlerMethod)) { + io.swagger.v3.oas.models.tags.Tag tag = springdocTags.get(handlerMethod); + tagsStr.add(tag.getName()); + if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { + openAPI.addTagsItem(tag); + } + } + + if (!CollectionUtils.isEmpty(tagsStr)) { + if (CollectionUtils.isEmpty(operation.getTags())) + operation.setTags(new ArrayList<>(tagsStr)); + else { + Set operationTagsSet = new HashSet<>(operation.getTags()); + operationTagsSet.addAll(tagsStr); + operation.getTags().clear(); + operation.getTags().addAll(operationTagsSet); + } + } + + if (isAutoTagClasses(operation)) { + + + if (javadocProvider.isPresent()) { + String description = javadocProvider.get().getClassJavadoc(handlerMethod.getBeanType()); + if (StringUtils.isNotBlank(description)) { + io.swagger.v3.oas.models.tags.Tag tag = new io.swagger.v3.oas.models.tags.Tag(); + + // 自定义部分 修改使用java注释当tag名 + List list = IoUtil.readLines(new StringReader(description), new ArrayList<>()); + // tag.setName(tagAutoName); + tag.setName(list.get(0)); + operation.addTagsItem(list.get(0)); + + tag.setDescription(description); + if (openAPI.getTags() == null || !openAPI.getTags().contains(tag)) { + openAPI.addTagsItem(tag); + } + } + } else { + String tagAutoName = splitCamelCase(handlerMethod.getBeanType().getSimpleName()); + operation.addTagsItem(tagAutoName); + } + } + + if (!CollectionUtils.isEmpty(tags)) { + // Existing tags + List openApiTags = openAPI.getTags(); + if (!CollectionUtils.isEmpty(openApiTags)) + tags.addAll(openApiTags); + openAPI.setTags(new ArrayList<>(tags)); + } + + // Handle SecurityRequirement at operation level + io.swagger.v3.oas.annotations.security.SecurityRequirement[] securityRequirements = securityParser + .getSecurityRequirements(handlerMethod); + if (securityRequirements != null) { + if (securityRequirements.length == 0) + operation.setSecurity(Collections.emptyList()); + else + securityParser.buildSecurityRequirement(securityRequirements, operation); + } + + return operation; + } + + private void buildTagsFromMethod(Method method, Set tags, Set tagsStr, Locale locale) { + // method tags + Set tagsSet = AnnotatedElementUtils + .findAllMergedAnnotations(method, Tags.class); + Set methodTags = tagsSet.stream() + .flatMap(x -> Stream.of(x.value())).collect(Collectors.toSet()); + methodTags.addAll(AnnotatedElementUtils.findAllMergedAnnotations(method, io.swagger.v3.oas.annotations.tags.Tag.class)); + if (!CollectionUtils.isEmpty(methodTags)) { + tagsStr.addAll(StreamUtils.toSet(methodTags, tag -> propertyResolverUtils.resolve(tag.name(), locale))); + List allTags = new ArrayList<>(methodTags); + addTags(allTags, tags, locale); + } + } + + private void addTags(List sourceTags, Set tags, Locale locale) { + Optional> optionalTagSet = AnnotationsUtils + .getTags(sourceTags.toArray(new io.swagger.v3.oas.annotations.tags.Tag[0]), true); + optionalTagSet.ifPresent(tagsSet -> { + tagsSet.forEach(tag -> { + tag.name(propertyResolverUtils.resolve(tag.getName(), locale)); + tag.description(propertyResolverUtils.resolve(tag.getDescription(), locale)); + if (tags.stream().noneMatch(t -> t.getName().equals(tag.getName()))) + tags.add(tag); + }); + }); + } + +} diff --git a/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..fe11e76 --- /dev/null +++ b/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.doc.config.SpringDocConfig diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java new file mode 100644 index 0000000..7f52de8 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java @@ -0,0 +1,20 @@ +package org.dromara.common.encrypt.annotation; + +import java.lang.annotation.*; + +/** + * 强制加密注解 + * + * @author Michelle.Chung + */ +@Documented +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiEncrypt { + + /** + * 响应加密忽略,默认不加密,为 true 时加密 + */ + boolean response() default false; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java new file mode 100644 index 0000000..d357d72 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java @@ -0,0 +1,44 @@ +package org.dromara.common.encrypt.annotation; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; + +import java.lang.annotation.*; + +/** + * 字段加密注解 + * + * @author 老马 + */ +@Documented +@Inherited +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface EncryptField { + + /** + * 加密算法 + */ + AlgorithmType algorithm() default AlgorithmType.DEFAULT; + + /** + * 秘钥。AES、SM4需要 + */ + String password() default ""; + + /** + * 公钥。RSA、SM2需要 + */ + String publicKey() default ""; + + /** + * 私钥。RSA、SM2需要 + */ + String privateKey() default ""; + + /** + * 编码方式。对加密算法为BASE64的不起作用 + */ + EncodeType encode() default EncodeType.DEFAULT; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java new file mode 100644 index 0000000..098f6bc --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java @@ -0,0 +1,32 @@ +package org.dromara.common.encrypt.config; + +import jakarta.servlet.DispatcherType; +import org.dromara.common.encrypt.filter.CryptoFilter; +import org.dromara.common.encrypt.properties.ApiDecryptProperties; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; + +/** + * api 解密自动配置 + * + * @author wdhcr + */ +@AutoConfiguration +@EnableConfigurationProperties(ApiDecryptProperties.class) +@ConditionalOnProperty(value = "api-decrypt.enabled", havingValue = "true") +public class ApiDecryptAutoConfiguration { + + @Bean + public FilterRegistrationBean cryptoFilterRegistration(ApiDecryptProperties properties) { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setDispatcherTypes(DispatcherType.REQUEST); + registration.setFilter(new CryptoFilter(properties)); + registration.addUrlPatterns("/*"); + registration.setName("cryptoFilter"); + registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE); + return registration; + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java new file mode 100644 index 0000000..fbc4e52 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java @@ -0,0 +1,49 @@ +package org.dromara.common.encrypt.config; + +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.encrypt.core.EncryptorManager; +import org.dromara.common.encrypt.interceptor.MybatisDecryptInterceptor; +import org.dromara.common.encrypt.interceptor.MybatisEncryptInterceptor; +import org.dromara.common.encrypt.properties.EncryptorProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * 加解密配置 + * + * @author 老马 + * @version 4.6.0 + */ +@AutoConfiguration(after = MybatisPlusAutoConfiguration.class) +@EnableConfigurationProperties(EncryptorProperties.class) +@ConditionalOnProperty(value = "mybatis-encryptor.enable", havingValue = "true") +@Slf4j +public class EncryptorAutoConfiguration { + + @Autowired + private EncryptorProperties properties; + + @Bean + public EncryptorManager encryptorManager(MybatisPlusProperties mybatisPlusProperties) { + return new EncryptorManager(mybatisPlusProperties.getTypeAliasesPackage()); + } + + @Bean + public MybatisEncryptInterceptor mybatisEncryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisEncryptInterceptor(encryptorManager, properties); + } + + @Bean + public MybatisDecryptInterceptor mybatisDecryptInterceptor(EncryptorManager encryptorManager) { + return new MybatisDecryptInterceptor(encryptorManager, properties); + } + +} + + + diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java new file mode 100644 index 0000000..dbc4420 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java @@ -0,0 +1,35 @@ +package org.dromara.common.encrypt.core; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; + +/** + * 加解者 + * + * @author 老马 + * @version 4.6.0 + */ +public interface IEncryptor { + + /** + * 获得当前算法 + */ + AlgorithmType algorithm(); + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + * @return 加密后的字符串 + */ + String encrypt(String value, EncodeType encodeType); + + /** + * 解密 + * + * @param value 待加密字符串 + * @return 解密后的字符串 + */ + String decrypt(String value); +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java new file mode 100644 index 0000000..858d229 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java @@ -0,0 +1,18 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.core.IEncryptor; + +/** + * 所有加密执行者的基类 + * + * @author 老马 + * @version 4.6.0 + */ +public abstract class AbstractEncryptor implements IEncryptor { + + public AbstractEncryptor(EncryptContext context) { + // 用户配置校验与配置注入 + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java new file mode 100644 index 0000000..5f03a4b --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java @@ -0,0 +1,62 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.core.utils.StringUtils; +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; + + +/** + * RSA算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class RsaEncryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public RsaEncryptor(EncryptContext context) { + super(context); + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。"); + } + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.RSA; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptByRsaHex(value, context.getPublicKey()); + } else { + return EncryptUtils.encryptByRsa(value, context.getPublicKey()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptByRsa(value, context.getPrivateKey()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java new file mode 100644 index 0000000..aec5d82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java @@ -0,0 +1,61 @@ +package org.dromara.common.encrypt.core.encryptor; + +import org.dromara.common.core.utils.StringUtils; +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; + +/** + * sm2算法实现 + * + * @author 老马 + * @version 4.6.0 + */ +public class Sm2Encryptor extends AbstractEncryptor { + + private final EncryptContext context; + + public Sm2Encryptor(EncryptContext context) { + super(context); + String privateKey = context.getPrivateKey(); + String publicKey = context.getPublicKey(); + if (StringUtils.isAnyEmpty(privateKey, publicKey)) { + throw new IllegalArgumentException("SM2公私钥均需要提供,公钥加密,私钥解密。"); + } + this.context = context; + } + + /** + * 获得当前算法 + */ + @Override + public AlgorithmType algorithm() { + return AlgorithmType.SM2; + } + + /** + * 加密 + * + * @param value 待加密字符串 + * @param encodeType 加密后的编码格式 + */ + @Override + public String encrypt(String value, EncodeType encodeType) { + if (encodeType == EncodeType.HEX) { + return EncryptUtils.encryptBySm2Hex(value, context.getPublicKey()); + } else { + return EncryptUtils.encryptBySm2(value, context.getPublicKey()); + } + } + + /** + * 解密 + * + * @param value 待加密字符串 + */ + @Override + public String decrypt(String value) { + return EncryptUtils.decryptBySm2(value, context.getPrivateKey()); + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java new file mode 100644 index 0000000..26ee1ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java @@ -0,0 +1,48 @@ +package org.dromara.common.encrypt.enumd; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.encrypt.core.encryptor.*; + +/** + * 算法名称 + * + * @author 老马 + * @version 4.6.0 + */ +@Getter +@AllArgsConstructor +public enum AlgorithmType { + + /** + * 默认走yml配置 + */ + DEFAULT(null), + + /** + * base64 + */ + BASE64(Base64Encryptor.class), + + /** + * aes + */ + AES(AesEncryptor.class), + + /** + * rsa + */ + RSA(RsaEncryptor.class), + + /** + * sm2 + */ + SM2(Sm2Encryptor.class), + + /** + * sm4 + */ + SM4(Sm4Encryptor.class); + + private final Class clazz; +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java new file mode 100644 index 0000000..f471221 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java @@ -0,0 +1,26 @@ +package org.dromara.common.encrypt.enumd; + +/** + * 编码类型 + * + * @author 老马 + * @version 4.6.0 + */ +public enum EncodeType { + + /** + * 默认使用yml配置 + */ + DEFAULT, + + /** + * base64编码 + */ + BASE64, + + /** + * 16进制编码 + */ + HEX; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java new file mode 100644 index 0000000..98f4bc7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java @@ -0,0 +1,94 @@ +package org.dromara.common.encrypt.filter; + +import cn.hutool.core.io.IoUtil; +import jakarta.servlet.ReadListener; +import jakarta.servlet.ServletInputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.encrypt.utils.EncryptUtils; +import org.springframework.http.MediaType; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +/** + * 解密请求参数工具类 + * + * @author wdhcr + */ +public class DecryptRequestBodyWrapper extends HttpServletRequestWrapper { + + private final byte[] body; + + public DecryptRequestBodyWrapper(HttpServletRequest request, String privateKey, String headerFlag) throws IOException { + super(request); + // 获取 AES 密码 采用 RSA 加密 + String headerRsa = request.getHeader(headerFlag); + String decryptAes = EncryptUtils.decryptByRsa(headerRsa, privateKey); + // 解密 AES 密码 + String aesPassword = EncryptUtils.decryptByBase64(decryptAes); + request.setCharacterEncoding(Constants.UTF8); + byte[] readBytes = IoUtil.readBytes(request.getInputStream(), false); + String requestBody = new String(readBytes, StandardCharsets.UTF_8); + // 解密 body 采用 AES 加密 + String decryptBody = EncryptUtils.decryptByAes(requestBody, aesPassword); + body = decryptBody.getBytes(StandardCharsets.UTF_8); + } + + @Override + public BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + + @Override + public int getContentLength() { + return body.length; + } + + @Override + public long getContentLengthLong() { + return body.length; + } + + @Override + public String getContentType() { + return MediaType.APPLICATION_JSON_VALUE; + } + + + @Override + public ServletInputStream getInputStream() { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + return new ServletInputStream() { + @Override + public int read() { + return bais.read(); + } + + @Override + public int available() { + return body.length; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java new file mode 100644 index 0000000..c0af232 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java @@ -0,0 +1,121 @@ +package org.dromara.common.encrypt.filter; + +import cn.hutool.core.util.RandomUtil; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.WriteListener; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; +import org.dromara.common.encrypt.utils.EncryptUtils; + +import java.io.*; +import java.nio.charset.StandardCharsets; + +/** + * 加密响应参数包装类 + * + * @author Michelle.Chung + */ +public class EncryptResponseBodyWrapper extends HttpServletResponseWrapper { + + private final ByteArrayOutputStream byteArrayOutputStream; + private final ServletOutputStream servletOutputStream; + private final PrintWriter printWriter; + + public EncryptResponseBodyWrapper(HttpServletResponse response) throws IOException { + super(response); + this.byteArrayOutputStream = new ByteArrayOutputStream(); + this.servletOutputStream = this.getOutputStream(); + this.printWriter = new PrintWriter(new OutputStreamWriter(byteArrayOutputStream)); + } + + @Override + public PrintWriter getWriter() { + return printWriter; + } + + @Override + public void flushBuffer() throws IOException { + if (servletOutputStream != null) { + servletOutputStream.flush(); + } + if (printWriter != null) { + printWriter.flush(); + } + } + + @Override + public void reset() { + byteArrayOutputStream.reset(); + } + + public byte[] getResponseData() throws IOException { + flushBuffer(); + return byteArrayOutputStream.toByteArray(); + } + + public String getContent() throws IOException { + flushBuffer(); + return byteArrayOutputStream.toString(); + } + + /** + * 获取加密内容 + * + * @param servletResponse response + * @param publicKey RSA公钥 (用于加密 AES 秘钥) + * @param headerFlag 请求头标志 + * @return 加密内容 + * @throws IOException + */ + public String getEncryptContent(HttpServletResponse servletResponse, String publicKey, String headerFlag) throws IOException { + // 生成秘钥 + String aesPassword = RandomUtil.randomString(32); + // 秘钥使用 Base64 编码 + String encryptAes = EncryptUtils.encryptByBase64(aesPassword); + // Rsa 公钥加密 Base64 编码 + String encryptPassword = EncryptUtils.encryptByRsa(encryptAes, publicKey); + + // 设置响应头 + servletResponse.addHeader("Access-Control-Expose-Headers", headerFlag); + servletResponse.setHeader(headerFlag, encryptPassword); + servletResponse.setHeader("Access-Control-Allow-Origin", "*"); + servletResponse.setHeader("Access-Control-Allow-Methods", "*"); + servletResponse.setCharacterEncoding(StandardCharsets.UTF_8.toString()); + + // 获取原始内容 + String originalBody = this.getContent(); + // 对内容进行加密 + return EncryptUtils.encryptByAes(originalBody, aesPassword); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + return new ServletOutputStream() { + @Override + public boolean isReady() { + return false; + } + + @Override + public void setWriteListener(WriteListener writeListener) { + + } + + @Override + public void write(int b) throws IOException { + byteArrayOutputStream.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + byteArrayOutputStream.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + byteArrayOutputStream.write(b, off, len); + } + }; + } + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java new file mode 100644 index 0000000..460aa36 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java @@ -0,0 +1,120 @@ +package org.dromara.common.encrypt.interceptor; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.resultset.ResultSetHandler; +import org.apache.ibatis.plugin.*; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.EncryptField; +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.core.EncryptorManager; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.properties.EncryptorProperties; + +import java.lang.reflect.Field; +import java.sql.Statement; +import java.util.*; + +/** + * 出参解密拦截器 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ResultSetHandler.class, + method = "handleResultSets", + args = {Statement.class}) +}) +@AllArgsConstructor +public class MybatisDecryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 获取执行mysql执行结果 + Object result = invocation.proceed(); + if (result == null) { + return null; + } + decryptHandler(result); + return result; + } + + /** + * 解密对象 + * + * @param sourceObject 待加密对象 + */ + private void decryptHandler(Object sourceObject) { + if (ObjectUtil.isNull(sourceObject)) { + return; + } + if (sourceObject instanceof Map map) { + new HashSet<>(map.values()).forEach(this::decryptHandler); + return; + } + if (sourceObject instanceof List list) { + if(CollUtil.isEmpty(list)) { + return; + } + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = list.get(0); + if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + list.forEach(this::decryptHandler); + return; + } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } + try { + for (Field field : fields) { + field.set(sourceObject, this.decryptField(Convert.toStr(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理解密字段时出错", e); + } + } + + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String decryptField(String value, Field field) { + if (ObjectUtil.isNull(value)) { + return null; + } + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.decrypt(value, encryptContext); + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java new file mode 100644 index 0000000..bcc2f4c --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java @@ -0,0 +1,124 @@ +package org.dromara.common.encrypt.interceptor; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.executor.parameter.ParameterHandler; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Signature; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.EncryptField; +import org.dromara.common.encrypt.core.EncryptContext; +import org.dromara.common.encrypt.core.EncryptorManager; +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import org.dromara.common.encrypt.properties.EncryptorProperties; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.util.*; + +/** + * 入参加密拦截器 + * + * @author 老马 + * @version 4.6.0 + */ +@Slf4j +@Intercepts({@Signature( + type = ParameterHandler.class, + method = "setParameters", + args = {PreparedStatement.class}) +}) +@AllArgsConstructor +public class MybatisEncryptInterceptor implements Interceptor { + + private final EncryptorManager encryptorManager; + private final EncryptorProperties defaultProperties; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + return invocation; + } + + @Override + public Object plugin(Object target) { + if (target instanceof ParameterHandler parameterHandler) { + // 进行加密操作 + Object parameterObject = parameterHandler.getParameterObject(); + if (ObjectUtil.isNotNull(parameterObject) && !(parameterObject instanceof String)) { + this.encryptHandler(parameterObject); + } + } + return target; + } + + /** + * 加密对象 + * + * @param sourceObject 待加密对象 + */ + private void encryptHandler(Object sourceObject) { + if (ObjectUtil.isNull(sourceObject)) { + return; + } + if (sourceObject instanceof Map map) { + new HashSet<>(map.values()).forEach(this::encryptHandler); + return; + } + if (sourceObject instanceof List list) { + if(CollUtil.isEmpty(list)) { + return; + } + // 判断第一个元素是否含有注解。如果没有直接返回,提高效率 + Object firstItem = list.get(0); + if (ObjectUtil.isNull(firstItem) || CollUtil.isEmpty(encryptorManager.getFieldCache(firstItem.getClass()))) { + return; + } + list.forEach(this::encryptHandler); + return; + } + // 不在缓存中的类,就是没有加密注解的类(当然也有可能是typeAliasesPackage写错) + Set fields = encryptorManager.getFieldCache(sourceObject.getClass()); + if(ObjectUtil.isNull(fields)){ + return; + } + try { + for (Field field : fields) { + field.set(sourceObject, this.encryptField(Convert.toStr(field.get(sourceObject)), field)); + } + } catch (Exception e) { + log.error("处理加密字段时出错", e); + } + } + + /** + * 字段值进行加密。通过字段的批注注册新的加密算法 + * + * @param value 待加密的值 + * @param field 待加密字段 + * @return 加密后结果 + */ + private String encryptField(String value, Field field) { + if (ObjectUtil.isNull(value)) { + return null; + } + EncryptField encryptField = field.getAnnotation(EncryptField.class); + EncryptContext encryptContext = new EncryptContext(); + encryptContext.setAlgorithm(encryptField.algorithm() == AlgorithmType.DEFAULT ? defaultProperties.getAlgorithm() : encryptField.algorithm()); + encryptContext.setEncode(encryptField.encode() == EncodeType.DEFAULT ? defaultProperties.getEncode() : encryptField.encode()); + encryptContext.setPassword(StringUtils.isBlank(encryptField.password()) ? defaultProperties.getPassword() : encryptField.password()); + encryptContext.setPrivateKey(StringUtils.isBlank(encryptField.privateKey()) ? defaultProperties.getPrivateKey() : encryptField.privateKey()); + encryptContext.setPublicKey(StringUtils.isBlank(encryptField.publicKey()) ? defaultProperties.getPublicKey() : encryptField.publicKey()); + return this.encryptorManager.encrypt(value, encryptContext); + } + + + @Override + public void setProperties(Properties properties) { + } +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java new file mode 100644 index 0000000..6aadb3e --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java @@ -0,0 +1,34 @@ +package org.dromara.common.encrypt.properties; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * api解密属性配置类 + * @author wdhcr + */ +@Data +@ConfigurationProperties(prefix = "api-decrypt") +public class ApiDecryptProperties { + + /** + * 加密开关 + */ + private Boolean enabled; + + /** + * 头部标识 + */ + private String headerFlag; + + /** + * 响应加密公钥 + */ + private String publicKey; + + /** + * 请求解密私钥 + */ + private String privateKey; + +} diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java new file mode 100644 index 0000000..ba445c1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java @@ -0,0 +1,48 @@ +package org.dromara.common.encrypt.properties; + +import org.dromara.common.encrypt.enumd.AlgorithmType; +import org.dromara.common.encrypt.enumd.EncodeType; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 加解密属性配置类 + * + * @author 老马 + * @version 4.6.0 + */ +@Data +@ConfigurationProperties(prefix = "mybatis-encryptor") +public class EncryptorProperties { + + /** + * 过滤开关 + */ + private Boolean enable; + + /** + * 默认算法 + */ + 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/utils/EncryptUtils.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java new file mode 100644 index 0000000..2a096ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java @@ -0,0 +1,313 @@ +package org.dromara.common.encrypt.utils; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SmUtil; +import cn.hutool.crypto.asymmetric.KeyType; +import cn.hutool.crypto.asymmetric.RSA; +import cn.hutool.crypto.asymmetric.SM2; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +/** + * 安全相关工具类 + * + * @author 老马 + */ +public class EncryptUtils { + + /** + * 公钥 + */ + public static final String PUBLIC_KEY = "publicKey"; + + /** + * 私钥 + */ + public static final String PRIVATE_KEY = "privateKey"; + + /** + * Base64加密 + * + * @param data 待加密数据 + * @return 加密后字符串 + */ + public static String encryptByBase64(String data) { + return Base64.encode(data, StandardCharsets.UTF_8); + } + + /** + * Base64解密 + * + * @param data 待解密数据 + * @return 解密后字符串 + */ + public static String decryptByBase64(String data) { + return Base64.decodeStr(data, StandardCharsets.UTF_8); + } + + /** + * AES加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptByAes(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8); + } + + /** + * AES加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptByAesHex(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8); + } + + /** + * AES解密 + * + * @param data 待解密数据 + * @param password 秘钥字符串 + * @return 解密后字符串 + */ + public static String decryptByAes(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("AES需要传入秘钥信息"); + } + // aes算法的秘钥要求是16位、24位、32位 + int[] array = {16, 24, 32}; + if (!ArrayUtil.contains(array, password.length())) { + throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位"); + } + return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8); + } + + /** + * sm4加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm4(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptBase64(data, StandardCharsets.UTF_8); + } + + /** + * sm4加密 + * + * @param data 待加密数据 + * @param password 秘钥字符串 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm4Hex(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8); + } + + /** + * sm4解密 + * + * @param data 待解密数据 + * @param password 秘钥字符串 + * @return 解密后字符串 + */ + public static String decryptBySm4(String data, String password) { + if (StrUtil.isBlank(password)) { + throw new IllegalArgumentException("SM4需要传入秘钥信息"); + } + // sm4算法的秘钥要求是16位长度 + int sm4PasswordLength = 16; + if (sm4PasswordLength != password.length()) { + throw new IllegalArgumentException("SM4秘钥长度要求为16位"); + } + return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).decryptStr(data, StandardCharsets.UTF_8); + } + + /** + * 产生sm2加解密需要的公钥和私钥 + * + * @return 公私钥Map + */ + public static Map generateSm2Key() { + Map keyMap = new HashMap<>(2); + SM2 sm2 = SmUtil.sm2(); + keyMap.put(PRIVATE_KEY, sm2.getPrivateKeyBase64()); + keyMap.put(PUBLIC_KEY, sm2.getPublicKeyBase64()); + return keyMap; + } + + /** + * sm2公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptBySm2(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("SM2需要传入公钥进行加密"); + } + SM2 sm2 = SmUtil.sm2(null, publicKey); + return sm2.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * sm2公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySm2Hex(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("SM2需要传入公钥进行加密"); + } + SM2 sm2 = SmUtil.sm2(null, publicKey); + return sm2.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * sm2私钥解密 + * + * @param data 待解密数据 + * @param privateKey 私钥 + * @return 解密后字符串 + */ + public static String decryptBySm2(String data, String privateKey) { + if (StrUtil.isBlank(privateKey)) { + throw new IllegalArgumentException("SM2需要传入私钥进行解密"); + } + SM2 sm2 = SmUtil.sm2(privateKey, null); + return sm2.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8); + } + + /** + * 产生RSA加解密需要的公钥和私钥 + * + * @return 公私钥Map + */ + public static Map generateRsaKey() { + Map keyMap = new HashMap<>(2); + RSA rsa = SecureUtil.rsa(); + keyMap.put(PRIVATE_KEY, rsa.getPrivateKeyBase64()); + keyMap.put(PUBLIC_KEY, rsa.getPublicKeyBase64()); + return keyMap; + } + + /** + * rsa公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Base64编码 + */ + public static String encryptByRsa(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("RSA需要传入公钥进行加密"); + } + RSA rsa = SecureUtil.rsa(null, publicKey); + return rsa.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * rsa公钥加密 + * + * @param data 待加密数据 + * @param publicKey 公钥 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptByRsaHex(String data, String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("RSA需要传入公钥进行加密"); + } + RSA rsa = SecureUtil.rsa(null, publicKey); + return rsa.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey); + } + + /** + * rsa私钥解密 + * + * @param data 待解密数据 + * @param privateKey 私钥 + * @return 解密后字符串 + */ + public static String decryptByRsa(String data, String privateKey) { + if (StrUtil.isBlank(privateKey)) { + throw new IllegalArgumentException("RSA需要传入私钥进行解密"); + } + RSA rsa = SecureUtil.rsa(privateKey, null); + return rsa.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8); + } + + /** + * md5加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptByMd5(String data) { + return SecureUtil.md5(data); + } + + /** + * sha256加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySha256(String data) { + return SecureUtil.sha256(data); + } + + /** + * sm3加密 + * + * @param data 待加密数据 + * @return 加密后字符串, 采用Hex编码 + */ + public static String encryptBySm3(String data) { + return SmUtil.sm3(data); + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml new file mode 100644 index 0000000..dd4a5ee --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/pom.xml @@ -0,0 +1,30 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-excel + + + ruoyi-common-excel + + + + + org.dromara + ruoyi-common-json + + + + com.alibaba + easyexcel + + + + diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java new file mode 100644 index 0000000..6b9211b --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java @@ -0,0 +1,29 @@ +package org.dromara.common.excel.annotation; + +import org.dromara.common.excel.core.CellMergeStrategy; + +import java.lang.annotation.*; + +/** + * excel 列单元格合并(合并列相同项) + * + * 需搭配 {@link CellMergeStrategy} 策略使用 + * + * @author Lion Li + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CellMerge { + + /** + * col index + */ + int index() default -1; + + /** + * 合并需要依赖的其他字段名称 + */ + String[] mergeBy() default {}; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java new file mode 100644 index 0000000..5c51842 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java @@ -0,0 +1,32 @@ +package org.dromara.common.excel.annotation; + +import org.dromara.common.core.utils.StringUtils; + +import java.lang.annotation.*; + +/** + * 字典格式化 + * + * @author Lion Li + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDictFormat { + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + String separator() default StringUtils.SEPARATOR; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java new file mode 100644 index 0000000..290379d --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java @@ -0,0 +1,30 @@ +package org.dromara.common.excel.annotation; + +import java.lang.annotation.*; + +/** + * 枚举格式化 + * + * @author Liang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelEnumFormat { + + /** + * 字典枚举类型 + */ + Class> enumClass(); + + /** + * 字典枚举类中对应的code属性名称,默认为code + */ + String codeField() default "code"; + + /** + * 字典枚举类中对应的text属性名称,默认为text + */ + String textField() default "text"; + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java new file mode 100644 index 0000000..f358afc --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java @@ -0,0 +1,24 @@ +package org.dromara.common.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 批注 + * @author guzhouyanyu + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelNotation { + + /** + * col index + */ + int index() default -1; + /** + * 批注内容 + */ + String value() default ""; +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java new file mode 100644 index 0000000..15784e1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java @@ -0,0 +1,26 @@ +package org.dromara.common.excel.annotation; + +import org.apache.poi.ss.usermodel.IndexedColors; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 是否必填 + * @author guzhouyanyu + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ExcelRequired { + + /** + * col index + */ + int index() default -1; + /** + * 字体颜色 + */ + IndexedColors fontColor() default IndexedColors.RED; +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java new file mode 100644 index 0000000..61eeabf --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java @@ -0,0 +1,73 @@ +package org.dromara.common.excel.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +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 org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.excel.utils.ExcelUtil; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; + +/** + * 字典格式化转换处理 + * + * @author Lion Li + */ +@Slf4j +public class ExcelDictConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String label = cellData.getStringValue(); + String value; + if (StringUtils.isBlank(type)) { + value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator()); + } else { + value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator()); + } + return Convert.convert(contentProperty.getField().getType(), value); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String value = Convert.toStr(object); + String label; + if (StringUtils.isBlank(type)) { + label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator()); + } else { + label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator()); + } + return new WriteCellData<>(label); + } + + private ExcelDictFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class); + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java new file mode 100644 index 0000000..b948ea7 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java @@ -0,0 +1,87 @@ +package org.dromara.common.excel.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +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 org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.excel.annotation.ExcelEnumFormat; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 枚举格式化转换处理 + * + * @author Liang + */ +@Slf4j +public class ExcelEnumConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + cellData.checkEmpty(); + // Excel中填入的是枚举中指定的描述 + Object textValue = switch (cellData.getType()) { + case STRING, DIRECT_STRING, RICH_TEXT_STRING -> cellData.getStringValue(); + case NUMBER -> cellData.getNumberValue(); + case BOOLEAN -> cellData.getBooleanValue(); + default -> throw new IllegalArgumentException("单元格类型异常!"); + }; + // 如果是空值 + if (ObjectUtil.isNull(textValue)) { + return null; + } + Map enumCodeToTextMap = beforeConvert(contentProperty); + // 从Java输出至Excel是code转text + // 因此从Excel转Java应该将text与code对调 + Map enumTextToCodeMap = new HashMap<>(); + enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key)); + // 应该从text -> code中查找 + Object codeValue = enumTextToCodeMap.get(textValue); + return Convert.convert(contentProperty.getField().getType(), codeValue); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + Map enumValueMap = beforeConvert(contentProperty); + String value = Convert.toStr(enumValueMap.get(object), ""); + return new WriteCellData<>(value); + } + + private Map beforeConvert(ExcelContentProperty contentProperty) { + ExcelEnumFormat anno = getAnnotation(contentProperty.getField()); + Map enumValueMap = new HashMap<>(); + Enum[] enumConstants = anno.enumClass().getEnumConstants(); + for (Enum enumConstant : enumConstants) { + Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); + String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); + enumValueMap.put(codeValue, textValue); + } + return enumValueMap; + } + + private ExcelEnumFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class); + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java new file mode 100644 index 0000000..7c7721c --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java @@ -0,0 +1,157 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.WorkbookWriteHandler; +import com.alibaba.excel.write.handler.context.WorkbookWriteHandlerContext; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.excel.annotation.CellMerge; + +import java.lang.reflect.Field; +import java.util.*; + +/** + * 列值重复合并策略 + * + * @author Lion Li + */ +@Slf4j +public class CellMergeStrategy extends AbstractMergeStrategy implements WorkbookWriteHandler { + + private final List cellList; + private final boolean hasTitle; + private int rowIndex; + + public CellMergeStrategy(List list, boolean hasTitle) { + this.hasTitle = hasTitle; + // 行合并开始下标 + this.rowIndex = hasTitle ? 1 : 0; + this.cellList = handle(list, hasTitle); + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + //单元格写入了,遍历合并区域,如果该Cell在区域内,但非首行,则清空 + final int rowIndex = cell.getRowIndex(); + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress cellAddresses : cellList) { + final int firstRow = cellAddresses.getFirstRow(); + if (cellAddresses.isInRange(cell) && rowIndex != firstRow){ + cell.setBlank(); + } + } + } + } + + @Override + public void afterWorkbookDispose(final WorkbookWriteHandlerContext context) { + //当前表格写完后,统一写入 + if (CollUtil.isNotEmpty(cellList)){ + for (CellRangeAddress item : cellList) { + context.getWriteContext().writeSheetHolder().getSheet().addMergedRegion(item); + } + } + } + + @SneakyThrows + private List handle(List list, boolean hasTitle) { + List cellList = new ArrayList<>(); + if (CollUtil.isEmpty(list)) { + return cellList; + } + Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName())); + + // 有注解的字段 + List mergeFields = new ArrayList<>(); + List mergeFieldsIndex = new ArrayList<>(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); + mergeFields.add(field); + mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); + if (hasTitle) { + ExcelProperty property = field.getAnnotation(ExcelProperty.class); + rowIndex = Math.max(rowIndex, property.value().length); + } + } + } + + Map map = new HashMap<>(); + // 生成两两合并单元格 + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < mergeFields.size(); j++) { + Field field = mergeFields.get(j); + Object val = ReflectUtils.invokeGetter(list.get(i), field.getName()); + + int colNum = mergeFieldsIndex.get(j); + if (!map.containsKey(field)) { + map.put(field, new RepeatCell(val, i)); + } else { + RepeatCell repeatCell = map.get(field); + Object cellValue = repeatCell.getValue(); + if (cellValue == null || "".equals(cellValue)) { + // 空值跳过不合并 + continue; + } + + if (!cellValue.equals(val)) { + if ((i - repeatCell.getCurrent() > 1)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } else if (i == list.size() - 1) { + if (i > repeatCell.getCurrent() && isMerge(list, i, field)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); + } + } else if (!isMerge(list, i, field)) { + if ((i - repeatCell.getCurrent() > 1)) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } + } + } + } + return cellList; + } + + private boolean isMerge(List list, int i, Field field) { + boolean isMerge = true; + CellMerge cm = field.getAnnotation(CellMerge.class); + final String[] mergeBy = cm.mergeBy(); + if (StrUtil.isAllNotBlank(mergeBy)) { + //比对当前list(i)和list(i - 1)的各个属性值一一比对 如果全为真 则为真 + for (String fieldName : mergeBy) { + final Object valCurrent = ReflectUtil.getFieldValue(list.get(i), fieldName); + final Object valPre = ReflectUtil.getFieldValue(list.get(i - 1), fieldName); + if (!Objects.equals(valPre, valCurrent)) { + //依赖字段如有任一不等值,则标记为不可合并 + isMerge = false; + } + } + } + return isMerge; + } + + @Data + @AllArgsConstructor + static class RepeatCell { + + private Object value; + + private int current; + + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java new file mode 100644 index 0000000..b6fa0b4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java @@ -0,0 +1,104 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; +import java.util.Set; + +/** + * Excel 导入监听 + * + * @author Yjoioooo + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor +public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener { + + /** + * 是否Validator检验,默认为是 + */ + private Boolean isValidate = Boolean.TRUE; + + /** + * excel 表头数据 + */ + private Map headMap; + + /** + * 导入回执 + */ + private ExcelResult excelResult; + + public DefaultExcelListener(boolean isValidate) { + this.excelResult = new DefaultExcelResult<>(); + this.isValidate = isValidate; + } + + /** + * 处理异常 + * + * @param exception ExcelDataConvertException + * @param context Excel 上下文 + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + String errMsg = null; + if (exception instanceof ExcelDataConvertException excelDataConvertException) { + // 如果是某一个单元格的转换异常 能获取到具体行号 + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + if (exception instanceof ConstraintViolationException constraintViolationException) { + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); + errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + excelResult.getList().add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.debug("所有数据解析完成!"); + } + + @Override + public ExcelResult getExcelResult() { + return excelResult; + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java new file mode 100644 index 0000000..32fee7a --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java @@ -0,0 +1,399 @@ +package org.dromara.common.excel.core; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.EnumUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.metadata.FieldCache; +import com.alibaba.excel.metadata.FieldWrapper; +import com.alibaba.excel.util.ClassUtils; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.ss.util.WorkbookUtil; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.annotation.ExcelEnumFormat; + +import java.lang.reflect.Field; +import java.util.*; + +/** + *

Excel表格下拉选操作

+ * 考虑到下拉选过多可能导致Excel打开缓慢的问题,只校验前1000行 + *

+ * 即只有前1000行的数据可以用下拉框,超出的自行通过限制数据量的形式,第二次输出 + * + * @author Emil.Zhang + */ +@Slf4j +public class ExcelDownHandler implements SheetWriteHandler { + + /** + * Excel表格中的列名英文 + * 仅为了解析列英文,禁止修改 + */ + private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + /** + * 单选数据Sheet名 + */ + private static final String OPTIONS_SHEET_NAME = "options"; + /** + * 联动选择数据Sheet名的头 + */ + private static final String LINKED_OPTIONS_SHEET_NAME = "linkedOptions"; + /** + * 下拉可选项 + */ + private final List dropDownOptions; + private final DictService dictService; + /** + * 当前单选进度 + */ + private int currentOptionsColumnIndex; + /** + * 当前联动选择进度 + */ + private int currentLinkedOptionsSheetIndex; + + public ExcelDownHandler(List options) { + this.dropDownOptions = options; + this.currentOptionsColumnIndex = 0; + this.currentLinkedOptionsSheetIndex = 0; + this.dictService = SpringUtils.getBean(DictService.class); + } + + /** + *

开始创建下拉数据

+ * 1.通过解析传入的@ExcelProperty同级是否标注有@DropDown选项 + * 如果有且设置了value值,则将其直接置为下拉可选项 + *

+ * 2.或者在调用ExcelUtil时指定了可选项,将依据传入的可选项做下拉 + *

+ * 3.二者并存,注意调用方式 + */ + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Sheet sheet = writeSheetHolder.getSheet(); + // 开始设置下拉框 HSSFWorkbook + DataValidationHelper helper = sheet.getDataValidationHelper(); + Workbook workbook = writeWorkbookHolder.getWorkbook(); + FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder); + for (Map.Entry entry : fieldCache.getSortedFieldMap().entrySet()) { + Integer index = entry.getKey(); + FieldWrapper wrapper = entry.getValue(); + Field field = wrapper.getField(); + // 循环实体中的每个属性 + // 可选的下拉值 + List options = new ArrayList<>(); + if (field.isAnnotationPresent(ExcelDictFormat.class)) { + // 如果指定了@ExcelDictFormat,则使用字典的逻辑 + ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class); + String dictType = format.dictType(); + String converterExp = format.readConverterExp(); + if (StringUtils.isNotBlank(dictType)) { + // 如果传递了字典名,则依据字典建立下拉 + Collection values = Optional.ofNullable(dictService.getAllDictByDictType(dictType)) + .orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType))) + .values(); + options = new ArrayList<>(values); + } else if (StringUtils.isNotBlank(converterExp)) { + // 如果指定了确切的值,则直接解析确切的值 + List strList = StringUtils.splitList(converterExp, format.separator()); + options = StreamUtils.toList(strList, s -> StringUtils.split(s, "=")[1]); + } + } else if (field.isAnnotationPresent(ExcelEnumFormat.class)) { + // 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑 + ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class); + List values = EnumUtil.getFieldValues(format.enumClass(), format.textField()); + options = StreamUtils.toList(values, String::valueOf); + } + if (ObjectUtil.isNotEmpty(options)) { + // 仅当下拉可选项不为空时执行 + if (options.size() > 20) { + // 这里限制如果可选项大于20,则使用额外表形式 + dropDownWithSheet(helper, workbook, sheet, index, options); + } else { + // 否则使用固定值形式 + dropDownWithSimple(helper, sheet, index, options); + } + } + } + if (CollUtil.isEmpty(dropDownOptions)) { + return; + } + dropDownOptions.forEach(everyOptions -> { + // 如果传递了下拉框选择器参数 + if (!everyOptions.getNextOptions().isEmpty()) { + // 当二级选项不为空时,使用额外关联表的形式 + dropDownLinkedOptions(helper, workbook, sheet, everyOptions); + } else if (everyOptions.getOptions().size() > 10) { + // 当一级选项参数个数大于10,使用额外表的形式 + dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } else { + // 否则使用默认形式 + dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions()); + } + }); + } + + /** + *

简单下拉框

+ * 直接将可选项拼接为指定列的数据校验值 + * + * @param celIndex 列index + * @param value 下拉选可选值 + */ + private void dropDownWithSimple(DataValidationHelper helper, Sheet sheet, Integer celIndex, List value) { + if (ObjectUtil.isEmpty(value)) { + return; + } + this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(ArrayUtil.toArray(value, String.class))); + } + + /** + *

额外表格形式的级联下拉框

+ * + * @param options 额外表格形式存储的下拉可选项 + */ + private void dropDownLinkedOptions(DataValidationHelper helper, Workbook workbook, Sheet sheet, DropDownOptions options) { + String linkedOptionsSheetName = String.format("%s_%d", LINKED_OPTIONS_SHEET_NAME, currentLinkedOptionsSheetIndex); + // 创建联动下拉数据表 + Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName)); + // 将下拉表隐藏 + workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true); + // 选项数据 + List firstOptions = options.getOptions(); + Map> secoundOptionsMap = options.getNextOptions(); + + // 采用按行填充数据的方式,避免EasyExcel出现数据无法写入的问题 + // Attempting to write a row in the range that is already written to disk + + // 使用ArrayList记载数据,防止乱序 + List columnNames = new ArrayList<>(); + // 写入第一行,即第一级的数据 + Row firstRow = linkedOptionsDataSheet.createRow(0); + for (int columnIndex = 0; columnIndex < firstOptions.size(); columnIndex++) { + String columnName = firstOptions.get(columnIndex); + firstRow.createCell(columnIndex) + .setCellValue(columnName); + columnNames.add(columnName); + } + + // 创建名称管理器 + Name name = workbook.createName(); + // 设置名称管理器的别名 + name.setNameName(linkedOptionsSheetName); + // 以横向第一行创建一级下拉拼接引用位置 + String firstOptionsFunction = String.format("%s!$%s$1:$%s$1", + linkedOptionsSheetName, + getExcelColumnName(0), + getExcelColumnName(firstOptions.size()) + ); + // 设置名称管理器的引用位置 + name.setRefersToFormula(firstOptionsFunction); + // 设置数据校验为序列模式,引用的是名称管理器中的别名 + this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName)); + + // 创建二级选项的名称管理器 + for (int columIndex = 0; columIndex < columnNames.size(); columIndex++) { + // 列名 + String firstOptionsColumnName = getExcelColumnName(columIndex); + // 对应的一级值 + String thisFirstOptionsValue = columnNames.get(columIndex); + + // 以该一级选项值创建子名称管理器 + Name sonName = workbook.createName(); + // 设置名称管理器的别名 + sonName.setNameName(thisFirstOptionsValue); + // 以第二行该列数据拼接引用位置 + String sonFunction = String.format("%s!$%s$2:$%s$%d", + linkedOptionsSheetName, + firstOptionsColumnName, + firstOptionsColumnName, + // 二级选项存在则设置为(选项个数+1)行,否则设置为2行 + Math.max(Optional.ofNullable(secoundOptionsMap.get(thisFirstOptionsValue)) + .orElseGet(ArrayList::new).size(), 1) + 1 + ); + // 设置名称管理器的引用位置 + sonName.setRefersToFormula(sonFunction); + // 数据验证为序列模式,引用到每一个主表中的二级选项位置 + // 创建子项的名称管理器,只是为了使得Excel可以识别到数据 + String mainSheetFirstOptionsColumnName = getExcelColumnName(options.getIndex()); + for (int i = 0; i < 100; i++) { + // 以一级选项对应的主体所在位置创建二级下拉 + String secondOptionsFunction = String.format("=INDIRECT(%s%d)", mainSheetFirstOptionsColumnName, i + 1); + // 二级只能主表每一行的每一列添加二级校验 + markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction)); + } + } + + // 将二级数据处理为按行区分 + Map> columnValueMap = new HashMap<>(); + int currentRow = 1; + while (currentRow >= 0) { + boolean flag = false; + List rowData = new ArrayList<>(); + for (String columnName : columnNames) { + List data = secoundOptionsMap.get(columnName); + if (CollUtil.isEmpty(data)) { + // 添加空字符串填充位置 + rowData.add(" "); + continue; + } + // 取第一个 + String str = data.get(0); + rowData.add(str); + // 通过移除的方式避免重复 + data.remove(0); + // 设置可以继续 + flag = true; + } + columnValueMap.put(currentRow, rowData); + // 可以继续,则增加行数,否则置为负数跳出循环 + if (flag) { + currentRow++; + } else { + currentRow = -1; + } + } + + // 填充第二级选项数据 + columnValueMap.forEach((rowIndex, rowValues) -> { + Row row = linkedOptionsDataSheet.createRow(rowIndex); + for (int columnIndex = 0; columnIndex < rowValues.size(); columnIndex++) { + String rowValue = rowValues.get(columnIndex); + // 填充位置的部分不渲染 + if (StrUtil.isNotBlank(rowValue)) { + row.createCell(columnIndex) + .setCellValue(rowValue); + } + } + }); + + currentLinkedOptionsSheetIndex++; + } + + /** + *

额外表格形式的普通下拉框

+ * 由于下拉框可选值数量过多,为提升Excel打开效率,使用额外表格形式做下拉 + * + * @param celIndex 下拉选 + * @param value 下拉选可选值 + */ + private void dropDownWithSheet(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer celIndex, List value) { + // 创建下拉数据表 + Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))) + .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME))); + // 将下拉表隐藏 + workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true); + // 完善纵向的一级选项数据表 + for (int i = 0; i < value.size(); i++) { + int finalI = i; + // 获取每一选项行,如果没有则创建 + Row row = Optional.ofNullable(simpleDataSheet.getRow(i)) + .orElseGet(() -> simpleDataSheet.createRow(finalI)); + // 获取本级选项对应的选项列,如果没有则创建 + Cell cell = Optional.ofNullable(row.getCell(currentOptionsColumnIndex)) + .orElseGet(() -> row.createCell(currentOptionsColumnIndex)); + // 设置值 + cell.setCellValue(value.get(i)); + } + + // 创建名称管理器 + Name name = workbook.createName(); + // 设置名称管理器的别名 + String nameName = String.format("%s_%d", OPTIONS_SHEET_NAME, celIndex); + name.setNameName(nameName); + // 以纵向第一列创建一级下拉拼接引用位置 + String function = String.format("%s!$%s$1:$%s$%d", + OPTIONS_SHEET_NAME, + getExcelColumnName(currentOptionsColumnIndex), + getExcelColumnName(currentOptionsColumnIndex), + value.size()); + // 设置名称管理器的引用位置 + name.setRefersToFormula(function); + // 设置数据校验为序列模式,引用的是名称管理器中的别名 + this.markOptionsToSheet(helper, sheet, celIndex, helper.createFormulaListConstraint(nameName)); + currentOptionsColumnIndex++; + } + + /** + * 挂载下拉的列,仅限一级选项 + */ + private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex, + DataValidationConstraint constraint) { + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 挂载下拉的列,仅限二级选项 + */ + private void markLinkedOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer rowIndex, + Integer celIndex, DataValidationConstraint constraint) { + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, rowIndex, celIndex, celIndex); + markDataValidationToSheet(helper, sheet, constraint, addressList); + } + + /** + * 应用数据校验 + */ + private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet, + DataValidationConstraint constraint, CellRangeAddressList addressList) { + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, addressList); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) { + //数据校验 + dataValidation.setSuppressDropDownArrow(true); + //错误提示 + dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP); + dataValidation.createErrorBox("提示", "此值与单元格定义数据不一致"); + dataValidation.setShowErrorBox(true); + //选定提示 + dataValidation.createPromptBox("填写说明:", "填写内容只能为下拉中数据,其他数据将导致导入失败"); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } else { + dataValidation.setSuppressDropDownArrow(false); + } + sheet.addValidationData(dataValidation); + } + + /** + *

依据列index获取列名英文

+ * 依据列index转换为Excel中的列名英文 + *

例如第1列,index为0,解析出来为A列

+ * 第27列,index为26,解析为AA列 + *

第28列,index为27,解析为AB列

+ * + * @param columnIndex 列index + * @return 列index所在得英文名 + */ + private String getExcelColumnName(int columnIndex) { + // 26一循环的次数 + int columnCircleCount = columnIndex / 26; + // 26一循环内的位置 + int thisCircleColumnIndex = columnIndex % 26; + // 26一循环的次数大于0,则视为栏名至少两位 + String columnPrefix = columnCircleCount == 0 + ? StrUtil.EMPTY + : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1); + // 从26一循环内取对应的栏位名 + String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1); + // 将二者拼接即为最终的栏位名 + return columnPrefix + columnNext; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java new file mode 100644 index 0000000..2d0340f --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java @@ -0,0 +1,14 @@ +package org.dromara.common.excel.core; + +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Excel 导入监听 + * + * @author Lion Li + */ +public interface ExcelListener extends ReadListener { + + ExcelResult getExcelResult(); + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java new file mode 100644 index 0000000..0c2a418 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java @@ -0,0 +1,26 @@ +package org.dromara.common.excel.core; + +import java.util.List; + +/** + * excel返回对象 + * + * @author Lion Li + */ +public interface ExcelResult { + + /** + * 对象列表 + */ + List getList(); + + /** + * 错误列表 + */ + List getErrorList(); + + /** + * 导入回执 + */ + String getAnalysis(); +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java new file mode 100644 index 0000000..a2aa495 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java @@ -0,0 +1,135 @@ +package org.dromara.common.excel.handler; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.excel.metadata.data.DataFormatData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.handler.context.CellWriteHandlerContext; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.excel.annotation.ExcelNotation; +import org.dromara.common.excel.annotation.ExcelRequired; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 批注、必填 + * + * @author guzhouyanyu + */ +public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler { + + /** + * 批注 + */ + private final Map notationMap; + + /** + * 头列字体颜色 + */ + private final Map headColumnMap; + + + public DataWriteHandler(Class clazz) { + notationMap = getNotationMap(clazz); + headColumnMap = getRequiredMap(clazz); + } + + @Override + public void afterCellDispose(CellWriteHandlerContext context) { + if (CollUtil.isEmpty(notationMap) && CollUtil.isEmpty(headColumnMap)) { + return; + } + WriteCellData cellData = context.getFirstCellData(); + WriteCellStyle writeCellStyle = cellData.getOrCreateStyle(); + + DataFormatData dataFormatData = new DataFormatData(); + // 单元格设置为文本格式 + dataFormatData.setIndex((short) 49); + writeCellStyle.setDataFormatData(dataFormatData); + + if (context.getHead()) { + Cell cell = context.getCell(); + WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder(); + Sheet sheet = writeSheetHolder.getSheet(); + Workbook workbook = writeSheetHolder.getSheet().getWorkbook(); + Drawing drawing = sheet.createDrawingPatriarch(); + // 设置标题字体样式 + WriteFont headWriteFont = new WriteFont(); + // 加粗 + headWriteFont.setBold(true); + if (CollUtil.isNotEmpty(headColumnMap) && headColumnMap.containsKey(cell.getColumnIndex())) { + // 设置字体颜色 + headWriteFont.setColor(headColumnMap.get(cell.getColumnIndex())); + } + writeCellStyle.setWriteFont(headWriteFont); + CellStyle cellStyle = StyleUtil.buildCellStyle(workbook, null, writeCellStyle); + cell.setCellStyle(cellStyle); + + if (CollUtil.isNotEmpty(notationMap) && notationMap.containsKey(cell.getColumnIndex())) { + // 批注内容 + String notationContext = notationMap.get(cell.getColumnIndex()); + // 创建绘图对象 + Comment comment = drawing.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), 0, (short) 5, 5)); + comment.setString(new XSSFRichTextString(notationContext)); + cell.setCellComment(comment); + } + } + } + + /** + * 获取必填列 + */ + private static Map getRequiredMap(Class clazz) { + Map requiredMap = new HashMap<>(); + Field[] fields = clazz.getDeclaredFields(); + // 检查 fields 数组是否为空 + if (fields.length == 0) { + return requiredMap; + } + Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName())); + + for (int i = 0; i < filteredFields.length; i++) { + Field field = filteredFields[i]; + if (!field.isAnnotationPresent(ExcelRequired.class)) { + continue; + } + ExcelRequired excelRequired = field.getAnnotation(ExcelRequired.class); + int columnIndex = excelRequired.index() == -1 ? i : excelRequired.index(); + requiredMap.put(columnIndex, excelRequired.fontColor().getIndex()); + } + return requiredMap; + } + + /** + * 获取批注 + */ + private static Map getNotationMap(Class clazz) { + Map notationMap = new HashMap<>(); + Field[] fields = clazz.getDeclaredFields(); + // 检查 fields 数组是否为空 + if (fields.length == 0) { + return notationMap; + } + Field[] filteredFields = ReflectUtils.getFields(clazz, field -> !"serialVersionUID".equals(field.getName())); + for (int i = 0; i < filteredFields.length; i++) { + Field field = filteredFields[i]; + if (!field.isAnnotationPresent(ExcelNotation.class)) { + continue; + } + ExcelNotation excelNotation = field.getAnnotation(ExcelNotation.class); + int columnIndex = excelNotation.index() == -1 ? i : excelNotation.index(); + notationMap.put(columnIndex, excelNotation.value()); + } + return notationMap; + } +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java new file mode 100644 index 0000000..e6f9f82 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java @@ -0,0 +1,453 @@ +package org.dromara.common.excel.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.builder.ExcelWriterBuilder; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.excel.convert.ExcelBigNumberConvert; +import org.dromara.common.excel.core.*; +import org.dromara.common.excel.handler.DataWriteHandler; +import org.dromara.zhishu.annotation.EnableExcelComment; +import org.dromara.zhishu.handler.EmptyListTipHandler; +import org.dromara.zhishu.handler.HeadCommentWriteHandler; +import org.dromara.zhishu.handler.TipRowWriteHandler; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Excel相关处理 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ExcelUtil { + + /** + * 同步导入(适用于小数据量) + * + * @param is 输入流 + * @return 转换后集合 + */ + public static List importExcel(InputStream is, Class clazz) { + return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); + } + + + /** + * 使用校验监听器 异步导入 同步返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param isValidate 是否 Validator 检验 默认为是 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate) { + DefaultExcelListener listener = new DefaultExcelListener<>(isValidate); + EasyExcel.read(is, clazz, listener).headRowNumber(1).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 使用自定义监听器 异步导入 自定义返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param listener 自定义监听器 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, ExcelListener listener) { + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, false, os, null); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + * @param options 级联下拉选 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response, List options) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, false, os, options); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, merge, os, null); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + * @param options 级联下拉选 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response, List options) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + exportExcel(list, sheetName, clazz, merge, os, options); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os) { + exportExcel(list, sheetName, clazz, false, os, null); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param os 输出流 + * @param options 级联下拉选内容 + */ + public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os, List options) { + exportExcel(list, sheetName, clazz, false, os, options); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param os 输出流 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, + OutputStream os, List options) { + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .autoCloseStream(false) + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new DataWriteHandler(clazz)) + .sheet(sheetName); + + if (clazz.isAnnotationPresent(EnableExcelComment.class)) { + builder.registerWriteHandler(new HeadCommentWriteHandler()); + // 根据 list 是否为空,注册不同的处理器 + if (list == null || list.isEmpty()) { + // 空LIST:使用 EmptyListTipHandler + builder.registerWriteHandler(new EmptyListTipHandler()); + } else { + // 有数据:使用 TipRowWriteHandler + builder.registerWriteHandler(new TipRowWriteHandler()); + } + } + if (merge) { + builder.registerWriteHandler(new CellMergeStrategy(list, true)); + } + + builder.registerWriteHandler(new ExcelDownHandler(options)); + builder.doWrite(list); + } + + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplate(List data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplate(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplate(List data, String templatePath, OutputStream os) { + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .registerWriteHandler(new DataWriteHandler(data.get(0).getClass())) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + // 单表多数据导出 模板格式为 {.属性} + for (T d : data) { + excelWriter.fill(d, writeSheet); + } + excelWriter.finish(); + } + + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplateMultiList(Map data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplateMultiList(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 多sheet模板导出 模板格式为 {key.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param response 响应体 + */ + public static void exportTemplateMultiSheet(List> data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ServletOutputStream os = response.getOutputStream(); + exportTemplateMultiSheet(data, templatePath, os); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplateMultiList(Map data, String templatePath, OutputStream os) { + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + for (Map.Entry map : data.entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } + } + excelWriter.finish(); + } + + /** + * 多sheet模板导出 模板格式为 {key.属性} + * + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + * @param os 输出流 + */ + public static void exportTemplateMultiSheet(List> data, String templatePath, OutputStream os) { + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(os) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + for (int i = 0; i < data.size(); i++) { + WriteSheet writeSheet = EasyExcel.writerSheet(i).build(); + for (Map.Entry map : data.get(i).entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } + } + } + excelWriter.finish(); + } + + /** + * 重置响应体 + */ + private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException { + String filename = encodingFilename(sheetName); + FileUtils.setAttachmentResponseHeader(response, filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String convertByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[0].equals(value)) { + propertyString.append(itemArray[1] + separator); + break; + } + } + } else { + if (itemArray[0].equals(propertyValue)) { + return itemArray[1]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + public static String reverseByExp(String propertyValue, String converterExp, String separator) { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(StringUtils.SEPARATOR); + for (String item : convertSource) { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(propertyValue, separator)) { + for (String value : propertyValue.split(separator)) { + if (itemArray[1].equals(value)) { + propertyString.append(itemArray[0] + separator); + break; + } + } + } else { + if (itemArray[1].equals(propertyValue)) { + return itemArray[0]; + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 编码文件名 + */ + public static String encodingFilename(String filename) { + return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; + } + +} diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/annotation/EnableExcelComment.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/annotation/EnableExcelComment.java new file mode 100644 index 0000000..ca14dcc --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/annotation/EnableExcelComment.java @@ -0,0 +1,9 @@ +package org.dromara.zhishu.annotation; + +import java.lang.annotation.*; + +// 创建标记注解 +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface EnableExcelComment { +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/EmptyListTipHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/EmptyListTipHandler.java new file mode 100644 index 0000000..a314bf3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/EmptyListTipHandler.java @@ -0,0 +1,74 @@ +package org.dromara.zhishu.handler; + +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.handler.context.SheetWriteHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; + +@Slf4j +public class EmptyListTipHandler implements SheetWriteHandler { + + private final java.util.Map tipMap = new java.util.HashMap<>(); + private CellStyle cachedTipStyle; + private boolean executed = false; + + public EmptyListTipHandler() { + tipMap.put(5, "表头文字不要有任何改动。"); // 第6行 + tipMap.put(7, "发布商品任务ISBN、价格、库存列必须有且必填。"); // 第8行 + tipMap.put(8, "修改价格、库存、上下架状态任务 ISBN、商品ID、商品编码必填其中一个"); // 第9行 + tipMap.put(10, "用鼠标指向每列的标题都有详细的说明。"); // 第11行 + } + + @Override + public void afterSheetCreate(SheetWriteHandlerContext context) { + if (executed) { + return; + } + + Sheet sheet = context.getWriteSheetHolder().getSheet(); + + // 检查是否有数据行(除了表头之外的行) + // 在 Sheet 刚创建时,还没有数据,所以这个方法会在数据写入之前执行 + // 我们需要判断是否为空 LIST,这个判断在调用方做 + + // 设置L列宽度 + sheet.setColumnWidth(11, 80 * 256); + + // 创建提示行 + Workbook workbook = sheet.getWorkbook(); + CellStyle tipStyle = getOrCreateTipStyle(workbook); + + for (java.util.Map.Entry entry : tipMap.entrySet()) { + int rowIndex = entry.getKey(); + Row row = sheet.getRow(rowIndex); + if (row == null) { + row = sheet.createRow(rowIndex); + } + Cell cell = row.getCell(11); + if (cell == null) { + cell = row.createCell(11); + } + cell.setCellValue(entry.getValue()); + cell.setCellStyle(tipStyle); + } + + executed = true; + log.info("空LIST场景:已在L6、L8、L9、L11添加提示文字"); + } + + private CellStyle getOrCreateTipStyle(Workbook workbook) { + if (cachedTipStyle == null) { + Font font = workbook.createFont(); + font.setBold(true); + font.setFontHeightInPoints((short) 12); + font.setColor(IndexedColors.RED.getIndex()); + + cachedTipStyle = workbook.createCellStyle(); + cachedTipStyle.setFont(font); + cachedTipStyle.setWrapText(true); + cachedTipStyle.setAlignment(HorizontalAlignment.LEFT); + cachedTipStyle.setVerticalAlignment(VerticalAlignment.CENTER); + } + return cachedTipStyle; + } +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/TipRowWriteHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/TipRowWriteHandler.java new file mode 100644 index 0000000..423b986 --- /dev/null +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/zhishu/handler/TipRowWriteHandler.java @@ -0,0 +1,110 @@ +package org.dromara.zhishu.handler; + +import com.alibaba.excel.write.handler.RowWriteHandler; +import com.alibaba.excel.write.handler.context.RowWriteHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; + +@Slf4j +public class TipRowWriteHandler implements RowWriteHandler { + + private final java.util.Map tipMap = new java.util.HashMap<>(); + private CellStyle cachedTipStyle; + private boolean columnWidthSet = false; + private boolean hasData = false; // 标记是否有数据 + + public TipRowWriteHandler() { + tipMap.put(5, "表头文字不要有任何改动。"); // 第6行 + tipMap.put(7, "发布商品任务ISBN、价格、库存列必须有且必填。"); // 第8行 + tipMap.put(8, "修改价格、库存、上下架状态任务 ISBN、商品ID、商品编码必填其中一个"); // 第9行 + tipMap.put(10, "用鼠标指向每列的标题都有详细的说明。"); // 第11行 + } + + @Override + public void beforeRowCreate(RowWriteHandlerContext context) { + // 设置L列宽度(只一次) + if (!columnWidthSet && context.getRowIndex() == 0) { + Sheet sheet = context.getWriteSheetHolder().getSheet(); + sheet.setColumnWidth(11, 80 * 256); + columnWidthSet = true; + log.info("已设置L列宽度为80个字符"); + } + } + + @Override + public void afterRowDispose(RowWriteHandlerContext context) { + int rowIndex = context.getRowIndex(); + + // 检查是否有数据(除了表头之外的行) + if (rowIndex > 0) { + hasData = true; + } + + // 检查当前行是否是需要写入提示的行 + if (tipMap.containsKey(rowIndex)) { + Sheet sheet = context.getWriteSheetHolder().getSheet(); + Workbook workbook = sheet.getWorkbook(); + + Row row = sheet.getRow(rowIndex); + if (row == null) { + row = sheet.createRow(rowIndex); + } + + Cell cell = row.getCell(11); + if (cell == null) { + cell = row.createCell(11); + } + + cell.setCellValue(tipMap.get(rowIndex)); + cell.setCellStyle(getOrCreateTipStyle(workbook)); + + log.debug("已在L{}单元格添加提示文字", rowIndex + 1); + } + + // 判断是否是最后一行(空LIST时,只有rowIndex=0,不会进入这里) + // 如果有数据,走上面的逻辑;如果空LIST,不会进入afterRowDispose + } + + /** + * 供外部调用的方法:空LIST时手动触发提示写入 + */ + public void addTipsForEmptyList(Sheet sheet) { + if (sheet == null) { + return; + } + Workbook workbook = sheet.getWorkbook(); + CellStyle tipStyle = getOrCreateTipStyle(workbook); + + for (java.util.Map.Entry entry : tipMap.entrySet()) { + int rowIndex = entry.getKey(); + Row row = sheet.getRow(rowIndex); + if (row == null) { + row = sheet.createRow(rowIndex); + } + Cell cell = row.getCell(11); + if (cell == null) { + cell = row.createCell(11); + } + cell.setCellValue(entry.getValue()); + cell.setCellStyle(tipStyle); + } + + log.info("空LIST场景:已在L6、L8、L9、L11添加提示文字"); + } + + private CellStyle getOrCreateTipStyle(Workbook workbook) { + if (cachedTipStyle == null) { + Font font = workbook.createFont(); + font.setBold(true); + font.setFontHeightInPoints((short) 12); + font.setColor(IndexedColors.RED.getIndex()); + + cachedTipStyle = workbook.createCellStyle(); + cachedTipStyle.setFont(font); + cachedTipStyle.setWrapText(true); + cachedTipStyle.setAlignment(HorizontalAlignment.LEFT); + cachedTipStyle.setVerticalAlignment(VerticalAlignment.CENTER); + } + return cachedTipStyle; + } +} \ No newline at end of file diff --git a/ruoyi-common/ruoyi-common-idempotent/pom.xml b/ruoyi-common/ruoyi-common-idempotent/pom.xml new file mode 100644 index 0000000..64418b4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/pom.xml @@ -0,0 +1,41 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-idempotent + + + ruoyi-common-idempotent 幂等功能 + + + + + org.dromara + ruoyi-common-json + + + + org.dromara + ruoyi-common-redis + + + + cn.hutool + hutool-crypto + + + + cn.dev33 + sa-token-core + + + + + diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java new file mode 100644 index 0000000..42ae802 --- /dev/null +++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java @@ -0,0 +1,29 @@ +package org.dromara.common.idempotent.annotation; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +/** + * 自定义注解防止表单重复提交 + * + * @author Lion Li + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit { + + /** + * 间隔时间(ms),小于此时间视为重复提交 + */ + int interval() default 5000; + + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; + + /** + * 提示消息 支持国际化 格式为 {code} + */ + String message() default "{repeat.submit.message}"; + +} diff --git a/ruoyi-common/ruoyi-common-job/pom.xml b/ruoyi-common/ruoyi-common-job/pom.xml new file mode 100644 index 0000000..3a4a0cb --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/pom.xml @@ -0,0 +1,46 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-job + + + ruoyi-common-job 定时任务 + + + + + + org.springframework.boot + spring-boot-autoconfigure + + + + + com.aizuda + snail-job-client-starter + + + com.aizuda + snail-job-client-job-core + + + + org.projectlombok + lombok + + + + org.dromara + ruoyi-common-core + + + + diff --git a/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..3aa1881 --- /dev/null +++ b/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.job.config.SnailJobConfig diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java new file mode 100644 index 0000000..8752353 --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java @@ -0,0 +1,42 @@ +package org.dromara.common.json.handler; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JacksonStdImpl; +import com.fasterxml.jackson.databind.ser.std.NumberSerializer; + +import java.io.IOException; + +/** + * 超出 JS 最大最小值 处理 + * + * @author Lion Li + */ +@JacksonStdImpl +public class BigNumberSerializer extends NumberSerializer { + + /** + * 根据 JS Number.MAX_SAFE_INTEGER 与 Number.MIN_SAFE_INTEGER 得来 + */ + private static final long MAX_SAFE_INTEGER = 9007199254740991L; + private static final long MIN_SAFE_INTEGER = -9007199254740991L; + + /** + * 提供实例 + */ + public static final BigNumberSerializer INSTANCE = new BigNumberSerializer(Number.class); + + public BigNumberSerializer(Class rawType) { + super(rawType); + } + + @Override + public void serialize(Number value, JsonGenerator gen, SerializerProvider provider) throws IOException { + // 超出范围 序列化为字符串 + if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + super.serialize(value, gen, provider); + } else { + gen.writeString(value.toString()); + } + } +} diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java new file mode 100644 index 0000000..65c2faa --- /dev/null +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java @@ -0,0 +1,170 @@ +package org.dromara.common.json.utils; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils { + + private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class); + + public static ObjectMapper getObjectMapper() { + return OBJECT_MAPPER; + } + + /** + * 将对象转换为JSON格式的字符串 + * + * @param object 要转换的对象 + * @return JSON格式的字符串,如果对象为null,则返回null + * @throws RuntimeException 如果转换过程中发生JSON处理异常,则抛出运行时异常 + */ + public static String toJsonString(Object object) { + if (ObjectUtil.isNull(object)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型的对象 + * + * @param text JSON格式的字符串 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将字节数组转换为指定类型的对象 + * + * @param bytes 字节数组 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字节数组为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型的对象,支持复杂类型 + * + * @param text JSON格式的字符串 + * @param typeReference 指定类型的TypeReference对象 + * @param 目标对象的泛型类型 + * @return 转换后的对象,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static T parseObject(String text, TypeReference typeReference) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为Dict对象 + * + * @param text JSON格式的字符串 + * @return 转换后的Dict对象,如果字符串为空或者不是JSON格式则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static Dict parseMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); + } catch (MismatchedInputException e) { + // 类型不匹配说明不是json + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为Dict对象的列表 + * + * @param text JSON格式的字符串 + * @return 转换后的Dict对象的列表,如果字符串为空则返回null + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static List parseArrayMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将JSON格式的字符串转换为指定类型对象的列表 + * + * @param text JSON格式的字符串 + * @param clazz 要转换的目标对象类型 + * @param 目标对象的泛型类型 + * @return 转换后的对象的列表,如果字符串为空则返回空列表 + * @throws RuntimeException 如果转换过程中发生IO异常,则抛出运行时异常 + */ + public static List parseArray(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-log/pom.xml b/ruoyi-common/ruoyi-common-log/pom.xml new file mode 100644 index 0000000..1e2b33b --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/pom.xml @@ -0,0 +1,32 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-log + + + ruoyi-common-log 日志记录 + + + + + + org.dromara + ruoyi-common-satoken + + + + org.dromara + ruoyi-common-json + + + + + diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java new file mode 100644 index 0000000..2dced97 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java @@ -0,0 +1,48 @@ +package org.dromara.common.log.annotation; + +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.log.enums.OperatorType; + +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author ruoyi + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log { + /** + * 模块 + */ + String title() default ""; + + /** + * 功能 + */ + BusinessType businessType() default BusinessType.OTHER; + + /** + * 操作人类别 + */ + OperatorType operatorType() default OperatorType.MANAGE; + + /** + * 是否保存请求的参数 + */ + boolean isSaveRequestData() default true; + + /** + * 是否保存响应的参数 + */ + boolean isSaveResponseData() default true; + + + /** + * 排除指定的请求参数 + */ + String[] excludeParamNames() default {}; + +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java new file mode 100644 index 0000000..8ab2719 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java @@ -0,0 +1,219 @@ +package org.dromara.common.log.aspect; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.time.StopWatch; +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.domain.model.LoginUser; +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.json.utils.JsonUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessStatus; +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.http.HttpMethod; +import org.springframework.validation.BindingResult; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.Map; +import java.util.StringJoiner; + +/** + * 操作日志记录处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +@AutoConfiguration +public class LogAspect { + + /** + * 排除敏感属性字段 + */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + + + /** + * 计时 key + */ + private static final ThreadLocal KEY_CACHE = new ThreadLocal<>(); + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(controllerLog)") + public void doBefore(JoinPoint joinPoint, Log controllerLog) { + StopWatch stopWatch = new StopWatch(); + KEY_CACHE.set(stopWatch); + stopWatch.start(); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) { + handleLog(joinPoint, controllerLog, null, jsonResult); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) { + handleLog(joinPoint, controllerLog, e, null); + } + + protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) { + try { + + // *========数据库日志=========*// + OperLogEvent operLog = new OperLogEvent(); + operLog.setTenantId(LoginHelper.getTenantId()); + operLog.setStatus(BusinessStatus.SUCCESS.ordinal()); + // 请求的地址 + String ip = ServletUtils.getClientIP(); + operLog.setOperIp(ip); + operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); + LoginUser loginUser = LoginHelper.getLoginUser(); + operLog.setOperName(loginUser.getUsername()); + operLog.setDeptName(loginUser.getDeptName()); + + if (e != null) { + operLog.setStatus(BusinessStatus.FAIL.ordinal()); + operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 3800)); + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + operLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); + // 处理设置注解上的参数 + getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); + // 设置消耗时间 + StopWatch stopWatch = KEY_CACHE.get(); + stopWatch.stop(); + operLog.setCostTime(stopWatch.getDuration().toMillis()); + // 发布事件保存数据库 + SpringUtils.context().publishEvent(operLog); + } catch (Exception exp) { + // 记录本地异常日志 + log.error("异常信息:{}", exp.getMessage()); + } finally { + KEY_CACHE.remove(); + } + } + + /** + * 获取注解中对方法的描述信息 用于Controller层注解 + * + * @param log 日志 + * @param operLog 操作日志 + * @throws Exception + */ + public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception { + // 设置action动作 + operLog.setBusinessType(log.businessType().ordinal()); + // 设置标题 + operLog.setTitle(log.title()); + // 设置操作人类别 + operLog.setOperatorType(log.operatorType().ordinal()); + // 是否需要保存request,参数和值 + if (log.isSaveRequestData()) { + // 获取参数的信息,传入到数据库中。 + setRequestValue(joinPoint, operLog, log.excludeParamNames()); + } + // 是否需要保存response,参数和值 + if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) { + operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 3800)); + } + } + + /** + * 获取请求的参数,放到log中 + * + * @param operLog 操作日志 + * @throws Exception 异常 + */ + private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception { + Map paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); + String requestMethod = operLog.getRequestMethod(); + if (MapUtil.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) { + String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); + operLog.setOperParam(StringUtils.substring(params, 0, 3800)); + } else { + MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES); + MapUtil.removeAny(paramsMap, excludeParamNames); + operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 3800)); + } + } + + /** + * 参数拼装 + */ + private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) { + StringJoiner params = new StringJoiner(" "); + if (ArrayUtil.isEmpty(paramsArray)) { + return params.toString(); + } + for (Object o : paramsArray) { + if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) { + String str = JsonUtils.toJsonString(o); + Dict dict = JsonUtils.parseMap(str); + if (MapUtil.isNotEmpty(dict)) { + MapUtil.removeAny(dict, EXCLUDE_PROPERTIES); + MapUtil.removeAny(dict, excludeParamNames); + str = JsonUtils.toJsonString(dict); + } + params.add(str); + } + } + 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-log/src/main/java/org/dromara/common/log/enums/OperatorType.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java new file mode 100644 index 0000000..de9328b --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java @@ -0,0 +1,23 @@ +package org.dromara.common.log.enums; + +/** + * 操作人类别 + * + * @author ruoyi + */ +public enum OperatorType { + /** + * 其它 + */ + OTHER, + + /** + * 后台用户 + */ + MANAGE, + + /** + * 手机端用户 + */ + MOBILE +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java new file mode 100644 index 0000000..938eaad --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java @@ -0,0 +1,52 @@ +package org.dromara.common.log.event; + +import lombok.Data; + +import jakarta.servlet.http.HttpServletRequest; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 登录事件 + * + * @author Lion Li + */ + +@Data +public class LogininforEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 用户账号 + */ + private String username; + + /** + * 登录状态 0成功 1失败 + */ + private String status; + + /** + * 提示消息 + */ + private String message; + + /** + * 请求体 + */ + private HttpServletRequest request; + + /** + * 其他参数 + */ + private Object[] args; + +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java new file mode 100644 index 0000000..0386192 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java @@ -0,0 +1,115 @@ +package org.dromara.common.log.event; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 操作日志事件 + * + * @author Lion Li + */ + +@Data +public class OperLogEvent implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + private Long operId; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 操作模块 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求url + */ + private String operUrl; + + /** + * 操作地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; +} diff --git a/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..6893020 --- /dev/null +++ b/ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.log.aspect.LogAspect diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java new file mode 100644 index 0000000..0ea3007 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java @@ -0,0 +1,37 @@ +package org.dromara.common.mail.config; + +import cn.hutool.extra.mail.MailAccount; +import org.dromara.common.mail.config.properties.MailProperties; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * JavaMail 配置 + * + * @author Michelle.Chung + */ +@AutoConfiguration +@EnableConfigurationProperties(MailProperties.class) +public class MailConfig { + + @Bean + @ConditionalOnProperty(value = "mail.enabled", havingValue = "true") + public MailAccount mailAccount(MailProperties mailProperties) { + MailAccount account = new MailAccount(); + account.setHost(mailProperties.getHost()); + account.setPort(mailProperties.getPort()); + account.setAuth(mailProperties.getAuth()); + account.setFrom(mailProperties.getFrom()); + account.setUser(mailProperties.getUser()); + account.setPass(mailProperties.getPass()); + account.setSocketFactoryPort(mailProperties.getPort()); + account.setStarttlsEnable(mailProperties.getStarttlsEnable()); + account.setSslEnable(mailProperties.getSslEnable()); + account.setTimeout(mailProperties.getTimeout()); + account.setConnectionTimeout(mailProperties.getConnectionTimeout()); + return account; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml new file mode 100644 index 0000000..d79ba28 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml @@ -0,0 +1,52 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-mybatis + + + ruoyi-common-mybatis 数据库服务 + + + + + org.dromara + ruoyi-common-core + + + + org.dromara + ruoyi-common-satoken + + + + + com.baomidou + dynamic-datasource-spring-boot3-starter + + + + com.baomidou + mybatis-plus-spring-boot3-starter + + + + com.baomidou + mybatis-plus-jsqlparser + + + + + p6spy + p6spy + + + + diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java new file mode 100644 index 0000000..2879b9d --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java @@ -0,0 +1,40 @@ +package org.dromara.common.mybatis.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限注解,用于标记数据权限的占位符关键字和替换值 + *

+ * 一个注解只能对应一个模板 + *

+ * + * @author Lion Li + * @version 3.5.0 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataColumn { + + /** + * 数据权限模板的占位符关键字,默认为 "deptName" + * + * @return 占位符关键字数组 + */ + String[] key() default "deptName"; + + /** + * 数据权限模板的占位符替换值,默认为 "dept_id" + * + * @return 占位符替换值数组 + */ + String[] value() default "dept_id"; + + /** + * 权限标识符 用于通过菜单权限标识符来获取数据权限 + * 拥有此标识符的角色 将不会拼接此角色的数据过滤sql + * + * @return 权限标识符 + */ + String permission() default ""; +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java new file mode 100644 index 0000000..f5f22d5 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java @@ -0,0 +1,30 @@ +package org.dromara.common.mybatis.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限组注解,用于标记数据权限配置数组 + * + * @author Lion Li + * @version 3.5.0 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + /** + * 数据权限配置数组,用于指定数据权限的占位符关键字和替换值 + * + * @return 数据权限配置数组 + */ + DataColumn[] value(); + + /** + * 权限拼接标识符(用于指定连接语句的sql符号) + * 如不填 默认 select 用 OR 其他语句用 AND + * 内容 OR 或者 AND + */ + String joinStr() default ""; + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java new file mode 100644 index 0000000..1c83cc3 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAspect.java @@ -0,0 +1,50 @@ +package org.dromara.common.mybatis.aspect; + +import lombok.extern.slf4j.Slf4j; +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.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.helper.DataPermissionHelper; + +/** + * 数据权限处理 + * + * @author Lion Li + */ +@Slf4j +@Aspect +public class DataPermissionAspect { + + /** + * 处理请求前执行 + */ + @Before(value = "@annotation(dataPermission)") + public void doBefore(JoinPoint joinPoint, DataPermission dataPermission) { + DataPermissionHelper.setPermission(dataPermission); + } + + /** + * 处理完请求后执行 + * + * @param joinPoint 切点 + */ + @AfterReturning(pointcut = "@annotation(dataPermission)") + public void doAfterReturning(JoinPoint joinPoint, DataPermission dataPermission) { + DataPermissionHelper.removePermission(); + } + + /** + * 拦截异常操作 + * + * @param joinPoint 切点 + * @param e 异常 + */ + @AfterThrowing(value = "@annotation(dataPermission)", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, DataPermission dataPermission, Exception e) { + DataPermissionHelper.removePermission(); + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java new file mode 100644 index 0000000..3912524 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java @@ -0,0 +1,139 @@ +package org.dromara.common.mybatis.config; + +import cn.hutool.core.net.NetUtil; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler; +import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import org.dromara.common.core.factory.YmlPropertySourceFactory; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.mybatis.aspect.DataPermissionAspect; +import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler; +import org.dromara.common.mybatis.handler.MybatisExceptionHandler; +import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler; +import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.BeansException; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.PropertySource; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * mybatis-plus配置类(下方注释有插件介绍) + * + * @author Lion Li + */ +@EnableTransactionManagement(proxyTargetClass = true) +@MapperScan("${mybatis-plus.mapperPackage}") +@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class) +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + // 多租户插件 必须放到第一位 + try { + TenantLineInnerInterceptor tenant = SpringUtils.getBean(TenantLineInnerInterceptor.class); + interceptor.addInnerInterceptor(tenant); + } catch (BeansException ignore) { + } + paginationInnerInterceptor().setMaxLimit(1000L); + // 数据权限处理 + interceptor.addInnerInterceptor(dataPermissionInterceptor()); + // 分页插件 + interceptor.addInnerInterceptor(paginationInnerInterceptor()); + // 乐观锁插件 + interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor()); + return interceptor; + } + + /** + * 数据权限拦截器 + */ + public PlusDataPermissionInterceptor dataPermissionInterceptor() { + return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage")); + } + + /** + * 数据权限切面处理器 + */ + @Bean + public DataPermissionAspect dataPermissionAspect() { + return new DataPermissionAspect(); + } + + /** + * 分页插件,自动识别数据库类型 + */ + public PaginationInnerInterceptor paginationInnerInterceptor() { + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(); + // 分页合理化 + paginationInnerInterceptor.setOverflow(true); + return paginationInnerInterceptor; + } + + /** + * 乐观锁插件 + */ + public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() { + return new OptimisticLockerInnerInterceptor(); + } + + /** + * 元对象字段填充控制器 + */ + @Bean + public MetaObjectHandler metaObjectHandler() { + return new InjectionMetaObjectHandler(); + } + + /** + * 使用网卡信息绑定雪花生成器 + * 防止集群雪花ID重复 + */ + @Bean + public IdentifierGenerator idGenerator() { + return new DefaultIdentifierGenerator(NetUtil.getLocalhost()); + } + + /** + * 异常处理器 + */ + @Bean + public MybatisExceptionHandler mybatisExceptionHandler() { + return new MybatisExceptionHandler(); + } + + /** + * 初始化表对象处理器 + */ + @Bean + public PostInitTableInfoHandler postInitTableInfoHandler() { + return new PlusPostInitTableInfoHandler(); + } + + /** + * PaginationInnerInterceptor 分页插件,自动识别数据库类型 + * https://baomidou.com/pages/97710a/ + * OptimisticLockerInnerInterceptor 乐观锁插件 + * https://baomidou.com/pages/0d93c0/ + * MetaObjectHandler 元对象字段填充控制器 + * https://baomidou.com/pages/4c6bcf/ + * ISqlInjector sql注入器 + * https://baomidou.com/pages/42ea4a/ + * BlockAttackInnerInterceptor 如果是对全表的删除或更新操作,就会终止该操作 + * https://baomidou.com/pages/f9a237/ + * IllegalSQLInnerInterceptor sql性能规范插件(垃圾SQL拦截) + * IdentifierGenerator 自定义主键策略 + * https://baomidou.com/pages/568eb2/ + * TenantLineInnerInterceptor 多租户插件 + * https://baomidou.com/pages/aef2f2/ + * DynamicTableNameInnerInterceptor 动态表名插件 + * https://baomidou.com/pages/2a45ff/ + */ + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java new file mode 100644 index 0000000..13a7941 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java @@ -0,0 +1,70 @@ +package org.dromara.common.mybatis.core.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Entity基类 + * + * @author Lion Li + */ +@Data +public class BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 搜索值 + */ + @JsonIgnore + @TableField(exist = false) + private String searchValue; + + /** + * 创建部门 + */ + @TableField(fill = FieldFill.INSERT) + private Long createDept; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private Long createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Long updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @TableField(exist = false) + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java new file mode 100644 index 0000000..89dbbe2 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java @@ -0,0 +1,354 @@ +package org.dromara.common.mybatis.core.mapper; + +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.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.toolkit.Db; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StreamUtils; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * 自定义 Mapper 接口, 实现 自定义扩展 + * + * @param table 泛型 + * @param vo 泛型 + * @author Lion Li + * @since 2021-05-13 + */ +@SuppressWarnings("unchecked") +public interface BaseMapperPlus extends BaseMapper { + + Log log = LogFactory.getLog(BaseMapperPlus.class); + + /** + * 获取当前实例对象关联的泛型类型 V 的 Class 对象 + * + * @return 返回当前实例对象关联的泛型类型 V 的 Class 对象 + */ + default Class currentVoClass() { + return (Class) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[1]; + } + + /** + * 获取当前实例对象关联的泛型类型 T 的 Class 对象 + * + * @return 返回当前实例对象关联的泛型类型 T 的 Class 对象 + */ + default Class currentModelClass() { + return (Class) GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseMapperPlus.class)[0]; + } + + /** + * 使用默认的查询条件查询并返回结果列表 + * + * @return 返回查询结果的列表 + */ + default List selectList() { + return this.selectList(new QueryWrapper<>()); + } + + /** + * 批量插入实体对象集合 + * + * @param entityList 实体对象集合 + * @return 插入操作是否成功的布尔值 + */ + default boolean insertBatch(Collection entityList) { + return Db.saveBatch(entityList); + } + + /** + * 批量根据ID更新实体对象集合 + * + * @param entityList 实体对象集合 + * @return 更新操作是否成功的布尔值 + */ + default boolean updateBatchById(Collection entityList) { + return Db.updateBatchById(entityList); + } + + /** + * 批量插入或更新实体对象集合 + * + * @param entityList 实体对象集合 + * @return 插入或更新操作是否成功的布尔值 + */ + default boolean insertOrUpdateBatch(Collection entityList) { + return Db.saveOrUpdateBatch(entityList); + } + + /** + * 批量插入实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 插入操作是否成功的布尔值 + */ + default boolean insertBatch(Collection entityList, int batchSize) { + return Db.saveBatch(entityList, batchSize); + } + + /** + * 批量根据ID更新实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 更新操作是否成功的布尔值 + */ + default boolean updateBatchById(Collection entityList, int batchSize) { + return Db.updateBatchById(entityList, batchSize); + } + + /** + * 批量插入或更新实体对象集合并指定批处理大小 + * + * @param entityList 实体对象集合 + * @param batchSize 批处理大小 + * @return 插入或更新操作是否成功的布尔值 + */ + default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { + return Db.saveOrUpdateBatch(entityList, batchSize); + } + + /** + * 根据ID查询单个VO对象 + * + * @param id 主键ID + * @return 查询到的单个VO对象 + */ + default V selectVoById(Serializable id) { + return selectVoById(id, this.currentVoClass()); + } + + /** + * 根据ID查询单个VO对象并将其转换为指定的VO类 + * + * @param id 主键ID + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的单个VO对象,经过转换为指定的VO类后返回 + */ + default C selectVoById(Serializable id, Class voClass) { + T obj = this.selectById(id); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + /** + * 根据ID集合批量查询VO对象列表 + * + * @param idList 主键ID集合 + * @return 查询到的VO对象列表 + */ + default List selectVoByIds(Collection idList) { + return selectVoByIds(idList, this.currentVoClass()); + } + + /** + * 根据ID集合批量查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param idList 主键ID集合 + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoByIds(Collection idList, Class voClass) { + List list = this.selectByIds(idList); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据查询条件Map查询VO对象列表 + * + * @param map 查询条件Map + * @return 查询到的VO对象列表 + */ + default List selectVoByMap(Map map) { + return selectVoByMap(map, this.currentVoClass()); + } + + /** + * 根据查询条件Map查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param map 查询条件Map + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoByMap(Map map, Class voClass) { + List list = this.selectByMap(map); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据条件查询单个VO对象 + * + * @param wrapper 查询条件Wrapper + * @return 查询到的单个VO对象 + */ + default V selectVoOne(Wrapper wrapper) { + return selectVoOne(wrapper, this.currentVoClass()); + } + + /** + * 根据条件查询单个VO对象,并根据需要决定是否抛出异常 + * + * @param wrapper 查询条件Wrapper + * @param throwEx 是否抛出异常的标志 + * @return 查询到的单个VO对象 + */ + default V selectVoOne(Wrapper wrapper, boolean throwEx) { + return selectVoOne(wrapper, this.currentVoClass(), throwEx); + } + + /** + * 根据条件查询单个VO对象,并指定返回的VO对象的类型 + * + * @param wrapper 查询条件Wrapper + * @param voClass 返回的VO对象的Class对象 + * @param 返回的VO对象的类型 + * @return 查询到的单个VO对象,经过类型转换为指定的VO类后返回 + */ + default C selectVoOne(Wrapper wrapper, Class voClass) { + return selectVoOne(wrapper, voClass, true); + } + + /** + * 根据条件查询单个实体对象,并将其转换为指定的VO对象 + * + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param throwEx 是否抛出异常的标志 + * @param VO类的类型 + * @return 查询到的单个VO对象,经过转换为指定的VO类后返回 + */ + default C selectVoOne(Wrapper wrapper, Class voClass, boolean throwEx) { + T obj = this.selectOne(wrapper, throwEx); + if (ObjectUtil.isNull(obj)) { + return null; + } + return MapstructUtils.convert(obj, voClass); + } + + /** + * 查询所有VO对象列表 + * + * @return 查询到的VO对象列表 + */ + default List selectVoList() { + return selectVoList(new QueryWrapper<>(), this.currentVoClass()); + } + + /** + * 根据条件查询VO对象列表 + * + * @param wrapper 查询条件Wrapper + * @return 查询到的VO对象列表 + */ + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + + /** + * 根据条件查询实体对象列表,并将其转换为指定的VO对象列表 + * + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @return 查询到的VO对象列表,经过转换为指定的VO类后返回 + */ + default List selectVoList(Wrapper wrapper, Class voClass) { + List list = this.selectList(wrapper); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return MapstructUtils.convert(list, voClass); + } + + /** + * 根据条件分页查询VO对象列表 + * + * @param page 分页信息 + * @param wrapper 查询条件Wrapper + * @return 查询到的VO对象分页列表 + */ + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + /** + * 根据条件分页查询实体对象列表,并将其转换为指定的VO对象分页列表 + * + * @param page 分页信息 + * @param wrapper 查询条件Wrapper + * @param voClass 要转换的VO类的Class对象 + * @param VO类的类型 + * @param

VO对象分页列表的类型 + * @return 查询到的VO对象分页列表,经过转换为指定的VO类后返回 + */ + default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { + // 根据条件分页查询实体对象列表 + List list = this.selectList(page, wrapper); + // 创建一个新的VO对象分页列表,并设置分页信息 + IPage voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal()); + if (CollUtil.isEmpty(list)) { + return (P) voPage; + } + voPage.setRecords(MapstructUtils.convert(list, voClass)); + return (P) voPage; + } + + /** + * 根据条件查询符合条件的对象,并将其转换为指定类型的对象列表 + * + * @param wrapper 查询条件Wrapper + * @param mapper 转换函数,用于将查询到的对象转换为指定类型的对象 + * @param 要转换的对象的类型 + * @return 查询到的符合条件的对象列表,经过转换为指定类型的对象后返回 + */ + default List selectObjs(Wrapper wrapper, Function mapper) { + return StreamUtils.toList(this.selectObjs(wrapper), mapper); + } + @Select("SELECT 't_depot' AS table_name, id FROM t_depot WHERE name = #{depotName} " + + "UNION ALL " + + "SELECT 't_freight' AS table_name, id FROM t_freight WHERE name = #{freightName} " + + "UNION ALL " + + "SELECT 't_shelves' AS table_name, id FROM t_shelves WHERE name = #{shelvesName}") + Map getIdsByNames(String depotName, String freightName, String shelvesName); + + + @Select("select id from t_shelves where code = #{shelvesName} AND depot_id = #{depotId}") + Long getShelvesIdByName(String shelvesName,Long depotId); + + @Select("select id from t_depot where name = #{depotName} AND user_id= #{userId}") + Long getDepotIdByName(String depotName, Long userId); + + @Select("select user_id from sys_user where phonenumber = #{phoneNumber}") + Long selectUserIdByNameAndPassWord(String phoneNumber); + + @Insert("insert into sys_user_role(user_id, role_id) values(#{userId},#{roleId})") + void insertUserRole(Long userId, Long roleId); +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java new file mode 100644 index 0000000..370f479 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java @@ -0,0 +1,91 @@ +package org.dromara.common.mybatis.core.page; + +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.metadata.IPage; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 表格分页数据对象 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class TableDataInfo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 总记录数 + */ + private long total; + + /** + * 列表数据 + */ + private List rows; + + /** + * 消息状态码 + */ + private int code; + + /** + * 消息内容 + */ + private String msg; + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, long total) { + this.rows = list; + this.total = total; + this.code = HttpStatus.HTTP_OK; + this.msg = "查询成功"; + } + + /** + * 根据分页对象构建表格分页数据对象 + */ + public static TableDataInfo build(IPage page) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(page.getRecords()); + rspData.setTotal(page.getTotal()); + return rspData; + } + + /** + * 根据数据列表构建表格分页数据对象 + */ + public static TableDataInfo build(List list) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(list.size()); + return rspData; + } + + /** + * 构建表格分页数据对象 + */ + public static TableDataInfo build() { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + return rspData; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java new file mode 100644 index 0000000..5084424 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java @@ -0,0 +1,58 @@ +package org.dromara.common.mybatis.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.dromara.common.core.utils.StringUtils; + +/** + * 数据库类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DataBaseType { + + /** + * MySQL + */ + MY_SQL("MySQL"), + + /** + * Oracle + */ + ORACLE("Oracle"), + + /** + * PostgreSQL + */ + POSTGRE_SQL("PostgreSQL"), + + /** + * SQL Server + */ + SQL_SERVER("Microsoft SQL Server"); + + /** + * 数据库类型 + */ + private final String type; + + /** + * 根据数据库产品名称查找对应的数据库类型 + * + * @param databaseProductName 数据库产品名称 + * @return 对应的数据库类型枚举值,如果未找到则返回 null + */ + public static DataBaseType find(String databaseProductName) { + if (StringUtils.isBlank(databaseProductName)) { + return null; + } + for (DataBaseType type : values()) { + if (type.getType().equals(databaseProductName)) { + return type; + } + } + return null; + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java new file mode 100644 index 0000000..fec2579 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java @@ -0,0 +1,102 @@ +package org.dromara.common.mybatis.handler; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.reflection.MetaObject; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.satoken.utils.LoginHelper; + +import java.util.Date; + +/** + * MP注入处理器 + * + * @author Lion Li + * @date 2021/4/25 + */ +@Slf4j +public class InjectionMetaObjectHandler implements MetaObjectHandler { + + /** + * 插入填充方法,用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息 + * + * @param metaObject 元对象,用于获取原始对象并进行填充 + */ + @Override + public void insertFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { + // 获取当前时间作为创建时间和更新时间,如果创建时间不为空,则使用创建时间,否则使用当前时间 + Date current = ObjectUtils.notNull(baseEntity.getCreateTime(), new Date()); + baseEntity.setCreateTime(current); + baseEntity.setUpdateTime(current); + + // 如果创建人为空,则填充当前登录用户的信息 + if (ObjectUtil.isNull(baseEntity.getCreateBy())) { + LoginUser loginUser = getLoginUser(); + if (ObjectUtil.isNotNull(loginUser)) { + Long userId = loginUser.getUserId(); + // 填充创建人、更新人和创建部门信息 + baseEntity.setCreateBy(userId); + baseEntity.setUpdateBy(userId); + baseEntity.setCreateDept(ObjectUtils.notNull(baseEntity.getCreateDept(), loginUser.getDeptId())); + } + } + } else { + Date date = new Date(); + this.strictInsertFill(metaObject, "createTime", Date.class, date); + this.strictInsertFill(metaObject, "updateTime", Date.class, date); + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + + /** + * 更新填充方法,用于在更新数据时自动填充实体对象中的更新时间和更新人信息 + * + * @param metaObject 元对象,用于获取原始对象并进行填充 + */ + @Override + public void updateFill(MetaObject metaObject) { + try { + if (ObjectUtil.isNotNull(metaObject) && metaObject.getOriginalObject() instanceof BaseEntity baseEntity) { + // 获取当前时间作为更新时间,无论原始对象中的更新时间是否为空都填充 + Date current = new Date(); + baseEntity.setUpdateTime(current); + + // 获取当前登录用户的ID,并填充更新人信息 + Long userId = LoginHelper.getUserId(); + if (ObjectUtil.isNotNull(userId)) { + baseEntity.setUpdateBy(userId); + } + } else { + this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); + } + } catch (Exception e) { + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + } + } + + /** + * 获取当前登录用户信息 + * + * @return 当前登录用户的信息,如果用户未登录则返回 null + */ + private LoginUser getLoginUser() { + LoginUser loginUser; + try { + loginUser = LoginHelper.getLoginUser(); + } catch (Exception e) { + log.warn("自动注入警告 => 用户未登录"); + return null; + } + return loginUser; + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java new file mode 100644 index 0000000..518d52d --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java @@ -0,0 +1,46 @@ +package org.dromara.common.mybatis.handler; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.mybatis.spring.MyBatisSystemException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * Mybatis异常处理器 + * + * @author Lion Li + */ +@Slf4j +@RestControllerAdvice +public class MybatisExceptionHandler { + + /** + * 主键或UNIQUE索引,数据重复异常 + */ + @ExceptionHandler(DuplicateKeyException.class) + public R handleDuplicateKeyException(DuplicateKeyException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("请求地址'{}',数据库中已存在记录'{}'", requestURI, e.getMessage()); + return R.fail("数据库中已存在该记录,请联系管理员确认"); + } + + /** + * Mybatis系统异常 通用处理 + */ + @ExceptionHandler(MyBatisSystemException.class) + public R handleCannotFindDataSourceException(MyBatisSystemException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + String message = e.getMessage(); + if (StringUtils.contains("CannotFindDataSourceException", message)) { + log.error("请求地址'{}', 未找到数据源", requestURI); + return R.fail("未找到数据源,请联系管理员确认"); + } + log.error("请求地址'{}', Mybatis系统异常", requestURI, e); + return R.fail(message); + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java new file mode 100644 index 0000000..a354707 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java @@ -0,0 +1,332 @@ +package org.dromara.common.mybatis.handler; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import org.apache.ibatis.io.Resources; +import org.dromara.common.core.domain.dto.RoleDTO; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.common.mybatis.enums.DataScopeType; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.expression.BeanFactoryResolver; +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.expression.*; +import org.springframework.expression.common.TemplateParserContext; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.ClassUtils; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +/** + * 数据权限过滤 + * + * @author Lion Li + * @version 3.5.0 + */ +@Slf4j +public class PlusDataPermissionHandler { + + /** + * 类名称与注解的映射关系缓存(由于aop无法拦截mybatis接口类上的注解 只能通过启动预扫描的方式进行) + */ + private final Map dataPermissionCacheMap = new ConcurrentHashMap<>(); + + /** + * spel 解析器 + */ + private final ExpressionParser parser = new SpelExpressionParser(); + private final ParserContext parserContext = new TemplateParserContext(); + /** + * bean解析器 用于处理 spel 表达式中对 bean 的调用 + */ + private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory()); + + /** + * 构造方法,扫描指定包下的 Mapper 类并初始化缓存 + * + * @param mapperPackage Mapper 类所在的包路径 + */ + public PlusDataPermissionHandler(String mapperPackage) { + scanMapperClasses(mapperPackage); + } + + /** + * 获取数据过滤条件的 SQL 片段 + * + * @param where 原始的查询条件表达式 + * @param mappedStatementId Mapper 方法的 ID + * @param isSelect 是否为查询语句 + * @return 数据过滤条件的 SQL 片段 + */ + public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { + try { + // 获取数据权限配置 + DataPermission dataPermission = getDataPermission(mappedStatementId); + // 获取当前登录用户信息 + LoginUser currentUser = DataPermissionHelper.getVariable("user"); + if (ObjectUtil.isNull(currentUser)) { + currentUser = LoginHelper.getLoginUser(); + DataPermissionHelper.setVariable("user", currentUser); + } + // 如果是超级管理员或租户管理员,则不过滤数据 + if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { + return where; + } + // 构造数据过滤条件的 SQL 片段 + String dataFilterSql = buildDataFilter(dataPermission, isSelect); + if (StringUtils.isBlank(dataFilterSql)) { + return where; + } + Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql); + // 数据权限使用单独的括号 防止与其他条件冲突 + ParenthesedExpressionList parenthesis = new ParenthesedExpressionList<>(expression); + if (ObjectUtil.isNotNull(where)) { + return new AndExpression(where, parenthesis); + } else { + return parenthesis; + } + } catch (JSQLParserException e) { + throw new ServiceException("数据权限解析异常 => " + e.getMessage()); + } finally { + DataPermissionHelper.removePermission(); + } + } + + /** + * 构建数据过滤条件的 SQL 语句 + * + * @param dataPermission 数据权限注解 + * @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式 + * @return 构建的数据过滤条件的 SQL 语句 + * @throws ServiceException 如果角色的数据范围异常或者 key 与 value 的长度不匹配,则抛出 ServiceException 异常 + */ + private String buildDataFilter(DataPermission dataPermission, boolean isSelect) { + // 更新或删除需满足所有条件 + String joinStr = isSelect ? " OR " : " AND "; + if (StringUtils.isNotBlank(dataPermission.joinStr())) { + joinStr = " " + dataPermission.joinStr() + " "; + } + LoginUser user = DataPermissionHelper.getVariable("user"); + Object defaultValue = "-1"; + NullSafeStandardEvaluationContext context = new NullSafeStandardEvaluationContext(defaultValue); + context.addPropertyAccessor(new NullSafePropertyAccessor(context.getPropertyAccessors().get(0), defaultValue)); + context.setBeanResolver(beanResolver); + DataPermissionHelper.getContext().forEach(context::setVariable); + Set conditions = new HashSet<>(); + // 优先设置变量 + List keys = new ArrayList<>(); + Map ignoreMap = new HashMap<>(); + for (DataColumn dataColumn : dataPermission.value()) { + if (dataColumn.key().length != dataColumn.value().length) { + throw new ServiceException("角色数据范围异常 => key与value长度不匹配"); + } + // 包含权限标识符 这直接跳过 + if (StringUtils.isNotBlank(dataColumn.permission()) && + CollUtil.contains(user.getMenuPermission(), dataColumn.permission()) + ) { + ignoreMap.put(dataColumn, Boolean.TRUE); + continue; + } + // 设置注解变量 key 为表达式变量 value 为变量值 + for (int i = 0; i < dataColumn.key().length; i++) { + context.setVariable(dataColumn.key()[i], dataColumn.value()[i]); + } + keys.addAll(Arrays.stream(dataColumn.key()).map(key -> "#" + key).toList()); + } + + for (RoleDTO role : user.getRoles()) { + user.setRoleId(role.getRoleId()); + // 获取角色权限泛型 + DataScopeType type = DataScopeType.findCode(role.getDataScope()); + if (ObjectUtil.isNull(type)) { + throw new ServiceException("角色数据范围异常 => " + role.getDataScope()); + } + // 全部数据权限直接返回 + if (type == DataScopeType.ALL) { + return StringUtils.EMPTY; + } + boolean isSuccess = false; + for (DataColumn dataColumn : dataPermission.value()) { + // 包含权限标识符 这直接跳过 + if (ignoreMap.containsKey(dataColumn)) { + // 修复多角色与权限标识符共用问题 https://gitee.com/dromara/RuoYi-Vue-Plus/issues/IB4CS4 + conditions.add(joinStr + " 1 = 1 "); + isSuccess = true; + continue; + } + // 不包含 key 变量 则不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), keys.toArray(String[]::new))) { + continue; + } + // 当前注解不满足模板 不处理 + if (!StringUtils.containsAny(type.getSqlTemplate(), dataColumn.key())) { + continue; + } + // 忽略数据权限 防止spel表达式内有其他sql查询导致死循环调用 + String sql = DataPermissionHelper.ignore(() -> + parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class) + ); + // 解析sql模板并填充 + conditions.add(joinStr + sql); + isSuccess = true; + } + // 未处理成功则填充兜底方案 + if (!isSuccess && StringUtils.isNotBlank(type.getElseSql())) { + conditions.add(joinStr + type.getElseSql()); + } + } + + if (CollUtil.isNotEmpty(conditions)) { + String sql = StreamUtils.join(conditions, Function.identity(), ""); + return sql.substring(joinStr.length()); + } + return StringUtils.EMPTY; + } + + /** + * 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类 + * + * @param mapperPackage Mapper 类所在的包路径 + */ + private void scanMapperClasses(String mapperPackage) { + // 创建资源解析器和元数据读取工厂 + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory(); + // 将 Mapper 包路径按分隔符拆分为数组 + String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX; + try { + for (String packagePattern : packagePatternArray) { + // 将包路径转换为资源路径 + String path = ClassUtils.convertClassNameToResourcePath(packagePattern); + // 获取指定路径下的所有 .class 文件资源 + Resource[] resources = resolver.getResources(classpath + path + "/*.class"); + for (Resource resource : resources) { + // 获取资源的类元数据 + ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata(); + // 获取资源对应的类对象 + Class clazz = Resources.classForName(classMetadata.getClassName()); + // 查找类中的特定注解 + if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) { + DataPermission dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class); + dataPermissionCacheMap.put(clazz.getName(), dataPermission); + } + } + } + } catch (Exception e) { + log.error("初始化数据安全缓存时出错:{}", e.getMessage()); + } + } + + /** + * 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象 + * + * @param mapperId 映射语句 ID + * @return DataPermission 注解对象,如果不存在则返回 null + */ + public DataPermission getDataPermission(String mapperId) { + // 检查上下文中是否包含映射语句 ID 对应的 DataPermission 注解对象 + if (DataPermissionHelper.getPermission() != null) { + return DataPermissionHelper.getPermission(); + } + // 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找 + String clazzName = mapperId.substring(0, mapperId.lastIndexOf(".")); + if (dataPermissionCacheMap.containsKey(clazzName)) { + return dataPermissionCacheMap.get(clazzName); + } + return null; + } + + /** + * 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象 + * + * @param mapperId 映射语句 ID + * @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true + */ + public boolean invalid(String mapperId) { + return getDataPermission(mapperId) == null; + } + + /** + * 对所有null变量找不到的变量返回默认值 + */ + @AllArgsConstructor + private static class NullSafeStandardEvaluationContext extends StandardEvaluationContext { + + private final Object defaultValue; + + @Override + public Object lookupVariable(String name) { + Object obj = super.lookupVariable(name); + // 如果读取到的值是 null,则返回默认值 + if (obj == null) { + return defaultValue; + } + return obj; + } + + } + + /** + * 对所有null变量找不到的变量返回默认值 委托模式 将不需要处理的方法委托给原处理器 + */ + @AllArgsConstructor + private static class NullSafePropertyAccessor implements PropertyAccessor { + + private final PropertyAccessor delegate; + private final Object defaultValue; + + @Override + public Class[] getSpecificTargetClasses() { + return delegate.getSpecificTargetClasses(); + } + + @Override + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + return delegate.canRead(context, target, name); + } + + @Override + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + TypedValue value = delegate.read(context, target, name); + // 如果读取到的值是 null,则返回默认值 + if (value.getValue() == null) { + return new TypedValue(defaultValue); + } + return value; + } + + @Override + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + return delegate.canWrite(context, target, name); + } + + @Override + public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException { + delegate.write(context, target, name, newValue); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java new file mode 100644 index 0000000..60ca20b --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java @@ -0,0 +1,27 @@ +package org.dromara.common.mybatis.handler; + +import cn.hutool.core.convert.Convert; +import com.baomidou.mybatisplus.core.handlers.PostInitTableInfoHandler; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import org.apache.ibatis.session.Configuration; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.reflect.ReflectUtils; + +/** + * 修改表信息初始化方式 + * 目前用于全局修改是否使用逻辑删除 + * + * @author Lion Li + */ +public class PlusPostInitTableInfoHandler implements PostInitTableInfoHandler { + + @Override + public void postTableInfo(TableInfo tableInfo, Configuration configuration) { + String flag = SpringUtils.getProperty("mybatis-plus.enableLogicDelete", "true"); + // 只有关闭时 统一设置false 为true时mp自动判断不处理 + if (!Convert.toBool(flag)) { + ReflectUtils.setFieldValue(tableInfo, "withLogicDelete", false); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java new file mode 100644 index 0000000..cd43c68 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java @@ -0,0 +1,81 @@ +package org.dromara.common.mybatis.helper; + +import cn.hutool.core.convert.Convert; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.mybatis.enums.DataBaseType; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * 数据库助手 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DataBaseHelper { + + private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); + + /** + * 获取当前数据库类型 + */ + public static DataBaseType getDataBaseType() { + DataSource dataSource = DS.determineDataSource(); + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + return DataBaseType.find(databaseProductName); + } catch (SQLException e) { + throw new ServiceException(e.getMessage()); + } + } + + public static boolean isMySql() { + return DataBaseType.MY_SQL == getDataBaseType(); + } + + public static boolean isOracle() { + return DataBaseType.ORACLE == getDataBaseType(); + } + + public static boolean isPostgerSql() { + return DataBaseType.POSTGRE_SQL == getDataBaseType(); + } + + public static boolean isSqlServer() { + return DataBaseType.SQL_SERVER == getDataBaseType(); + } + + public static String findInSet(Object var1, String var2) { + DataBaseType dataBasyType = getDataBaseType(); + String var = Convert.toStr(var1); + if (dataBasyType == DataBaseType.SQL_SERVER) { + // charindex(',100,' , ',0,100,101,') <> 0 + return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2); + } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { + // (select strpos(',0,100,101,' , ',100,')) <> 0 + return "(select strpos(','||%s||',' , ',%s,')) <> 0".formatted(var2, var); + } else if (dataBasyType == DataBaseType.ORACLE) { + // instr(',0,100,101,' , ',100,') <> 0 + return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var); + } + // find_in_set(100 , '0,100,101') + return "find_in_set('%s' , %s) <> 0".formatted(var, var2); + } + + /** + * 获取当前加载的数据库名 + */ + public static List getDataSourceNameList() { + return new ArrayList<>(DS.getDataSources().keySet()); + } +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java new file mode 100644 index 0000000..f03d74e --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java @@ -0,0 +1,176 @@ +package org.dromara.common.mybatis.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.utils.reflect.ReflectUtils; +import org.dromara.common.mybatis.annotation.DataPermission; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import java.util.function.Supplier; + +/** + * 数据权限助手 + * + * @author Lion Li + * @version 3.5.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings("unchecked cast") +public class DataPermissionHelper { + + private static final String DATA_PERMISSION_KEY = "data:permission"; + + private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new); + + private static final ThreadLocal PERMISSION_CACHE = new ThreadLocal<>(); + + /** + * 获取当前执行mapper权限注解 + * + * @return 返回当前执行mapper权限注解 + */ + public static DataPermission getPermission() { + return PERMISSION_CACHE.get(); + } + + /** + * 设置当前执行mapper权限注解 + * + * @param dataPermission 数据权限注解 + */ + public static void setPermission(DataPermission dataPermission) { + PERMISSION_CACHE.set(dataPermission); + } + + /** + * 删除当前执行mapper权限注解 + */ + public static void removePermission() { + PERMISSION_CACHE.remove(); + } + + /** + * 从上下文中获取指定键的变量值,并将其转换为指定的类型 + * + * @param key 变量的键 + * @param 变量值的类型 + * @return 指定键的变量值,如果不存在则返回 null + */ + public static T getVariable(String key) { + Map context = getContext(); + return (T) context.get(key); + } + + /** + * 向上下文中设置指定键的变量值 + * + * @param key 要设置的变量的键 + * @param value 要设置的变量值 + */ + public static void setVariable(String key, Object value) { + Map context = getContext(); + context.put(key, value); + } + + /** + * 获取数据权限上下文 + * + * @return 存储在SaStorage中的Map对象,用于存储数据权限相关的上下文信息 + * @throws NullPointerException 如果数据权限上下文类型异常,则抛出NullPointerException + */ + public static Map getContext() { + SaStorage saStorage = SaHolder.getStorage(); + Object attribute = saStorage.get(DATA_PERMISSION_KEY); + if (ObjectUtil.isNull(attribute)) { + saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); + attribute = saStorage.get(DATA_PERMISSION_KEY); + } + if (attribute instanceof Map map) { + return map; + } + throw new NullPointerException("data permission context type exception"); + } + + private static IgnoreStrategy getIgnoreStrategy() { + Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL")); + if (ignoreStrategyLocal instanceof ThreadLocal IGNORE_STRATEGY_LOCAL) { + if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) { + return ignoreStrategy; + } + } + return null; + } + + /** + * 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭) + */ + public static void enableIgnore() { + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNull(ignoreStrategy)) { + InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build()); + } else { + ignoreStrategy.setDataPermission(true); + } + Stack reentrantStack = REENTRANT_IGNORE.get(); + reentrantStack.push(reentrantStack.size() + 1); + } + + /** + * 关闭忽略数据权限 + */ + public static void disableIgnore() { + IgnoreStrategy ignoreStrategy = getIgnoreStrategy(); + if (ObjectUtil.isNotNull(ignoreStrategy)) { + boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName()) + && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack()) + && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) + && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine()) + && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); + Stack reentrantStack = REENTRANT_IGNORE.get(); + boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1; + if (noOtherIgnoreStrategy && empty) { + InterceptorIgnoreHelper.clearIgnoreStrategy(); + } else if (empty) { + ignoreStrategy.setDataPermission(false); + } + + } + } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static void ignore(Runnable handle) { + enableIgnore(); + try { + handle.run(); + } finally { + disableIgnore(); + } + } + + /** + * 在忽略数据权限中执行 + * + * @param handle 处理执行方法 + */ + public static T ignore(Supplier handle) { + enableIgnore(); + try { + return handle.get(); + } finally { + disableIgnore(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java new file mode 100644 index 0000000..85a4d0a --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java @@ -0,0 +1,181 @@ +package org.dromara.common.mybatis.interceptor; + +import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; +import com.baomidou.mybatisplus.core.toolkit.PluginUtils; +import com.baomidou.mybatisplus.extension.plugins.handler.MultiDataPermissionHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.BaseMultiTableInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.update.Update; +import org.apache.ibatis.executor.Executor; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.dromara.common.mybatis.handler.PlusDataPermissionHandler; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.List; + +/** + * 数据权限拦截器 + * + * @author Lion Li + * @version 3.5.0 + */ +@Slf4j +public class PlusDataPermissionInterceptor extends BaseMultiTableInnerInterceptor implements InnerInterceptor { + + private final PlusDataPermissionHandler dataPermissionHandler; + + /** + * 构造函数,初始化 PlusDataPermissionHandler 实例 + * + * @param mapperPackage 扫描的映射器包 + */ + public PlusDataPermissionInterceptor(String mapperPackage) { + this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage); + } + + /** + * 在执行查询之前,检查并处理数据权限相关逻辑 + * + * @param executor MyBatis 执行器对象 + * @param ms 映射语句对象 + * @param parameter 方法参数 + * @param rowBounds 分页对象 + * @param resultHandler 结果处理器 + * @param boundSql 绑定的 SQL 对象 + * @throws SQLException 如果发生 SQL 异常 + */ + @Override + public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { + // 检查是否需要忽略数据权限处理 + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + // 检查是否缺少有效的数据权限注解 + if (dataPermissionHandler.invalid(ms.getId())) { + return; + } + // 解析 sql 分配对应方法 + PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); + mpBs.sql(parserSingle(mpBs.sql(), ms.getId())); + } + + /** + * 在准备 SQL 语句之前,检查并处理更新和删除操作的数据权限相关逻辑 + * + * @param sh MyBatis StatementHandler 对象 + * @param connection 数据库连接对象 + * @param transactionTimeout 事务超时时间 + */ + @Override + public void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) { + PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh); + MappedStatement ms = mpSh.mappedStatement(); + // 获取 SQL 命令类型(增、删、改、查) + SqlCommandType sct = ms.getSqlCommandType(); + + // 只处理更新和删除操作的 SQL 语句 + if (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE) { + if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { + return; + } + // 检查是否缺少有效的数据权限注解 + if (dataPermissionHandler.invalid(ms.getId())) { + return; + } + PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); + mpBs.sql(parserMulti(mpBs.sql(), ms.getId())); + } + } + + /** + * 处理 SELECT 查询语句中的 WHERE 条件 + * + * @param select SELECT 查询对象 + * @param index 查询语句的索引 + * @param sql 查询语句 + * @param obj WHERE 条件参数 + */ + @Override + protected void processSelect(Select select, int index, String sql, Object obj) { + if (select instanceof PlainSelect) { + this.setWhere((PlainSelect) select, (String) obj); + } else if (select instanceof SetOperationList setOperationList) { + List + SELECT * FROM test_demo ${ew.customSqlSegment} + + + diff --git a/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml b/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml new file mode 100644 index 0000000..d7975ec --- /dev/null +++ b/ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java new file mode 100644 index 0000000..8c0f352 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java @@ -0,0 +1,105 @@ +package org.dromara.generator.config; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.anyline.data.datasource.DataSourceMonitor; +import org.anyline.data.runtime.DataRuntime; +import org.anyline.util.ConfigTable; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DataSourceUtils; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.util.HashMap; +import java.util.Map; + +/** + * anyline 适配 动态数据源改造 + * + * @author Lion Li + */ +@Slf4j +@Component +public class MyBatisDataSourceMonitor implements DataSourceMonitor { + + public MyBatisDataSourceMonitor() { + // 调整执行模式为自定义 + ConfigTable.KEEP_ADAPTER = 2; + // 禁用缓存 + ConfigTable.METADATA_CACHE_SCOPE = 0; + } + + private final Map features = new HashMap<>(); + + /** + * 数据源特征 用来定准 adapter 包含数据库或JDBC协议关键字
+ * 一般会通过 产品名_url 合成 如果返回null 上层方法会通过driver_产品名_url合成 + * + * @param datasource 数据源 + * @return String 返回null由上层自动提取 + */ + @Override + public String feature(DataRuntime runtime, Object datasource) { + String feature = null; + if (datasource instanceof JdbcTemplate jdbc) { + DataSource ds = jdbc.getDataSource(); + if (ds instanceof DynamicRoutingDataSource) { + String key = DynamicDataSourceContextHolder.peek(); + feature = features.get(key); + if (null == feature) { + Connection con = null; + try { + con = DataSourceUtils.getConnection(ds); + DatabaseMetaData meta = con.getMetaData(); + String url = meta.getURL(); + feature = meta.getDatabaseProductName().toLowerCase().replace(" ", "") + "_" + url; + features.put(key, feature); + } catch (Exception e) { + log.error(e.getMessage(), e); + } finally { + if (null != con && !DataSourceUtils.isConnectionTransactional(con, ds)) { + DataSourceUtils.releaseConnection(con, ds); + } + } + } + } + } + return feature; + } + + /** + * 数据源唯一标识 如果不实现则默认feature + * @param datasource 数据源 + * @return String 返回null由上层自动提取 + */ + @Override + public String key(DataRuntime runtime, Object datasource) { + if(datasource instanceof JdbcTemplate jdbc){ + DataSource ds = jdbc.getDataSource(); + if(ds instanceof DynamicRoutingDataSource){ + return DynamicDataSourceContextHolder.peek(); + } + } + return runtime.getKey(); + } + + /** + * ConfigTable.KEEP_ADAPTER=2 : 根据当前接口判断是否保持同一个数据源绑定同一个adapter
+ * DynamicRoutingDataSource类型的返回false,因为同一个DynamicRoutingDataSource可能对应多类数据库, 如果项目中只有一种数据库 应该直接返回true + * + * @param datasource 数据源 + * @return boolean + */ + @Override + public boolean keepAdapter(DataRuntime runtime, Object datasource) { + if (datasource instanceof JdbcTemplate jdbc) { + DataSource ds = jdbc.getDataSource(); + return !(ds instanceof DynamicRoutingDataSource); + } + return true; + } + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java new file mode 100644 index 0000000..b9888fb --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java @@ -0,0 +1,186 @@ +package org.dromara.generator.constant; + +/** + * 代码生成通用常量 + * + * @author ruoyi + */ +public interface GenConstants { + /** + * 单表(增删改查) + */ + String TPL_CRUD = "crud"; + + /** + * 树表(增删改查) + */ + String TPL_TREE = "tree"; + + /** + * 树编码字段 + */ + String TREE_CODE = "treeCode"; + + /** + * 树父编码字段 + */ + String TREE_PARENT_CODE = "treeParentCode"; + + /** + * 树名称字段 + */ + String TREE_NAME = "treeName"; + + /** + * 上级菜单ID字段 + */ + String PARENT_MENU_ID = "parentMenuId"; + + /** + * 上级菜单名称字段 + */ + String PARENT_MENU_NAME = "parentMenuName"; + + /** + * 数据库字符串类型 + */ + String[] COLUMNTYPE_STR = {"char", "varchar", "enum", "set", "nchar", "nvarchar", "varchar2", "nvarchar2"}; + + /** + * 数据库文本类型 + */ + String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext", "binary", "varbinary", "blob", + "ntext", "image", "bytea"}; + + /** + * 数据库时间类型 + */ + String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval", + "smalldatetime", "datetime2", "datetimeoffset", "timestamptz"}; + + /** + * 数据库数字类型 + */ + String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "int2", "int4", "int8", "number", "integer", + "bit", "bigint", "float", "float4", "float8", "double", "decimal", "numeric", "real", "double precision", + "smallserial", "serial", "bigserial", "money", "smallmoney"}; + + /** + * BO对象 不需要添加字段 + */ + String[] COLUMNNAME_NOT_ADD = {"create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "version", "tenant_id"}; + + /** + * BO对象 不需要编辑字段 + */ + String[] COLUMNNAME_NOT_EDIT = {"create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "version", "tenant_id"}; + + /** + * VO对象 不需要返回字段 + */ + String[] COLUMNNAME_NOT_LIST = {"create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "version", "tenant_id"}; + + /** + * BO对象 不需要查询字段 + */ + String[] COLUMNNAME_NOT_QUERY = {"id", "create_dept", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark", "version", "tenant_id"}; + + /** + * Entity基类字段 + */ + String[] BASE_ENTITY = {"createDept", "createBy", "createTime", "updateBy", "updateTime", "tenantId"}; + + /** + * 文本框 + */ + String HTML_INPUT = "input"; + + /** + * 文本域 + */ + String HTML_TEXTAREA = "textarea"; + + /** + * 下拉框 + */ + String HTML_SELECT = "select"; + + /** + * 单选框 + */ + String HTML_RADIO = "radio"; + + /** + * 复选框 + */ + String HTML_CHECKBOX = "checkbox"; + + /** + * 日期控件 + */ + String HTML_DATETIME = "datetime"; + + /** + * 图片上传控件 + */ + String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** + * 文件上传控件 + */ + String HTML_FILE_UPLOAD = "fileUpload"; + + /** + * 富文本控件 + */ + String HTML_EDITOR = "editor"; + + /** + * 字符串类型 + */ + String TYPE_STRING = "String"; + + /** + * 整型 + */ + String TYPE_INTEGER = "Integer"; + + /** + * 长整型 + */ + String TYPE_LONG = "Long"; + + /** + * 浮点型 + */ + String TYPE_DOUBLE = "Double"; + + /** + * 高精度计算类型 + */ + String TYPE_BIGDECIMAL = "BigDecimal"; + + /** + * 时间类型 + */ + String TYPE_DATE = "Date"; + + /** + * 模糊查询 + */ + String QUERY_LIKE = "LIKE"; + + /** + * 相等查询 + */ + String QUERY_EQ = "EQ"; + + /** + * 需要 + */ + String REQUIRE = "1"; +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java new file mode 100644 index 0000000..e3d4c08 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java @@ -0,0 +1,217 @@ +package org.dromara.generator.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.generator.domain.GenTable; +import org.dromara.generator.domain.GenTableColumn; +import org.dromara.generator.service.IGenTableService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 代码生成 操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/tool/gen") +public class GenController extends BaseController { + + private final IGenTableService genTableService; + + /** + * 查询代码生成列表 + */ + @SaCheckPermission("tool:gen:list") + @GetMapping("/list") + public TableDataInfo genList(GenTable genTable, PageQuery pageQuery) { + return genTableService.selectPageGenTableList(genTable, pageQuery); + } + + /** + * 修改代码生成业务 + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:query") + @GetMapping(value = "/{tableId}") + public R> getInfo(@PathVariable Long tableId) { + GenTable table = genTableService.selectGenTableById(tableId); + List tables = genTableService.selectGenTableAll(); + List list = genTableService.selectGenTableColumnListByTableId(tableId); + Map map = new HashMap<>(3); + map.put("info", table); + map.put("rows", list); + map.put("tables", tables); + return R.ok(map); + } + + /** + * 查询数据库列表 + */ + @SaCheckPermission("tool:gen:list") + @GetMapping("/db/list") + public TableDataInfo dataList(GenTable genTable, PageQuery pageQuery) { + return genTableService.selectPageDbTableList(genTable, pageQuery); + } + + /** + * 查询数据表字段列表 + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:list") + @GetMapping(value = "/column/{tableId}") + public TableDataInfo columnList(@PathVariable("tableId") Long tableId) { + TableDataInfo dataInfo = new TableDataInfo<>(); + List list = genTableService.selectGenTableColumnListByTableId(tableId); + dataInfo.setRows(list); + dataInfo.setTotal(list.size()); + return dataInfo; + } + + /** + * 导入表结构(保存) + * + * @param tables 表名串 + */ + @SaCheckPermission("tool:gen:import") + @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @PostMapping("/importTable") + public R importTableSave(String tables, String dataName) { + String[] tableNames = Convert.toStrArray(tables); + // 查询表信息 + List tableList = genTableService.selectDbTableListByNames(tableNames, dataName); + genTableService.importGenTable(tableList, dataName); + return R.ok(); + } + + /** + * 修改保存代码生成业务 + */ + @SaCheckPermission("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @PutMapping + public R editSave(@Validated @RequestBody GenTable genTable) { + genTableService.validateEdit(genTable); + genTableService.updateGenTable(genTable); + return R.ok(); + } + + /** + * 删除代码生成 + * + * @param tableIds 表ID串 + */ + @SaCheckPermission("tool:gen:remove") + @Log(title = "代码生成", businessType = BusinessType.DELETE) + @DeleteMapping("/{tableIds}") + public R remove(@PathVariable Long[] tableIds) { + genTableService.deleteGenTableByIds(tableIds); + return R.ok(); + } + + /** + * 预览代码 + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:preview") + @GetMapping("/preview/{tableId}") + public R> preview(@PathVariable("tableId") Long tableId) throws IOException { + Map dataMap = genTableService.previewCode(tableId); + return R.ok(dataMap); + } + + /** + * 生成代码(下载方式) + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/download/{tableId}") + public void download(HttpServletResponse response, @PathVariable("tableId") Long tableId) throws IOException { + byte[] data = genTableService.downloadCode(tableId); + genCode(response, data); + } + + /** + * 生成代码(自定义路径) + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/genCode/{tableId}") + public R genCode(@PathVariable("tableId") Long tableId) { + genTableService.generatorCode(tableId); + return R.ok(); + } + + /** + * 同步数据库 + * + * @param tableId 表ID + */ + @SaCheckPermission("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @GetMapping("/synchDb/{tableId}") + public R synchDb(@PathVariable("tableId") Long tableId) { + genTableService.synchDb(tableId); + return R.ok(); + } + + /** + * 批量生成代码 + * + * @param tableIdStr 表ID串 + */ + @SaCheckPermission("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/batchGenCode") + public void batchGenCode(HttpServletResponse response, String tableIdStr) throws IOException { + String[] tableIds = Convert.toStrArray(tableIdStr); + byte[] data = genTableService.downloadCode(tableIds); + genCode(response, data); + } + + /** + * 生成zip文件 + */ + private void genCode(HttpServletResponse response, byte[] data) throws IOException { + response.reset(); + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\""); + response.addHeader("Content-Length", "" + data.length); + response.setContentType("application/octet-stream; charset=UTF-8"); + IoUtil.write(response.getOutputStream(), false, data); + } + + /** + * 查询数据源名称列表 + */ + @SaCheckPermission("tool:gen:list") + @GetMapping(value = "/getDataNames") + public R getCurrentDataSourceNameList(){ + return R.ok(DataBaseHelper.getDataSourceNameList()); + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java new file mode 100644 index 0000000..6b2e429 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java @@ -0,0 +1,222 @@ +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 lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.ibatis.type.JdbcType; + +import jakarta.validation.constraints.NotBlank; + +/** + * 代码生成业务字段表 gen_table_column + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("gen_table_column") +public class GenTableColumn extends BaseEntity { + + /** + * 编号 + */ + @TableId(value = "column_id") + private Long columnId; + + /** + * 归属表编号 + */ + private Long tableId; + + /** + * 列名称 + */ + private String columnName; + + /** + * 列描述 + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String columnComment; + + /** + * 列类型 + */ + private String columnType; + + /** + * JAVA类型 + */ + private String javaType; + + /** + * JAVA字段名 + */ + @NotBlank(message = "Java属性不能为空") + private String javaField; + + /** + * 是否主键(1是) + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String isPk; + + /** + * 是否自增(1是) + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String isIncrement; + + /** + * 是否必填(1是) + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String isRequired; + + /** + * 是否为插入字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String isInsert; + + /** + * 是否编辑字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String isEdit; + + /** + * 是否列表字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String isList; + + /** + * 是否查询字段(1是) + */ + @TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR) + private String isQuery; + + /** + * 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) + */ + private String queryType; + + /** + * 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) + */ + private String htmlType; + + /** + * 字典类型 + */ + private String dictType; + + /** + * 排序 + */ + private Integer sort; + + public String getCapJavaField() { + return StringUtils.capitalize(javaField); + } + + public boolean isPk() { + return isPk(this.isPk); + } + + public boolean isPk(String isPk) { + return isPk != null && StringUtils.equals("1", isPk); + } + + public boolean isIncrement() { + return isIncrement(this.isIncrement); + } + + public boolean isIncrement(String isIncrement) { + return isIncrement != null && StringUtils.equals("1", isIncrement); + } + + public boolean isRequired() { + return isRequired(this.isRequired); + } + + public boolean isRequired(String isRequired) { + return isRequired != null && StringUtils.equals("1", isRequired); + } + + public boolean isInsert() { + return isInsert(this.isInsert); + } + + public boolean isInsert(String isInsert) { + return isInsert != null && StringUtils.equals("1", isInsert); + } + + public boolean isEdit() { + return isEdit(this.isEdit); + } + + public boolean isEdit(String isEdit) { + return isEdit != null && StringUtils.equals("1", isEdit); + } + + public boolean isList() { + return isList(this.isList); + } + + public boolean isList(String isList) { + return isList != null && StringUtils.equals("1", isList); + } + + public boolean isQuery() { + return isQuery(this.isQuery); + } + + public boolean isQuery(String isQuery) { + return isQuery != null && StringUtils.equals("1", isQuery); + } + + public boolean isSuperColumn() { + return isSuperColumn(this.javaField); + } + + public static boolean isSuperColumn(String javaField) { + return StringUtils.equalsAnyIgnoreCase(javaField, + // BaseEntity + "createBy", "createTime", "updateBy", "updateTime", + // TreeEntity + "parentName", "parentId"); + } + + public boolean isUsableColumn() { + return isUsableColumn(javaField); + } + + public static boolean isUsableColumn(String javaField) { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); + } + + public String readConverterExp() { + String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); + StringBuffer sb = new StringBuffer(); + if (StringUtils.isNotEmpty(remarks)) { + for (String value : remarks.split(" ")) { + if (StringUtils.isNotEmpty(value)) { + Object startStr = value.subSequence(0, 1); + String endStr = value.substring(1); + sb.append(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR); + } + } + return sb.deleteCharAt(sb.length() - 1).toString(); + } else { + return this.columnComment; + } + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java new file mode 100644 index 0000000..ed8ed20 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java @@ -0,0 +1,15 @@ +package org.dromara.generator.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.generator.domain.GenTableColumn; + +/** + * 业务字段 数据层 + * + * @author Lion Li + */ +@InterceptorIgnore(dataPermission = "true", tenantLine = "true") +public interface GenTableColumnMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java new file mode 100644 index 0000000..1798b4b --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java @@ -0,0 +1,51 @@ +package org.dromara.generator.mapper; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.generator.domain.GenTable; + +import java.util.List; + +/** + * 业务 数据层 + * + * @author Lion Li + */ +@InterceptorIgnore(dataPermission = "true", tenantLine = "true") +public interface GenTableMapper extends BaseMapperPlus { + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + List selectGenTableAll(); + + /** + * 查询表ID业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + GenTable selectGenTableById(Long id); + + /** + * 查询表名称业务信息 + * + * @param tableName 表名称 + * @return 业务信息 + */ + GenTable selectGenTableByName(String tableName); + + /** + * 查询指定数据源下的所有表名列表 + * + * @param dataName 数据源名称,用于选择不同的数据源 + * @return 当前数据库中的表名列表 + * + * @DS("") 使用默认数据源执行查询操作 + */ + @DS("") + List selectTableNameList(String dataName); +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java new file mode 100644 index 0000000..6b9e606 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java @@ -0,0 +1,582 @@ +package org.dromara.generator.service; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +import com.baomidou.mybatisplus.core.metadata.IPage; +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.anyline.metadata.Column; +import org.anyline.metadata.Table; +import org.anyline.proxy.ServiceProxy; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.generator.constant.GenConstants; +import org.dromara.generator.domain.GenTable; +import org.dromara.generator.domain.GenTableColumn; +import org.dromara.generator.mapper.GenTableColumnMapper; +import org.dromara.generator.mapper.GenTableMapper; +import org.dromara.generator.util.GenUtils; +import org.dromara.generator.util.VelocityInitializer; +import org.dromara.generator.util.VelocityUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 业务 服务层实现 + * + * @author Lion Li + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class GenTableServiceImpl implements IGenTableService { + + private final GenTableMapper baseMapper; + private final GenTableColumnMapper genTableColumnMapper; + private final IdentifierGenerator identifierGenerator; + + private static final String[] TABLE_IGNORE = new String[]{"sj_", "flow_", "gen_"}; + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + @Override + public List selectGenTableColumnListByTableId(Long tableId) { + return genTableColumnMapper.selectList(new LambdaQueryWrapper() + .eq(GenTableColumn::getTableId, tableId) + .orderByAsc(GenTableColumn::getSort)); + } + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + @Override + public GenTable selectGenTableById(Long id) { + GenTable genTable = baseMapper.selectGenTableById(id); + setTableFromOptions(genTable); + return genTable; + } + + @Override + public TableDataInfo selectPageGenTableList(GenTable genTable, PageQuery pageQuery) { + Page page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable)); + return TableDataInfo.build(page); + } + + private QueryWrapper buildGenTableQueryWrapper(GenTable genTable) { + Map params = genTable.getParams(); + QueryWrapper wrapper = Wrappers.query(); + wrapper + .eq(StringUtils.isNotEmpty(genTable.getDataName()), "data_name", genTable.getDataName()) + .like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName())) + .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment())) + .between(params.get("beginTime") != null && params.get("endTime") != null, + "create_time", params.get("beginTime"), params.get("endTime")) + .orderByDesc("update_time"); + return wrapper; + } + + /** + * 查询数据库列表 + * + * @param genTable 包含查询条件的GenTable对象 + * @param pageQuery 包含分页信息的PageQuery对象 + * @return 包含分页结果的TableDataInfo对象 + */ + @DS("#genTable.dataName") + @Override + public TableDataInfo selectPageDbTableList(GenTable genTable, PageQuery pageQuery) { + // 获取查询条件 + String tableName = genTable.getTableName(); + String tableComment = genTable.getTableComment(); + + LinkedHashMap> tablesMap = ServiceProxy.metadata().tables(); + if (CollUtil.isEmpty(tablesMap)) { + return TableDataInfo.build(); + } + List tableNames = baseMapper.selectTableNameList(genTable.getDataName()); + String[] tableArrays; + if (CollUtil.isNotEmpty(tableNames)) { + tableArrays = tableNames.toArray(new String[0]); + } else { + tableArrays = new String[0]; + } + // 过滤并转换表格数据 + List tables = tablesMap.values().stream() + .filter(x -> !StringUtils.startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE)) + .filter(x -> { + if (CollUtil.isEmpty(tableNames)) { + return true; + } + return !StringUtils.equalsAnyIgnoreCase(x.getName(), tableArrays); + }) + .filter(x -> { + boolean nameMatches = true; + boolean commentMatches = true; + // 进行表名称的模糊查询 + if (StringUtils.isNotBlank(tableName)) { + nameMatches = StringUtils.containsIgnoreCase(x.getName(), tableName); + } + // 进行表描述的模糊查询 + if (StringUtils.isNotBlank(tableComment)) { + commentMatches = StringUtils.containsIgnoreCase(x.getComment(), tableComment); + } + // 同时匹配名称和描述 + return nameMatches && commentMatches; + }) + .map(x -> { + GenTable gen = new GenTable(); + gen.setTableName(x.getName()); + gen.setTableComment(x.getComment()); + // postgresql的表元数据没有创建时间这个东西(好奇葩) 只能new Date代替 + gen.setCreateTime(ObjectUtil.defaultIfNull(x.getCreateTime(), new Date())); + gen.setUpdateTime(x.getUpdateTime()); + return gen; + }).sorted(Comparator.comparing(GenTable::getCreateTime).reversed()) + .toList(); + + IPage page = pageQuery.build(); + page.setTotal(tables.size()); + // 手动分页 set数据 + page.setRecords(CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), tables)); + return TableDataInfo.build(page); + } + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @param dataName 数据源名称 + * @return 数据库表集合 + */ + @DS("#dataName") + @Override + public List selectDbTableListByNames(String[] tableNames, String dataName) { + Set tableNameSet = new HashSet<>(List.of(tableNames)); + LinkedHashMap> tablesMap = ServiceProxy.metadata().tables(); + + if (CollUtil.isEmpty(tablesMap)) { + return new ArrayList<>(); + } + + List> tableList = tablesMap.values().stream() + .filter(x -> !StringUtils.startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE)) + .filter(x -> tableNameSet.contains(x.getName())).toList(); + + if (CollUtil.isEmpty(tableList)) { + return new ArrayList<>(); + } + return tableList.stream().map(x -> { + GenTable gen = new GenTable(); + gen.setDataName(dataName); + gen.setTableName(x.getName()); + gen.setTableComment(x.getComment()); + gen.setCreateTime(x.getCreateTime()); + gen.setUpdateTime(x.getUpdateTime()); + return gen; + }).toList(); + } + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List selectGenTableAll() { + return baseMapper.selectGenTableAll(); + } + + /** + * 修改业务 + * + * @param genTable 业务信息 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void updateGenTable(GenTable genTable) { + String options = JsonUtils.toJsonString(genTable.getParams()); + genTable.setOptions(options); + int row = baseMapper.updateById(genTable); + if (row > 0) { + for (GenTableColumn cenTableColumn : genTable.getColumns()) { + genTableColumnMapper.updateById(cenTableColumn); + } + } + } + + /** + * 删除业务对象 + * + * @param tableIds 需要删除的数据ID + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void deleteGenTableByIds(Long[] tableIds) { + List ids = Arrays.asList(tableIds); + baseMapper.deleteByIds(ids); + genTableColumnMapper.delete(new LambdaQueryWrapper().in(GenTableColumn::getTableId, ids)); + } + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + * @param dataName 数据源名称 + */ + @DSTransactional + @Override + public void importGenTable(List tableList, String dataName) { + try { + for (GenTable table : tableList) { + String tableName = table.getTableName(); + GenUtils.initTable(table); + table.setDataName(dataName); + int row = baseMapper.insert(table); + if (row > 0) { + // 保存列信息 + List genTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(tableName, dataName); + List saveColumns = new ArrayList<>(); + for (GenTableColumn column : genTableColumns) { + GenUtils.initColumnField(column, table); + saveColumns.add(column); + } + if (CollUtil.isNotEmpty(saveColumns)) { + genTableColumnMapper.insertBatch(saveColumns); + } + } + } + } catch (Exception e) { + throw new ServiceException("导入失败:" + e.getMessage()); + } + } + + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @param dataName 数据源名称 + * @return 列信息 + */ + @DS("#dataName") + @Override + public List selectDbTableColumnsByName(String tableName, String dataName) { + Table table = ServiceProxy.metadata().table(tableName); + if (ObjectUtil.isNull(table)) { + return new ArrayList<>(); + } + LinkedHashMap columns = table.getColumns(); + List tableColumns = new ArrayList<>(); + columns.forEach((columnName, column) -> { + GenTableColumn tableColumn = new GenTableColumn(); + tableColumn.setIsPk(String.valueOf(column.isPrimaryKey())); + tableColumn.setColumnName(column.getName()); + tableColumn.setColumnComment(column.getComment()); + tableColumn.setColumnType(column.getOriginType().toLowerCase()); + tableColumn.setSort(column.getPosition()); + tableColumn.setIsRequired(column.isNullable() == 0 ? "1" : "0"); + tableColumn.setIsIncrement(column.isAutoIncrement() == -1 ? "0" : "1"); + tableColumns.add(tableColumn); + }); + return tableColumns; + } + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + @Override + public Map previewCode(Long tableId) { + Map dataMap = new LinkedHashMap<>(); + // 查询表信息 + GenTable table = baseMapper.selectGenTableById(tableId); + List menuIds = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + menuIds.add(identifierGenerator.nextId(null).longValue()); + } + table.setMenuIds(menuIds); + // 设置主键列信息 + setPkColumn(table); + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + dataMap.put(template, sw.toString()); + } + return dataMap; + } + + /** + * 生成代码(下载方式) + * + * @param tableId 表名称 + * @return 数据 + */ + @Override + public byte[] downloadCode(Long tableId) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + generatorCode(tableId, zip); + IoUtil.close(zip); + return outputStream.toByteArray(); + } + + /** + * 生成代码(自定义路径) + * + * @param tableId 表名称 + */ + @Override + public void generatorCode(Long tableId) { + // 查询表信息 + GenTable table = baseMapper.selectGenTableById(tableId); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + if (!StringUtils.containsAny(template, "sql.vm", "api.ts.vm", "types.ts.vm", "index.vue.vm", "index-tree.vue.vm")) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + String path = getGenPath(table, template); + FileUtils.writeUtf8String(sw.toString(), path); + } catch (Exception e) { + throw new ServiceException("渲染模板失败,表名:" + table.getTableName()); + } + } + } + } + + /** + * 同步数据库 + * + * @param tableId 表名称 + */ + @DSTransactional + @Override + public void synchDb(Long tableId) { + GenTable table = baseMapper.selectGenTableById(tableId); + List tableColumns = table.getColumns(); + Map tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName); + + List dbTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(table.getTableName(), table.getDataName()); + if (CollUtil.isEmpty(dbTableColumns)) { + throw new ServiceException("同步数据失败,原表结构不存在"); + } + List dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName); + + List saveColumns = new ArrayList<>(); + dbTableColumns.forEach(column -> { + GenUtils.initColumnField(column, table); + if (tableColumnMap.containsKey(column.getColumnName())) { + GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName()); + column.setColumnId(prevColumn.getColumnId()); + if (column.isList()) { + // 如果是列表,继续保留查询方式/字典类型选项 + column.setDictType(prevColumn.getDictType()); + column.setQueryType(prevColumn.getQueryType()); + } + if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk() + && (column.isInsert() || column.isEdit()) + && ((column.isUsableColumn()) || (!column.isSuperColumn()))) { + // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项 + column.setIsRequired(prevColumn.getIsRequired()); + column.setHtmlType(prevColumn.getHtmlType()); + } + } + saveColumns.add(column); + }); + if (CollUtil.isNotEmpty(saveColumns)) { + genTableColumnMapper.insertOrUpdateBatch(saveColumns); + } + List delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName())); + if (CollUtil.isNotEmpty(delColumns)) { + List ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId); + if (CollUtil.isNotEmpty(ids)) { + genTableColumnMapper.deleteByIds(ids); + } + } + } + + /** + * 批量生成代码(下载方式) + * + * @param tableIds 表ID数组 + * @return 数据 + */ + @Override + public byte[] downloadCode(String[] tableIds) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + for (String tableId : tableIds) { + generatorCode(Long.parseLong(tableId), zip); + } + IoUtil.close(zip); + return outputStream.toByteArray(); + } + + /** + * 查询表信息并生成代码 + */ + private void generatorCode(Long tableId, ZipOutputStream zip) { + // 查询表信息 + GenTable table = baseMapper.selectGenTableById(tableId); + List menuIds = new ArrayList<>(); + for (int i = 0; i < 6; i++) { + menuIds.add(identifierGenerator.nextId(null).longValue()); + } + table.setMenuIds(menuIds); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try { + // 添加到zip + zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table))); + IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString()); + IoUtil.close(sw); + zip.flush(); + zip.closeEntry(); + } catch (IOException e) { + log.error("渲染模板失败,表名:" + table.getTableName(), e); + } + } + } + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + @Override + public void validateEdit(GenTable genTable) { + if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) { + String options = JsonUtils.toJsonString(genTable.getParams()); + Dict paramsObj = JsonUtils.parseMap(options); + if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_CODE))) { + throw new ServiceException("树编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_PARENT_CODE))) { + throw new ServiceException("树父编码字段不能为空"); + } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_NAME))) { + throw new ServiceException("树名称字段不能为空"); + } + } + } + + /** + * 设置主键列信息 + * + * @param table 业务表信息 + */ + public void setPkColumn(GenTable table) { + for (GenTableColumn column : table.getColumns()) { + if (column.isPk()) { + table.setPkColumn(column); + break; + } + } + if (ObjectUtil.isNull(table.getPkColumn())) { + table.setPkColumn(table.getColumns().get(0)); + } + + } + + /** + * 设置代码生成其他选项值 + * + * @param genTable 设置后的生成对象 + */ + public void setTableFromOptions(GenTable genTable) { + Dict paramsObj = JsonUtils.parseMap(genTable.getOptions()); + if (ObjectUtil.isNotNull(paramsObj)) { + String treeCode = paramsObj.getStr(GenConstants.TREE_CODE); + String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE); + String treeName = paramsObj.getStr(GenConstants.TREE_NAME); + Long parentMenuId = paramsObj.getLong(GenConstants.PARENT_MENU_ID); + String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME); + + genTable.setTreeCode(treeCode); + genTable.setTreeParentCode(treeParentCode); + genTable.setTreeName(treeName); + genTable.setParentMenuId(parentMenuId); + genTable.setParentMenuName(parentMenuName); + } + } + + /** + * 获取代码生成地址 + * + * @param table 业务表信息 + * @param template 模板文件路径 + * @return 生成地址 + */ + public static String getGenPath(GenTable table, String template) { + String genPath = table.getGenPath(); + if (StringUtils.equals(genPath, "/")) { + return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table); + } + return genPath + File.separator + VelocityUtils.getFileName(template, table); + } +} + diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java new file mode 100644 index 0000000..b2c20c5 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java @@ -0,0 +1,141 @@ +package org.dromara.generator.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.generator.domain.GenTable; +import org.dromara.generator.domain.GenTableColumn; + +import java.util.List; +import java.util.Map; + +/** + * 业务 服务层 + * + * @author Lion Li + */ +public interface IGenTableService { + + /** + * 查询业务字段列表 + * + * @param tableId 业务字段编号 + * @return 业务字段集合 + */ + List selectGenTableColumnListByTableId(Long tableId); + + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + TableDataInfo selectPageGenTableList(GenTable genTable, PageQuery pageQuery); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + TableDataInfo selectPageDbTableList(GenTable genTable, PageQuery pageQuery); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @param dataName 数据源名称 + * @return 数据库表集合 + */ + List selectDbTableListByNames(String[] tableNames, String dataName); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + List selectGenTableAll(); + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + GenTable selectGenTableById(Long id); + + /** + * 修改业务 + * + * @param genTable 业务信息 + */ + void updateGenTable(GenTable genTable); + + /** + * 删除业务信息 + * + * @param tableIds 需要删除的表数据ID + */ + void deleteGenTableByIds(Long[] tableIds); + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + * @param dataName 数据源名称 + */ + void importGenTable(List tableList, String dataName); + + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @param dataName 数据源名称 + * @return 列信息 + */ + List selectDbTableColumnsByName(String tableName, String dataName); + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + Map previewCode(Long tableId); + + /** + * 生成代码(下载方式) + * + * @param tableId 表名称 + * @return 数据 + */ + byte[] downloadCode(Long tableId); + + /** + * 生成代码(自定义路径) + * + * @param tableId 表名称 + */ + void generatorCode(Long tableId); + + /** + * 同步数据库 + * + * @param tableId 表名称 + */ + void synchDb(Long tableId); + + /** + * 批量生成代码(下载方式) + * + * @param tableIds 表ID数组 + * @return 数据 + */ + byte[] downloadCode(String[] tableIds); + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + void validateEdit(GenTable genTable); +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java new file mode 100644 index 0000000..6e111e3 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java @@ -0,0 +1,341 @@ +package org.dromara.generator.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Dict; +import org.dromara.generator.constant.GenConstants; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.helper.DataBaseHelper; +import org.dromara.generator.domain.GenTable; +import org.dromara.generator.domain.GenTableColumn; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.velocity.VelocityContext; + +import java.util.*; + +/** + * 模板处理工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class VelocityUtils { + + /** + * 项目空间路径 + */ + private static final String PROJECT_PATH = "main/java"; + + /** + * mybatis空间路径 + */ + private static final String MYBATIS_PATH = "main/resources/mapper"; + + /** + * 默认上级菜单,系统工具 + */ + private static final String DEFAULT_PARENT_MENU_ID = "3"; + + /** + * 设置模板变量信息 + * + * @return 模板列表 + */ + public static VelocityContext prepareContext(GenTable genTable) { + String moduleName = genTable.getModuleName(); + String businessName = genTable.getBusinessName(); + String packageName = genTable.getPackageName(); + String tplCategory = genTable.getTplCategory(); + String functionName = genTable.getFunctionName(); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("tplCategory", genTable.getTplCategory()); + velocityContext.put("tableName", genTable.getTableName()); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); + velocityContext.put("ClassName", genTable.getClassName()); + velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); + velocityContext.put("moduleName", genTable.getModuleName()); + velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName())); + velocityContext.put("businessName", genTable.getBusinessName()); + velocityContext.put("basePackage", getPackagePrefix(packageName)); + velocityContext.put("packageName", packageName); + velocityContext.put("author", genTable.getFunctionAuthor()); + velocityContext.put("datetime", DateUtils.getDate()); + velocityContext.put("pkColumn", genTable.getPkColumn()); + velocityContext.put("importList", getImportList(genTable)); + velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); + velocityContext.put("columns", genTable.getColumns()); + velocityContext.put("table", genTable); + velocityContext.put("dicts", getDicts(genTable)); + setMenuVelocityContext(velocityContext, genTable); + if (GenConstants.TPL_TREE.equals(tplCategory)) { + setTreeVelocityContext(velocityContext, genTable); + } + return velocityContext; + } + + public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String parentMenuId = getParentMenuId(paramsObj); + context.put("parentMenuId", parentMenuId); + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String treeCode = getTreecode(paramsObj); + String treeParentCode = getTreeParentCode(paramsObj); + String treeName = getTreeName(paramsObj); + + context.put("treeCode", treeCode); + context.put("treeParentCode", treeParentCode); + context.put("treeName", treeName); + context.put("expandColumn", getExpandColumn(genTable)); + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + context.put("tree_parent_code", paramsObj.get(GenConstants.TREE_PARENT_CODE)); + } + if (paramsObj.containsKey(GenConstants.TREE_NAME)) { + context.put("tree_name", paramsObj.get(GenConstants.TREE_NAME)); + } + } + + /** + * 获取模板信息 + * + * @return 模板列表 + */ + public static List getTemplateList(String tplCategory) { + List templates = new ArrayList<>(); + templates.add("vm/java/domain.java.vm"); + templates.add("vm/java/vo.java.vm"); + templates.add("vm/java/bo.java.vm"); + templates.add("vm/java/mapper.java.vm"); + templates.add("vm/java/service.java.vm"); + templates.add("vm/java/serviceImpl.java.vm"); + templates.add("vm/java/controller.java.vm"); + templates.add("vm/xml/mapper.xml.vm"); + if (DataBaseHelper.isOracle()) { + templates.add("vm/sql/oracle/sql.vm"); + } else if (DataBaseHelper.isPostgerSql()) { + templates.add("vm/sql/postgres/sql.vm"); + } else if (DataBaseHelper.isSqlServer()) { + templates.add("vm/sql/sqlserver/sql.vm"); + } else { + templates.add("vm/sql/sql.vm"); + } + templates.add("vm/ts/api.ts.vm"); + templates.add("vm/ts/types.ts.vm"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) { + templates.add("vm/vue/index.vue.vm"); + } else if (GenConstants.TPL_TREE.equals(tplCategory)) { + templates.add("vm/vue/index-tree.vue.vm"); + } + return templates; + } + + /** + * 获取文件名 + */ + public static String getFileName(String template, GenTable genTable) { + // 文件名称 + String fileName = ""; + // 包路径 + String packageName = genTable.getPackageName(); + // 模块名 + String moduleName = genTable.getModuleName(); + // 大写类名 + String className = genTable.getClassName(); + // 业务名称 + String businessName = genTable.getBusinessName(); + + String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/"); + String mybatisPath = MYBATIS_PATH + "/" + moduleName; + String vuePath = "vue"; + + if (template.contains("domain.java.vm")) { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); + } + if (template.contains("vo.java.vm")) { + fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className); + } + if (template.contains("bo.java.vm")) { + fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className); + } + if (template.contains("mapper.java.vm")) { + fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); + } else if (template.contains("service.java.vm")) { + fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className); + } else if (template.contains("serviceImpl.java.vm")) { + fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); + } else if (template.contains("controller.java.vm")) { + fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className); + } else if (template.contains("mapper.xml.vm")) { + fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); + } else if (template.contains("sql.vm")) { + fileName = businessName + "Menu.sql"; + } else if (template.contains("api.ts.vm")) { + fileName = StringUtils.format("{}/api/{}/{}/index.ts", vuePath, moduleName, businessName); + } else if (template.contains("types.ts.vm")) { + fileName = StringUtils.format("{}/api/{}/{}/types.ts", vuePath, moduleName, businessName); + } else if (template.contains("index.vue.vm")) { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } else if (template.contains("index-tree.vue.vm")) { + fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName); + } + return fileName; + } + + /** + * 获取包前缀 + * + * @param packageName 包名称 + * @return 包前缀名称 + */ + public static String getPackagePrefix(String packageName) { + int lastIndex = packageName.lastIndexOf("."); + return StringUtils.substring(packageName, 0, lastIndex); + } + + /** + * 根据列类型获取导入包 + * + * @param genTable 业务表对象 + * @return 返回需要导入的包列表 + */ + public static HashSet getImportList(GenTable genTable) { + List columns = genTable.getColumns(); + HashSet importList = new HashSet<>(); + for (GenTableColumn column : columns) { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) { + importList.add("java.util.Date"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) { + importList.add("java.math.BigDecimal"); + } else if (!column.isSuperColumn() && "imageUpload".equals(column.getHtmlType())) { + importList.add("org.dromara.common.translation.annotation.Translation"); + importList.add("org.dromara.common.translation.constant.TransConstant"); + } + } + return importList; + } + + /** + * 根据列类型获取字典组 + * + * @param genTable 业务表对象 + * @return 返回字典组 + */ + public static String getDicts(GenTable genTable) { + List columns = genTable.getColumns(); + Set dicts = new HashSet<>(); + addDicts(dicts, columns); + return StringUtils.join(dicts, ", "); + } + + /** + * 添加字典列表 + * + * @param dicts 字典列表 + * @param columns 列集合 + */ + public static void addDicts(Set dicts, List columns) { + for (GenTableColumn column : columns) { + if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( + column.getHtmlType(), + new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) { + dicts.add("'" + column.getDictType() + "'"); + } + } + } + + /** + * 获取权限前缀 + * + * @param moduleName 模块名称 + * @param businessName 业务名称 + * @return 返回权限前缀 + */ + public static String getPermissionPrefix(String moduleName, String businessName) { + return StringUtils.format("{}:{}", moduleName, businessName); + } + + /** + * 获取上级菜单ID字段 + * + * @param paramsObj 生成其他选项 + * @return 上级菜单ID字段 + */ + public static String getParentMenuId(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID) + && StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) { + return paramsObj.getStr(GenConstants.PARENT_MENU_ID); + } + return DEFAULT_PARENT_MENU_ID; + } + + /** + * 获取树编码 + * + * @param paramsObj 生成其他选项 + * @return 树编码 + */ + public static String getTreecode(Map paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) { + return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE))); + } + return StringUtils.EMPTY; + } + + /** + * 获取树父编码 + * + * @param paramsObj 生成其他选项 + * @return 树父编码 + */ + public static String getTreeParentCode(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_PARENT_CODE)); + } + return StringUtils.EMPTY; + } + + /** + * 获取树名称 + * + * @param paramsObj 生成其他选项 + * @return 树名称 + */ + public static String getTreeName(Dict paramsObj) { + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) { + return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_NAME)); + } + return StringUtils.EMPTY; + } + + /** + * 获取需要在哪一列上面显示展开按钮 + * + * @param genTable 业务表对象 + * @return 展开按钮列序号 + */ + public static int getExpandColumn(GenTable genTable) { + String options = genTable.getOptions(); + Dict paramsObj = JsonUtils.parseMap(options); + String treeName = paramsObj.getStr(GenConstants.TREE_NAME); + int num = 0; + for (GenTableColumn column : genTable.getColumns()) { + if (column.isList()) { + num++; + String columnName = column.getColumnName(); + if (columnName.equals(treeName)) { + break; + } + } + } + return num; + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml new file mode 100644 index 0000000..fc1c610 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml new file mode 100644 index 0000000..78aa852 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark, + c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort + FROM gen_table t + LEFT JOIN gen_table_column c ON t.table_id = c.table_id + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm new file mode 100644 index 0000000..511d37c --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm @@ -0,0 +1,50 @@ +package ${packageName}.domain.bo; + +import ${packageName}.domain.${ClassName}; +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.*; +#foreach ($import in $importList) +import ${import}; +#end + +/** + * ${functionName}业务对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false) +public class ${ClassName}Bo extends BaseEntity { + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit)) + /** + * $column.columnComment + */ +#if($column.insert && $column.edit) +#set($Group="AddGroup.class, EditGroup.class") +#elseif($column.insert) +#set($Group="AddGroup.class") +#elseif($column.edit) +#set($Group="EditGroup.class") +#end +#if($column.required) +#if($column.javaType == 'String') + @NotBlank(message = "$column.columnComment不能为空", groups = { $Group }) +#else + @NotNull(message = "$column.columnComment不能为空", groups = { $Group }) +#end +#end + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm new file mode 100644 index 0000000..205fb73 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm @@ -0,0 +1,60 @@ +package ${packageName}.domain; + +#foreach ($column in $columns) +#if($column.javaField=='tenantId') +#set($IsTenant=1) +#end +#end +#if($IsTenant==1) +import org.dromara.common.tenant.core.TenantEntity; +#else +import org.dromara.common.mybatis.core.domain.BaseEntity; +#end +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +#foreach ($import in $importList) +import ${import}; +#end + +import java.io.Serial; + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($IsTenant==1) +#set($Entity="TenantEntity") +#else +#set($Entity="BaseEntity") +#end +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("${tableName}") +public class ${ClassName} extends ${Entity} { + + @Serial + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) + /** + * $column.columnComment + */ +#if($column.javaField=='delFlag') + @TableLogic +#end +#if($column.javaField=='version') + @Version +#end +#if($column.isPk==1) + @TableId(value = "$column.columnName") +#end + private $column.javaType $column.javaField; + +#end +#end + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm new file mode 100644 index 0000000..0922401 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm @@ -0,0 +1,15 @@ +package ${packageName}.mapper; + +import ${packageName}.domain.${ClassName}; +import ${packageName}.domain.vo.${ClassName}Vo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * ${functionName}Mapper接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> { + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm new file mode 100644 index 0000000..4db9030 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm @@ -0,0 +1,72 @@ +package ${packageName}.service; + +import ${packageName}.domain.vo.${ClassName}Vo; +import ${packageName}.domain.bo.${ClassName}Bo; +#if($table.crud) +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +#end + +import java.util.Collection; +import java.util.List; + +/** + * ${functionName}Service接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Service { + + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} 主键 + * @return ${functionName} + */ + ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}); + +#if($table.crud) + /** + * 分页查询${functionName}列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return ${functionName}分页列表 + */ + TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery); +#end + + /** + * 查询符合条件的${functionName}列表 + * + * @param bo 查询条件 + * @return ${functionName}列表 + */ + List<${ClassName}Vo> queryList(${ClassName}Bo bo); + + /** + * 新增${functionName} + * + * @param bo ${functionName} + * @return 是否新增成功 + */ + Boolean insertByBo(${ClassName}Bo bo); + + /** + * 修改${functionName} + * + * @param bo ${functionName} + * @return 是否修改成功 + */ + Boolean updateByBo(${ClassName}Bo bo); + + /** + * 校验并批量删除${functionName}信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm new file mode 100644 index 0000000..48cc8b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -0,0 +1,158 @@ +package ${packageName}.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +#if($table.crud) +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +#end +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import ${packageName}.domain.bo.${ClassName}Bo; +import ${packageName}.domain.vo.${ClassName}Vo; +import ${packageName}.domain.${ClassName}; +import ${packageName}.mapper.${ClassName}Mapper; +import ${packageName}.service.I${ClassName}Service; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * ${functionName}Service业务层处理 + * + * @author ${author} + * @date ${datetime} + */ +@RequiredArgsConstructor +@Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service { + + private final ${ClassName}Mapper baseMapper; + + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} 主键 + * @return ${functionName} + */ + @Override + public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){ + return baseMapper.selectVoById(${pkColumn.javaField}); + } + +#if($table.crud) + /** + * 分页查询${functionName}列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return ${functionName}分页列表 + */ + @Override + public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery) { + LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo); + Page<${ClassName}Vo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } +#end + + /** + * 查询符合条件的${functionName}列表 + * + * @param bo 查询条件 + * @return ${functionName}列表 + */ + @Override + public List<${ClassName}Vo> queryList(${ClassName}Bo bo) { + LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery(); +#foreach($column in $columns) +#if($column.query) +#set($queryType=$column.queryType) +#set($javaField=$column.javaField) +#set($javaType=$column.javaType) +#set($columnName=$column.columnName) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($mpMethod=$column.queryType.toLowerCase()) +#if($queryType != 'BETWEEN') +#if($javaType == 'String') +#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())') +#else +#set($condition='bo.get'+$AttrName+'() != null') +#end + lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName()); +#else + lqw.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null, + ${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName")); +#end +#end +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#if($column.isPk==1) + lqw.orderByAsc(${ClassName}::get$AttrName); +#end +#end + return lqw; + } + + /** + * 新增${functionName} + * + * @param bo ${functionName} + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(${ClassName}Bo bo) { + ${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; +#set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)}) + if (flag) { + bo.set$pk(add.get$pk()); + } + return flag; + } + + /** + * 修改${functionName} + * + * @param bo ${functionName} + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(${ClassName}Bo bo) { + ${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(${ClassName} entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除${functionName}信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm new file mode 100644 index 0000000..5591f97 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm @@ -0,0 +1,66 @@ +package ${packageName}.domain.vo; + +#foreach ($import in $importList) +import ${import}; +#end +import ${packageName}.domain.${ClassName}; +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; + + + +/** + * ${functionName}视图对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ${ClassName}.class) +public class ${ClassName}Vo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if($column.list) + /** + * $column.columnComment + */ +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if(${column.dictType} && ${column.dictType} != '') + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "${column.dictType}") +#elseif($parentheseIndex != -1) + @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "$column.readConverterExp()") +#else + @ExcelProperty(value = "${comment}") +#end + private $column.javaType $column.javaField; + +#if($column.htmlType == "imageUpload") + /** + * ${column.columnComment}Url + */ + @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}") + private String ${column.javaField}Url; +#end +#end +#end + +} diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm new file mode 100644 index 0000000..f6638be --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate, null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate, null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate, null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm new file mode 100644 index 0000000..0923392 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm @@ -0,0 +1,20 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, now(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, now(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, now(), null, null, ''); + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm new file mode 100644 index 0000000..01824c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate(), null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm new file mode 100644 index 0000000..bdf166e --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm @@ -0,0 +1,19 @@ +-- 菜单 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, getdate(), null, null, '${functionName}菜单'); + +-- 按钮 SQL +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, getdate(), null, null, ''); + +insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark) +values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, getdate(), null, null, ''); diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm new file mode 100644 index 0000000..3aa4a5f --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm @@ -0,0 +1,63 @@ +import request from '@/utils/request'; +import { AxiosPromise } from 'axios'; +import { ${BusinessName}VO, ${BusinessName}Form, ${BusinessName}Query } from '@/api/${moduleName}/${businessName}/types'; + +/** + * 查询${functionName}列表 + * @param query + * @returns {*} + */ + +export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> => { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'get', + params: query + }); +}; + +/** + * 查询${functionName}详细 + * @param ${pkColumn.javaField} + */ +export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'get' + }); +}; + +/** + * 新增${functionName} + * @param data + */ +export const add${BusinessName} = (data: ${BusinessName}Form) => { + return request({ + url: '/${moduleName}/${businessName}', + method: 'post', + data: data + }); +}; + +/** + * 修改${functionName} + * @param data + */ +export const update${BusinessName} = (data: ${BusinessName}Form) => { + return request({ + url: '/${moduleName}/${businessName}', + method: 'put', + data: data + }); +}; + +/** + * 删除${functionName} + * @param ${pkColumn.javaField} + */ +export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array) => { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'delete' + }); +}; diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm new file mode 100644 index 0000000..caf3472 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -0,0 +1,498 @@ + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm new file mode 100644 index 0000000..a92d19a --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm @@ -0,0 +1,459 @@ + + + diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm new file mode 100644 index 0000000..9fb48d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-job/pom.xml b/ruoyi-modules/ruoyi-job/pom.xml new file mode 100644 index 0000000..b022088 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/pom.xml @@ -0,0 +1,52 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + jar + ruoyi-job + + + 任务调度 + + + + + + + org.dromara + ruoyi-common-json + + + + org.dromara + ruoyi-common-job + + + com.pdd + com.pdd + 1.92.52 + compile + + + com.github.therapi + therapi-runtime-javadoc + + + com.google.code.gson + gson + + + org.dromara + ruoyi-zhishu + + + + + + diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/domains/ShopOrderVO.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/domains/ShopOrderVO.java new file mode 100644 index 0000000..4e84b18 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/domains/ShopOrderVO.java @@ -0,0 +1,17 @@ +package org.dromara.job.domains; + +import lombok.Data; + +import java.util.List; + +@Data +public class ShopOrderVO { + + private Integer page; + + private Integer mallId;//店铺id + + private String shopName;//店铺名称 + + private String accessToken; +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/mapper/ShopOrderDetailMapper.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/mapper/ShopOrderDetailMapper.java new file mode 100644 index 0000000..1646c68 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/mapper/ShopOrderDetailMapper.java @@ -0,0 +1,10 @@ +package org.dromara.job.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TShopOrderDetail; +import org.dromara.zhishu.domain.vo.TShopOrderDetailVo; + + +public interface ShopOrderDetailMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/service/impl/PddServiceImpl.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/service/impl/PddServiceImpl.java new file mode 100644 index 0000000..82f3555 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/service/impl/PddServiceImpl.java @@ -0,0 +1,1121 @@ +package org.dromara.job.service.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.google.gson.*; +import com.google.j2objc.annotations.LoopTranslation; +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.request.PddOrderNumberListIncrementGetRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddOrderListGetResponse; +import com.pdd.pop.sdk.http.api.pop.response.PddOrderNumberListIncrementGetResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.aspectj.weaver.Utils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.job.mapper.ShopOrderDetailMapper; +import org.dromara.job.mapper.ShopOrderMapper; +import org.dromara.job.service.IPddService; +import org.dromara.zhishu.domain.TShopOrder; +import org.dromara.zhishu.domain.TShopOrderDetail; +import org.dromara.zhishu.enums.PddOrderEnum; +import org.dromara.zhishu.enums.PddResCodeEnum; +import org.dromara.zhishu.util.JsonObjUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.dromara.job.domains.ShopOrderVO; + + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.List; + + +@RequiredArgsConstructor +@Log4j2 +@Service("pddJobServiceImpl") +public class PddServiceImpl implements IPddService { + + private final ShopOrderMapper shopOrderMapper; + private final ShopOrderDetailMapper shopOrderDetailMapper; + + //同步三个月以内历史订单(根据成交时间) + @Override + @Transactional(rollbackFor = Exception.class) + public void getConfirmOrderList(ShopOrderVO orderVO) throws Exception { + //todo 租户编码暂时写死tenant_id 000000 + String clientId = "203c5a7ba8bd4b8488d5e26f93052642"; + String clientSecret = "892ffaa86e12b7a3d8d2942b669d9aa520ad8179"; +// String accessToken = "6778e421d0ac477e81fb009418ca8f056842cba0"; + PopClient client = new PopHttpClient(clientId, clientSecret); + + PddOrderListGetRequest request = new PddOrderListGetRequest(); + + //获取日期,遍历三个月内时间作比较,查询近三个月每一天的订单 + + //当前日期 + LocalDate today = LocalDate.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + today = LocalDate.parse(today.format(formatter), formatter); + + LocalDate threeMonthsAgo = today.minusMonths(3); + System.out.println("------------------三月前的日期"+threeMonthsAgo+"--------------"); + + + QueryWrapper orderQueryWrapper = new QueryWrapper<>(); + orderQueryWrapper.select("DISTINCT DATE(confirm_time) as confirm_date") + .groupBy("DATE(confirm_time)"); + + List shopOrderList = shopOrderMapper.selectObjs(orderQueryWrapper); + + // 遍历三个月里的每一天 + LocalDate currentDate = threeMonthsAgo; + + String formattedDate = ""; + + while (!currentDate.isAfter(today)) { + + formattedDate = currentDate.format(DateTimeFormatter.ISO_DATE); + + // 检查 shopOrderList 中是否包含当前日期 + boolean dateExists = false; + for (Object orderDate : shopOrderList) { + if (orderDate != null && orderDate.toString().contains(formattedDate)) { + dateExists = true; + break; + } + } + + // 如果当前日期不在 shopOrderList 中,停止遍历 + if (!dateExists) { + System.out.println("日期 " + formattedDate + " 不在订单列表中,停止遍历。"); + break; + } + + // 继续遍历下一天 + currentDate = currentDate.plusDays(1); + } + + //时间戳转换 + LocalDate date = LocalDate.parse(formattedDate, DateTimeFormatter.ISO_DATE); + + // 指定时区(例如 UTC 或 Asia/Shanghai) + ZoneId zone = ZoneId.of("Asia/Shanghai"); // 或 + + // 获取当天的开始时间 (00:00:00) + LocalDateTime startOfDay = date.atStartOfDay(); + long startTimestamp = startOfDay.atZone(zone).toEpochSecond(); // 以秒为单位 + + // 获取当天的结束时间 (23:59:59) + LocalDateTime endOfDay = date.atTime(23, 59, 59); + long endTimestamp = endOfDay.atZone(zone).toEpochSecond(); // 以秒为单位 + + System.out.println("--------开始时间:"+startTimestamp+"-------结束时间:"+endTimestamp); + + request.setStartConfirmAt(startTimestamp); + request.setEndConfirmAt(endTimestamp); + request.setOrderStatus(5); + if (ObjectUtils.isNotEmpty(orderVO.getPage())){ + request.setPage(orderVO.getPage()); + } +// request.setPage(page);默认1 +// request.setPageSize(100);默认100 + request.setRefundStatus(5); + request.setTradeType(0); + request.setUseHasNext(true); + PddOrderListGetResponse response = client.syncInvoke(request, orderVO.getAccessToken()); + 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.getAsJsonObject("error_response"))){ + JsonObject error_response = obj.getAsJsonObject("error_response"); + log.error( "数据异常" +error_response.get("error_msg").toString()); + return; + } + + // 获取根对象 + JsonObject object = obj.getAsJsonObject("order_list_get_response"); + + // 获取 has_next 字段 + boolean hasNext = object.get("has_next").getAsBoolean(); + System.out.println("Has next: " + hasNext); + +// int total_count = object.get("total_count").getAsInt(); +// if (total_count == 0){ +// log.info("日期:"+formattedDate+"此天无订单"); +// TShopOrder order = new TShopOrder(); +// order.setConfirmTime(formattedDate); +// shopOrderMapper.insert(order); +// } + + // 获取 order_list 数组 + JsonArray orderList = object.getAsJsonArray("order_list"); + + if (ObjectUtils.isEmpty(orderList)){ + log.info("日期:"+formattedDate+"此天无订单"); + if ( !today.toString().equals(formattedDate)){ + TShopOrder order = new TShopOrder(); + order.setConfirmTime(formattedDate); + shopOrderMapper.insert(order); + } + } + + // 遍历订单列表 + for (JsonElement orderElement : orderList) { + JsonObject order = orderElement.getAsJsonObject(); + + + // 提取订单字段 + //根据订单编号判断 + String orderSn = order.get("order_sn").getAsString(); + + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("order_sn", orderSn); + + TShopOrder shopOrder = shopOrderMapper.selectOne(queryWrapper); + if (ObjectUtils.isEmpty(shopOrder)){ + shopOrder = new TShopOrder(); + shopOrder.setOrderSn(orderSn); + } + + //todo地址-加密 + String address = order.get("address").getAsString(); +// shopOrder.setAddress(address); + + //地址 + String addressMask = order.get("address_mask").getAsString(); + shopOrder.setAddressMask(addressMask); + + //售后状态 + int afterSalesStatus = order.get("after_sales_status").getAsInt(); + shopOrder.setAfterSalesStatus(afterSalesStatus); + + //买家留言信息 + String buyerMemo = order.get("buyer_memo").getAsString(); + shopOrder.setBuyerMemo(buyerMemo); + + //成交状态 + int confirmStatus = order.get("confirm_status").getAsInt(); + shopOrder.setConfirmStatus(confirmStatus); + + //成交时间 + String confirmTime = order.get("confirm_time").getAsString(); + shopOrder.setConfirmTime(confirmTime); + + //订单创建时间 + String createdTime = order.get("created_time").getAsString(); + shopOrder.setCreatedTime(createdTime); + + //是否当日发货: 1-是,0-否 + int deliveryOneDay = order.get("delivery_one_day").getAsInt(); + if (deliveryOneDay == 1){ + shopOrder.setDeliveryOneDay("是"); + } + if (deliveryOneDay == 0){ + shopOrder.setDeliveryOneDay("否"); + } + + //折扣金额 + double discountAmount = order.get("discount_amount").getAsDouble(); + shopOrder.setDiscountAmount(new BigDecimal(discountAmount)); + + //多多支付立减金额 + if (ObjectUtils.isNotEmpty(order.get("duo_duo_pay_reduction"))){ + double duoDuoPayReduction = order.get("duo_duo_pay_reduction").getAsDouble(); + shopOrder.setDuoDuoPayReduction(new BigDecimal(duoDuoPayReduction)); + } + + + //是否多多批发 + int duoduoWholesale = order.get("duoduo_wholesale").getAsInt(); + shopOrder.setDuoduoWholesale(duoduoWholesale); + + //商品金额 + double goodsAmount = order.get("goods_amount").getAsDouble(); + shopOrder.setGoodsAmount(new BigDecimal(goodsAmount)); + + //仓库编码 + if (ObjectUtils.isNotEmpty(order.get("depot_code"))){ + String depotCode = order.get("depot_code").getAsString(); + shopOrder.setDepotCode(depotCode); + } + + + //仓库信息 + if (ObjectUtils.isNotEmpty(order.get("order_depot_info"))){ + Object orderDepotInfo = order.get("order_depot_info"); + shopOrder.setOrderDepotInfo(String.valueOf(orderDepotInfo)); + } + + //仓库id + if (ObjectUtils.isNotEmpty(order.get("depot_id"))){ + long depotId = order.get("depot_id").getAsLong(); + shopOrder.setDepotId(String.valueOf(depotId)); + } + + //仓库名称 + if (ObjectUtils.isNotEmpty(order.get("depot_name"))){ + + String depotName = order.get("depot_name").getAsString(); + shopOrder.setDepotName(depotName); + } + + //仓库类型 + if (ObjectUtils.isNotEmpty(order.get("depot_type"))){ + int depotType = order.get("depot_type").getAsInt(); + shopOrder.setDepotType(depotType); + } + + //货品id + if (ObjectUtils.isNotEmpty(order.get("ware_id"))){ + long wareId = order.get("ware_id").getAsLong(); + shopOrder.setWareId(wareId); + } + + + //货品名称 + if (ObjectUtils.isNotEmpty(order.get("ware_name"))){ + String wareName = order.get("ware_name").getAsString(); + shopOrder.setWareName(wareName); + } + + + //货品编码 + if (ObjectUtils.isNotEmpty(order.get("ware_sn"))){ + String wareSn = order.get("ware_sn").getAsString(); + shopOrder.setWareSn(wareSn); + } + + + //货品类型 + if (ObjectUtils.isNotEmpty(order.get("ware_type"))){ + int wareType = order.get("ware_type").getAsInt(); + shopOrder.setWareType(wareType); + } + + + //订单状态 + int orderStatus = order.get("order_status").getAsInt(); + shopOrder.setOrderStatus(orderStatus); + + //支付金额 + double payAmount = order.get("pay_amount").getAsDouble(); + shopOrder.setPayAmount(new BigDecimal(payAmount)); + + //支付单号 + if (ObjectUtils.isNotEmpty(order.get("pay_no"))){ + String payNo = order.get("pay_no").getAsString(); + shopOrder.setPayNo(payNo); + } + + //支付时间 + String payTime = order.get("pay_time").getAsString(); + shopOrder.setPayTime(payTime); + + //支付方式 + String payType = order.get("pay_type").getAsString(); + shopOrder.setPayType(payType); + + //平台优惠金额 + double platformDiscount = order.get("platform_discount").getAsDouble(); + shopOrder.setPlatformDiscount(new BigDecimal(platformDiscount)); + + //邮费 + double postage = order.get("postage").getAsDouble(); + shopOrder.setPostage(new BigDecimal(postage)); + + //预售时间 + String preSaleTime = order.get("pre_sale_time").getAsString(); + shopOrder.setPreSaleTime(preSaleTime); + + //承诺送达时间 + if (ObjectUtils.isNotEmpty(order.get("promise_delivery_time"))){ + String promiseDeliveryTime = order.get("promise_delivery_time").getAsString(); + shopOrder.setPromiseDeliveryTime(promiseDeliveryTime); + } + + //省份 + String province = order.get("province").getAsString(); + shopOrder.setProvince(province); + + //省份编码 + String provinceId = order.get("province_id").getAsString(); + shopOrder.setProvinceId(provinceId); + + //确认收货时间 + if (ObjectUtils.isNotEmpty(order.get("receive_time"))){ + String receiveTime = order.get("receive_time").getAsString(); + shopOrder.setReceiveTime(receiveTime); + } + + //收件人地址 + String receiverAddress = order.get("receiver_address").getAsString(); + shopOrder.setReceiverAddress(receiverAddress); + + //收件人地址(打码) + String receiverAddressMask = order.get("receiver_address_mask").getAsString(); + shopOrder.setReceiverAddressMask(receiverAddressMask); + + //收件人姓名 + String receiverName = order.get("receiver_name").getAsString(); + shopOrder.setReceiverName(receiverName); + + //收件人姓名 + String receiverNameMask = order.get("receiver_name_mask").getAsString(); + shopOrder.setReceiverNameMask(receiverNameMask); + + //收件人手机号 + String receiverPhone = order.get("receiver_phone").getAsString(); + shopOrder.setReceiverPhone(receiverPhone); + + //收件人手机号(打码) + String receiverPhoneMask = order.get("receiver_phone_mask").getAsString(); + shopOrder.setReceiverPhoneMask(receiverPhoneMask); + + //售后状态 + int refundStatus = order.get("refund_status").getAsInt(); + shopOrder.setRefundStatus(refundStatus); + + //订单备注 + String remark = order.get("remark").getAsString(); + shopOrder.setRemark(remark); + + //订单备注标记 + if (ObjectUtils.isNotEmpty(order.get("remark_tag"))){ + String remarkTag = order.get("remark_tag").getAsString(); + String remarkTagColor; + switch (remarkTag) { + case "1": + remarkTagColor = "红色"; + break; + case "2": + remarkTagColor = "黄色"; + break; + case "3": + remarkTagColor = "绿色"; + break; + case "4": + remarkTagColor = "蓝色"; + break; + case "5": + remarkTagColor = "紫色"; + break; + default: + remarkTagColor = "未知颜色"; + break; + } + shopOrder.setRemarkTag(remarkTagColor); + } + + + //订单备注标记名称 + if (ObjectUtils.isNotEmpty(order.get("remark_tag_name"))) { + String remarkTagName = order.get("remark_tag_name").getAsString(); + shopOrder.setRemarkTagName(remarkTagName); + } + + //退货包运费 + Integer returnFreightPayer = order.get("return_freight_payer").getAsInt(); + shopOrder.setReturnFreightPayer(returnFreightPayer); + + //订单审核状态 + Integer riskControlStatus = order.get("risk_control_status").getAsInt(); + shopOrder.setRiskControlStatus(riskControlStatus); + + //是否门店自提 + Integer selfContained = order.get("self_contained").getAsInt(); + shopOrder.setSelfContained(selfContained); + + //商家优惠金额 + BigDecimal sellerDiscount = new BigDecimal(order.get("seller_discount").getAsString()); + shopOrder.setSellerDiscount(sellerDiscount); + + //缺货处理状态 + Integer stockOutHandleStatus = order.get("stock_out_handle_status").getAsInt(); + shopOrder.setStockOutHandleStatus(stockOutHandleStatus); + + //全国联保 + Integer supportNationwideWarranty = order.get("support_nationwide_warranty").getAsInt(); + shopOrder.setSupportNationwideWarranty(supportNationwideWarranty); + + //区,乡镇 + String town = order.get("town").getAsString(); + shopOrder.setTown(town); + + //区县编码 + String townId = order.get("town_id").getAsString(); + shopOrder.setTownId(townId); + + //快递单号 + String trackingNumber = order.get("tracking_number").getAsString(); + shopOrder.setTrackingNumber(trackingNumber); + + //以旧换新国家补贴金额 + if (ObjectUtils.isNotEmpty(order.get("trade_in_national_subsidy_amount"))){ + double tradeInNationalSubsidyAmount = order.get("trade_in_national_subsidy_amount").getAsDouble(); + shopOrder.setTradeInNationalSubsidyAmount(new BigDecimal(tradeInNationalSubsidyAmount)); + } + + //订单类型 + int tradeType = order.get("trade_type").getAsInt(); + shopOrder.setTradeType(tradeType); + + //订单的更新时间 + if (ObjectUtils.isNotEmpty(order.get("updated_at"))) { + String updatedAt = order.get("updated_at").getAsString(); + shopOrder.setUpdatedAt(updatedAt); + } + + + //催发货时间 + if (ObjectUtils.isNotEmpty(order.get("urge_shipping_time"))) { + String urgeShippingTime = order.get("urge_shipping_time").getAsString(); + shopOrder.setUrgeShippingTime(urgeShippingTime); + } + + + //预约配送日期 + if (ObjectUtils.isNotEmpty(order.get("yyps_date"))) { + String yypsDate = order.get("yyps_date").getAsString(); + shopOrder.setYypsDate(yypsDate); + } + + + //预约配送时段 + if (ObjectUtils.isNotEmpty(order.get("yyps_time"))) { + String yypsTime = order.get("yyps_time").getAsString(); + shopOrder.setYypsTime(yypsTime); + } + + + //合单ID2 + if (ObjectUtils.isNotEmpty(order.get("open_address_id2"))){ + String openAddressId2 = order.get("open_address_id2").getAsString(); + shopOrder.setOpenAddressId2(openAddressId2); + } + + //商品信息列表 + Object itemList = order.get("item_list"); + shopOrder.setItemList(String.valueOf(itemList)); + + + //店铺名称 + shopOrder.setShopName(orderVO.getShopName()); + //店铺id + shopOrder.setShopId(String.valueOf(orderVO.getMallId())); + + //todo 租户编码写死 + shopOrder.setTenantId("000000"); +// String city = order.get("city").getAsString(); +// shopOrder.setCity(city); +// +// int cityId = order.get("city_id").getAsInt(); +// shopOrder.setCityId(cityId); + + // 快递公司编号 +// int logisticsId = order.get("logistics_id").getAsInt(); +// shopOrder.setLogisticsId(logisticsId); + + //是否顺丰包邮,1-是 0-否 +// int freeSf = order.get("free_sf").getAsInt(); +// shopOrder.setFreeSf(freeSf); + //是否缺货 0-无缺货处理 1: 有缺货处理 +// int isStockOut = order.get("is_stock_out").getAsInt(); +// shopOrder.setIsStockOut(isStockOut); + + + if (ObjectUtils.isNotEmpty(shopOrder.getId())){ + shopOrderMapper.updateById(shopOrder); + }else { + shopOrderMapper.insert(shopOrder); + } + + JsonArray orderItemList = order.getAsJsonArray("item_list"); + + if (ObjectUtils.isNotEmpty(orderItemList)) { + //遍历商品详情 + for (JsonElement orderItem : orderItemList) { + JsonObject item = orderItem.getAsJsonObject(); + + QueryWrapper detailQueryWrapper = new QueryWrapper<>(); + detailQueryWrapper.eq("order_id", shopOrder.getId()); + TShopOrderDetail detail = shopOrderDetailMapper.selectOne(detailQueryWrapper); + + if (ObjectUtils.isEmpty(detail)) { + detail = new TShopOrderDetail(); + detail.setOrderId(shopOrder.getId()); + detail.setOrderSn(shopOrder.getOrderSn()); + } + + int goodsCount = item.get("goods_count").getAsInt(); + detail.setGoodsCount(goodsCount); + + String goodsId = item.get("goods_id").getAsString(); + detail.setGoodsId(goodsId); + + String goodsImg = item.get("goods_img").getAsString(); + detail.setGoodsImg(goodsImg); + + String goodsName = item.get("goods_name").getAsString(); + detail.setGoodsName(goodsName); + + double goodsPrice = item.get("goods_price").getAsDouble(); + detail.setGoodsPrice(new BigDecimal(goodsPrice)); + + String goodsSpec = item.get("goods_spec").getAsString(); + detail.setGoodsSpec(goodsSpec); + + String outerGoodsId = item.get("outer_goods_id").getAsString(); + detail.setOuterGoodsId(outerGoodsId); + + String outerId = item.get("outer_id").getAsString(); + detail.setOuterId(outerId); + + String skuId = item.get("sku_id").getAsString(); + detail.setSkuId(skuId); + + //店铺名称 + detail.setShopName(orderVO.getShopName()); + //店铺id + detail.setShopId(String.valueOf(orderVO.getMallId())); + + detail.setTenantId("000000"); + + if (ObjectUtils.isEmpty(detail.getId())) { + shopOrderDetailMapper.insert(detail); + } else { + shopOrderDetailMapper.updateById(detail); + } + } + } + + } + + // 获取 has_next 字段 + boolean next = object.get("has_next").getAsBoolean(); + + if (next){ + orderVO.setPage(orderVO.getPage() + 1); + getConfirmOrderList(orderVO); + } + } + + //订单增量接口(时间跨度为30分钟) + @Override + public void getNowOrderList(ShopOrderVO orderVO) throws Exception { + + + String clientId = "203c5a7ba8bd4b8488d5e26f93052642"; + String clientSecret = "892ffaa86e12b7a3d8d2942b669d9aa520ad8179"; +// String accessToken = orderVO.getAccessToken(); + PopClient client = new PopHttpClient(clientId, clientSecret); + + //设置时间 end_updated_at - start_updated_at<= 30min + // 获取当前时间 + LocalDateTime now = LocalDateTime.now(); + + // 指定时区(例如 UTC 或 Asia/Shanghai) + ZoneId zone = ZoneId.of("Asia/Shanghai"); + + // 获取三十分钟之前的时间 + LocalDateTime tenMinutesAgo = now.minusMinutes(20); + + // 将当前时间转换为 UNIX 时间戳(秒) + long nowTimestamp = now.atZone(zone).toEpochSecond(); + + // 将三十分钟之前的时间转换为 UNIX 时间戳(秒) + long tenMinutesAgoTimestamp = tenMinutesAgo.atZone(zone).toEpochSecond(); + + System.out.println("开始时间----------"+nowTimestamp+":"+now); + System.out.println("结束时间----------"+tenMinutesAgoTimestamp+":"+tenMinutesAgo); + + PddOrderNumberListIncrementGetRequest request = new PddOrderNumberListIncrementGetRequest(); + + request.setStartUpdatedAt(tenMinutesAgoTimestamp);//开始时间 + request.setEndUpdatedAt(nowTimestamp);//结束时间 + + request.setIsLuckyFlag(0);//订单类型(是否抽奖订单),0-全部,1-非抽奖订单,2-抽奖订单 + request.setOrderStatus(5);//发货状态,1-待发货,2-已发货待签收,3-已签收,5-全部 + request.setRefundStatus(5);//售后状态,1-无售后或售后关闭,2-售后处理中,3-退款中,4-退款成功 5-全部 + request.setUseHasNext(true); + +// request.setTradeType(1);//订单类型: 0-普通订单、1-定金订单 不传为全部 +// request.setPage(1);//默认1 +// request.setPageSize(1);//默认100 + + System.out.println(JsonUtil.transferToJson(request)); + + PddOrderNumberListIncrementGetResponse response = client.syncInvoke(request, orderVO.getAccessToken()); + 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.getAsJsonObject("error_response"))){ + JsonObject error_response = obj.getAsJsonObject("error_response"); + log.error( "数据异常" +error_response.get("error_msg").toString()); + return; + } + + // 获取根对象 + JsonObject object = obj.getAsJsonObject("order_sn_increment_get_response"); + + // 获取 has_next 字段 + boolean hasNext = object.get("has_next").getAsBoolean(); + System.out.println("Has next: " + hasNext); + + + // 获取 order_list 数组 + JsonArray orderList = object.getAsJsonArray("order_sn_list"); + + // 遍历订单列表 + for (JsonElement orderElement : orderList) { + JsonObject order = orderElement.getAsJsonObject(); + + + // 提取订单字段 + //根据订单编号判断 + String orderSn = order.get("order_sn").getAsString(); + + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("order_sn", orderSn); + + TShopOrder shopOrder = shopOrderMapper.selectOne(queryWrapper); + if (ObjectUtils.isEmpty(shopOrder)){ + shopOrder = new TShopOrder(); + shopOrder.setOrderSn(orderSn); + } + + //todo地址 加密 + String address = order.get("address").getAsString(); +// shopOrder.setAddress(address); + + //地址 + String addressMask = order.get("address_mask").getAsString(); + shopOrder.setAddressMask(addressMask); + + //售后状态 + int afterSalesStatus = order.get("after_sales_status").getAsInt(); + shopOrder.setAfterSalesStatus(afterSalesStatus); + + //买家留言信息 + String buyerMemo = order.get("buyer_memo").getAsString(); + shopOrder.setBuyerMemo(buyerMemo); + + //成交状态 + int confirmStatus = order.get("confirm_status").getAsInt(); + shopOrder.setConfirmStatus(confirmStatus); + + //成交时间 + String confirmTime = order.get("confirm_time").getAsString(); + shopOrder.setConfirmTime(confirmTime); + + //订单创建时间 + String createdTime = order.get("created_time").getAsString(); + shopOrder.setCreatedTime(createdTime); + + //是否当日发货: 1-是,0-否 + int deliveryOneDay = order.get("delivery_one_day").getAsInt(); + if (deliveryOneDay == 1){ + shopOrder.setDeliveryOneDay("是"); + } + if (deliveryOneDay == 0){ + shopOrder.setDeliveryOneDay("否"); + } + + //折扣金额 + double discountAmount = order.get("discount_amount").getAsDouble(); + shopOrder.setDiscountAmount(new BigDecimal(discountAmount)); + + //多多支付立减金额 + if (ObjectUtils.isNotEmpty(order.get("duo_duo_pay_reduction"))){ + double duoDuoPayReduction = order.get("duo_duo_pay_reduction").getAsDouble(); + shopOrder.setDuoDuoPayReduction(new BigDecimal(duoDuoPayReduction)); + } + + + //是否多多批发 + int duoduoWholesale = order.get("duoduo_wholesale").getAsInt(); + shopOrder.setDuoduoWholesale(duoduoWholesale); + + //商品金额 + double goodsAmount = order.get("goods_amount").getAsDouble(); + shopOrder.setGoodsAmount(new BigDecimal(goodsAmount)); + + //仓库编码 + if (ObjectUtils.isNotEmpty(order.get("depot_code"))){ + String depotCode = order.get("depot_code").getAsString(); + shopOrder.setDepotCode(depotCode); + } + + + //仓库信息 + if (ObjectUtils.isNotEmpty(order.get("order_depot_info"))){ + Object orderDepotInfo = order.get("order_depot_info"); + shopOrder.setOrderDepotInfo(String.valueOf(orderDepotInfo)); + } + + //仓库id + if (ObjectUtils.isNotEmpty(order.get("depot_id"))){ + long depotId = order.get("depot_id").getAsLong(); + shopOrder.setDepotId(String.valueOf(depotId)); + } + + //仓库名称 + if (ObjectUtils.isNotEmpty(order.get("depot_name"))){ + + String depotName = order.get("depot_name").getAsString(); + shopOrder.setDepotName(depotName); + } + + //仓库类型 + if (ObjectUtils.isNotEmpty(order.get("depot_type"))){ + int depotType = order.get("depot_type").getAsInt(); + shopOrder.setDepotType(depotType); + } + + //货品id + if (ObjectUtils.isNotEmpty(order.get("ware_id"))){ + long wareId = order.get("ware_id").getAsLong(); + shopOrder.setWareId(wareId); + } + + + //货品名称 + if (ObjectUtils.isNotEmpty(order.get("ware_name"))){ + String wareName = order.get("ware_name").getAsString(); + shopOrder.setWareName(wareName); + } + + + //货品编码 + if (ObjectUtils.isNotEmpty(order.get("ware_sn"))){ + String wareSn = order.get("ware_sn").getAsString(); + shopOrder.setWareSn(wareSn); + } + + + //货品类型 + if (ObjectUtils.isNotEmpty(order.get("ware_type"))){ + int wareType = order.get("ware_type").getAsInt(); + shopOrder.setWareType(wareType); + } + + + //订单状态 + int orderStatus = order.get("order_status").getAsInt(); + shopOrder.setOrderStatus(orderStatus); + + //支付金额 + double payAmount = order.get("pay_amount").getAsDouble(); + shopOrder.setPayAmount(new BigDecimal(payAmount)); + + //支付单号 + if (ObjectUtils.isNotEmpty(order.get("pay_no"))){ + String payNo = order.get("pay_no").getAsString(); + shopOrder.setPayNo(payNo); + } + + //支付时间 + String payTime = order.get("pay_time").getAsString(); + shopOrder.setPayTime(payTime); + + //支付方式 + String payType = order.get("pay_type").getAsString(); + shopOrder.setPayType(payType); + + //平台优惠金额 + double platformDiscount = order.get("platform_discount").getAsDouble(); + shopOrder.setPlatformDiscount(new BigDecimal(platformDiscount)); + + //邮费 + double postage = order.get("postage").getAsDouble(); + shopOrder.setPostage(new BigDecimal(postage)); + + //预售时间 + String preSaleTime = order.get("pre_sale_time").getAsString(); + shopOrder.setPreSaleTime(preSaleTime); + + //承诺送达时间 + if (ObjectUtils.isNotEmpty(order.get("promise_delivery_time"))){ + String promiseDeliveryTime = order.get("promise_delivery_time").getAsString(); + shopOrder.setPromiseDeliveryTime(promiseDeliveryTime); + } + + //省份 + String province = order.get("province").getAsString(); + shopOrder.setProvince(province); + + //省份编码 + String provinceId = order.get("province_id").getAsString(); + shopOrder.setProvinceId(provinceId); + + //确认收货时间 + if (ObjectUtils.isNotEmpty(order.get("receive_time"))){ + String receiveTime = order.get("receive_time").getAsString(); + shopOrder.setReceiveTime(receiveTime); + } + + //收件人地址 + String receiverAddress = order.get("receiver_address").getAsString(); + shopOrder.setReceiverAddress(receiverAddress); + + //收件人地址(打码) + String receiverAddressMask = order.get("receiver_address_mask").getAsString(); + shopOrder.setReceiverAddressMask(receiverAddressMask); + + //收件人姓名 + String receiverName = order.get("receiver_name").getAsString(); + shopOrder.setReceiverName(receiverName); + + //收件人姓名 + String receiverNameMask = order.get("receiver_name_mask").getAsString(); + shopOrder.setReceiverNameMask(receiverNameMask); + + //收件人手机号 + String receiverPhone = order.get("receiver_phone").getAsString(); + shopOrder.setReceiverPhone(receiverPhone); + + //收件人手机号(打码) + String receiverPhoneMask = order.get("receiver_phone_mask").getAsString(); + shopOrder.setReceiverPhoneMask(receiverPhoneMask); + + //售后状态 + int refundStatus = order.get("refund_status").getAsInt(); + shopOrder.setRefundStatus(refundStatus); + + //订单备注 + String remark = order.get("remark").getAsString(); + shopOrder.setRemark(remark); + + //订单备注标记 + if (ObjectUtils.isNotEmpty(order.get("remark_tag"))){ + String remarkTag = order.get("remark_tag").getAsString(); + String remarkTagColor; + switch (remarkTag) { + case "1": + remarkTagColor = "红色"; + break; + case "2": + remarkTagColor = "黄色"; + break; + case "3": + remarkTagColor = "绿色"; + break; + case "4": + remarkTagColor = "蓝色"; + break; + case "5": + remarkTagColor = "紫色"; + break; + default: + remarkTagColor = "未知颜色"; + break; + } + shopOrder.setRemarkTag(remarkTagColor); + } + + + //订单备注标记名称 + if (ObjectUtils.isNotEmpty(order.get("remark_tag_name"))) { + String remarkTagName = order.get("remark_tag_name").getAsString(); + shopOrder.setRemarkTagName(remarkTagName); + } + + //退货包运费 + Integer returnFreightPayer = order.get("return_freight_payer").getAsInt(); + shopOrder.setReturnFreightPayer(returnFreightPayer); + + //订单审核状态 + Integer riskControlStatus = order.get("risk_control_status").getAsInt(); + shopOrder.setRiskControlStatus(riskControlStatus); + + //是否门店自提 + Integer selfContained = order.get("self_contained").getAsInt(); + shopOrder.setSelfContained(selfContained); + + //商家优惠金额 + BigDecimal sellerDiscount = new BigDecimal(order.get("seller_discount").getAsString()); + shopOrder.setSellerDiscount(sellerDiscount); + + //缺货处理状态 + Integer stockOutHandleStatus = order.get("stock_out_handle_status").getAsInt(); + shopOrder.setStockOutHandleStatus(stockOutHandleStatus); + + //全国联保 + Integer supportNationwideWarranty = order.get("support_nationwide_warranty").getAsInt(); + shopOrder.setSupportNationwideWarranty(supportNationwideWarranty); + + //区,乡镇 + String town = order.get("town").getAsString(); + shopOrder.setTown(town); + + //区县编码 + String townId = order.get("town_id").getAsString(); + shopOrder.setTownId(townId); + + //快递单号 + String trackingNumber = order.get("tracking_number").getAsString(); + shopOrder.setTrackingNumber(trackingNumber); + + //以旧换新国家补贴金额 + if (ObjectUtils.isNotEmpty(order.get("trade_in_national_subsidy_amount"))){ + double tradeInNationalSubsidyAmount = order.get("trade_in_national_subsidy_amount").getAsDouble(); + shopOrder.setTradeInNationalSubsidyAmount(new BigDecimal(tradeInNationalSubsidyAmount)); + } + + //订单类型 + int tradeType = order.get("trade_type").getAsInt(); + shopOrder.setTradeType(tradeType); + + //订单的更新时间 + if (ObjectUtils.isNotEmpty(order.get("updated_at"))) { + String updatedAt = order.get("updated_at").getAsString(); + shopOrder.setUpdatedAt(updatedAt); + } + + + //催发货时间 + if (ObjectUtils.isNotEmpty(order.get("urge_shipping_time"))) { + String urgeShippingTime = order.get("urge_shipping_time").getAsString(); + shopOrder.setUrgeShippingTime(urgeShippingTime); + } + + + //预约配送日期 + if (ObjectUtils.isNotEmpty(order.get("yyps_date"))) { + String yypsDate = order.get("yyps_date").getAsString(); + shopOrder.setYypsDate(yypsDate); + } + + + //预约配送时段 + if (ObjectUtils.isNotEmpty(order.get("yyps_time"))) { + String yypsTime = order.get("yyps_time").getAsString(); + shopOrder.setYypsTime(yypsTime); + } + + + //合单ID2 + if (ObjectUtils.isNotEmpty(order.get("open_address_id2"))){ + String openAddressId2 = order.get("open_address_id2").getAsString(); + shopOrder.setOpenAddressId2(openAddressId2); + } + + //商品信息列表 + Object itemList = order.get("item_list"); + shopOrder.setItemList(String.valueOf(itemList)); + + + //店铺名称 + shopOrder.setShopName(orderVO.getShopName()); + //店铺id + shopOrder.setShopId(String.valueOf(orderVO.getMallId())); + + + //todo 租户编码写死 + shopOrder.setTenantId("000000"); + + if (ObjectUtils.isNotEmpty(shopOrder.getId())){ + shopOrderMapper.updateById(shopOrder); + }else { + shopOrderMapper.insert(shopOrder); + } + + JsonArray orderItemList = order.getAsJsonArray("item_list"); + + if (ObjectUtils.isNotEmpty(orderItemList)) { + //遍历商品详情 + for (JsonElement orderItem : orderItemList) { + JsonObject item = orderItem.getAsJsonObject(); + + QueryWrapper detailQueryWrapper = new QueryWrapper<>(); + detailQueryWrapper.eq("order_id", shopOrder.getId()); + TShopOrderDetail detail = shopOrderDetailMapper.selectOne(detailQueryWrapper); + + if (ObjectUtils.isEmpty(detail)) { + detail = new TShopOrderDetail(); + detail.setOrderId(shopOrder.getId()); + detail.setOrderSn(shopOrder.getOrderSn()); + } + + int goodsCount = item.get("goods_count").getAsInt(); + detail.setGoodsCount(goodsCount); + + String goodsId = item.get("goods_id").getAsString(); + detail.setGoodsId(goodsId); + + String goodsImg = item.get("goods_img").getAsString(); + detail.setGoodsImg(goodsImg); + + String goodsName = item.get("goods_name").getAsString(); + detail.setGoodsName(goodsName); + + double goodsPrice = item.get("goods_price").getAsDouble(); + detail.setGoodsPrice(new BigDecimal(goodsPrice)); + + String goodsSpec = item.get("goods_spec").getAsString(); + detail.setGoodsSpec(goodsSpec); + + String outerGoodsId = item.get("outer_goods_id").getAsString(); + detail.setOuterGoodsId(outerGoodsId); + + String outerId = item.get("outer_id").getAsString(); + detail.setOuterId(outerId); + + String skuId = item.get("sku_id").getAsString(); + detail.setSkuId(skuId); + + //店铺名称 + detail.setShopName(orderVO.getShopName()); + //店铺id + detail.setShopId(String.valueOf(orderVO.getMallId())); + + + //todo 租户编码写死 + detail.setTenantId("000000"); + + if (ObjectUtils.isEmpty(detail.getId())) { + shopOrderDetailMapper.insert(detail); + } else { + shopOrderDetailMapper.updateById(detail); + } + } + } + + } + + // 获取 has_next 字段 + boolean next = object.get("has_next").getAsBoolean(); + + if (next){ + orderVO.setPage(orderVO.getPage() + 1); + getConfirmOrderList(orderVO); + } + + + + + + + + + + } + + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/CatsGetJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/CatsGetJobExecutor.java new file mode 100644 index 0000000..5a86628 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/CatsGetJobExecutor.java @@ -0,0 +1,34 @@ +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.zhishu.service.IPddService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@JobExecutor(name = "catsGetJobExecutor") +public class CatsGetJobExecutor { + + @Autowired + public IPddService pddService; + + //todo 拿不到未支付订单 + //增量订单 (30分钟之内) + public ExecuteResult jobExecute(JobArgs jobArgs) throws Exception { + + //todo -获取图书类目导航栏信息 +// pddService.getCats(15543L); + + return ExecuteResult.success("-----获取图书类目导航栏信息-----"); + } + + + + + + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/GetOrderNowJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/GetOrderNowJobExecutor.java new file mode 100644 index 0000000..f3640f8 --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/GetOrderNowJobExecutor.java @@ -0,0 +1,40 @@ +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.common.core.utils.PddUtil; +import org.dromara.job.domains.ShopOrderVO; +import org.dromara.job.service.IPddService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@JobExecutor(name = "getOrderNowJobExecutor") +public class GetOrderNowJobExecutor { + + @Autowired + public IPddService pddService; + + //todo 拿不到未支付订单 + //增量订单 (30分钟之内) + public ExecuteResult jobExecute(JobArgs jobArgs) throws Exception { + + //todo 多店铺需要同步 + ShopOrderVO shopOrderVO = new ShopOrderVO(); + shopOrderVO.setMallId(146727039); + shopOrderVO.setShopName("古威教辅专营店"); + shopOrderVO.setAccessToken(PddUtil.getToken()); + + pddService.getNowOrderList(shopOrderVO); + + return ExecuteResult.success("-----增量订单同步成功-----"); + } + + + + + + +} diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java new file mode 100644 index 0000000..6f7c21f --- /dev/null +++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java @@ -0,0 +1,19 @@ +package org.dromara.job.snailjob; + +import com.aizuda.snailjob.client.job.core.dto.JobArgs; +import com.aizuda.snailjob.client.job.core.executor.AbstractJobExecutor; +import com.aizuda.snailjob.client.model.ExecuteResult; +import org.springframework.stereotype.Component; + +/** + * @author opensnail + * @date 2024-05-17 + */ +@Component +public class TestClassJobExecutor extends AbstractJobExecutor { + + @Override + protected ExecuteResult doJobExecute(JobArgs jobArgs) { + return ExecuteResult.success("TestJobExecutor测试成功"); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java new file mode 100644 index 0000000..6b7499a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java @@ -0,0 +1,55 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.system.domain.vo.CacheListInfoVo; +import lombok.RequiredArgsConstructor; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 缓存监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/cache") +public class CacheController { + + private final RedissonConnectionFactory connectionFactory; + + /** + * 获取缓存监控列表 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping() + public R getInfo() throws Exception { + RedisConnection connection = connectionFactory.getConnection(); + Properties commandStats = connection.commands().info("commandstats"); + + List> pieList = new ArrayList<>(); + if (commandStats != null) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + } + + CacheListInfoVo infoVo = new CacheListInfoVo(); + infoVo.setInfo(connection.commands().info()); + infoVo.setDbSize(connection.commands().dbSize()); + infoVo.setCommandStats(pieList); + return R.ok(infoVo); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java new file mode 100644 index 0000000..98ac2d5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java @@ -0,0 +1,89 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +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.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysLogininforBo; +import org.dromara.system.domain.vo.SysLogininforVo; +import org.dromara.system.service.ISysLogininforService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 系统访问记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/logininfor") +public class SysLogininforController extends BaseController { + + private final ISysLogininforService logininforService; + + /** + * 获取系统访问记录列表 + */ + @SaCheckPermission("monitor:logininfor:list") + @GetMapping("/list") + public TableDataInfo list(SysLogininforBo logininfor, PageQuery pageQuery) { + return logininforService.selectPageLogininforList(logininfor, pageQuery); + } + + /** + * 导出系统访问记录列表 + */ + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:logininfor:export") + @PostMapping("/export") + public void export(SysLogininforBo logininfor, HttpServletResponse response) { + List list = logininforService.selectLogininforList(logininfor); + ExcelUtil.exportExcel(list, "登录日志", SysLogininforVo.class, response); + } + + /** + * 批量删除登录日志 + * @param infoIds 日志ids + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public R remove(@PathVariable Long[] infoIds) { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + + /** + * 清理系统访问记录 + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public R clean() { + logininforService.cleanLogininfor(); + return R.ok(); + } + + @SaCheckPermission("monitor:logininfor:unlock") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public R unlock(@PathVariable("userName") String userName) { + String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName; + if (RedisUtils.hasKey(loginName)) { + RedisUtils.deleteObject(loginName); + } + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000..1cab232 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,131 @@ +package org.dromara.system.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.dto.UserOnlineDTO; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysUserOnline; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 在线用户监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController { + + /** + * 获取在线用户监控列表 + * + * @param ipaddr IP地址 + * @param userName 用户名 + */ + @SaCheckPermission("monitor:online:list") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) { + // 获取所有未过期的 token + Collection keys = RedisUtils.keys(CacheConstants.ONLINE_TOKEN_KEY + "*"); + List userOnlineDTOList = new ArrayList<>(); + for (String key : keys) { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) { + continue; + } + userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)); + } + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) && + StringUtils.equals(userName, userOnline.getUserName()) + ); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) + ); + } else if (StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(userName, userOnline.getUserName()) + ); + } + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + + /** + * 强退用户 + * + * @param tokenId token值 + */ + @SaCheckPermission("monitor:online:forceLogout") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public R forceLogout(@PathVariable String tokenId) { + try { + StpUtil.kickoutByTokenValue(tokenId); + } catch (NotLoginException ignored) { + } + return R.ok(); + } + + /** + * 获取当前用户登录在线设备 + */ + @GetMapping() + public TableDataInfo getInfo() { + // 获取指定账号 id 的 token 集合 + List tokenIds = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + List userOnlineDTOList = tokenIds.stream() + .filter(token -> StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) >= -1) + .map(token -> (UserOnlineDTO) RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)) + .collect(Collectors.toList()); + //复制和处理 SysUserOnline 对象列表 + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + + /** + * 强退当前在线设备 + * + * @param tokenId token值 + */ + @Log(title = "在线设备", businessType = BusinessType.FORCE) + @DeleteMapping("/myself/{tokenId}") + public R remove(@PathVariable("tokenId") String tokenId) { + try { + // 获取指定账号 id 的 token 集合 + List keys = StpUtil.getTokenValueListByLoginId(StpUtil.getLoginIdAsString()); + keys.stream() + .filter(key -> key.equals(tokenId)) + .findFirst() + .ifPresent(key -> StpUtil.kickoutByTokenValue(tokenId)); + } catch (NotLoginException ignored) { + } + return R.ok(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java new file mode 100644 index 0000000..eaed068 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java @@ -0,0 +1,115 @@ +package org.dromara.system.controller.system; + +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.system.domain.vo.SysClientVo; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.system.service.ISysClientService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 客户端管理 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/client") +public class SysClientController extends BaseController { + + private final ISysClientService sysClientService; + + /** + * 查询客户端管理列表 + */ + @SaCheckPermission("system:client:list") + @GetMapping("/list") + public TableDataInfo list(SysClientBo bo, PageQuery pageQuery) { + return sysClientService.queryPageList(bo, pageQuery); + } + + /** + * 导出客户端管理列表 + */ + @SaCheckPermission("system:client:export") + @Log(title = "客户端管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysClientBo bo, HttpServletResponse response) { + List list = sysClientService.queryList(bo); + ExcelUtil.exportExcel(list, "客户端管理", SysClientVo.class, response); + } + + /** + * 获取客户端管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:client:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(sysClientService.queryById(id)); + } + + /** + * 新增客户端管理 + */ + @SaCheckPermission("system:client:add") + @Log(title = "客户端管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysClientBo bo) { + return toAjax(sysClientService.insertByBo(bo)); + } + + /** + * 修改客户端管理 + */ + @SaCheckPermission("system:client:edit") + @Log(title = "客户端管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysClientBo bo) { + return toAjax(sysClientService.updateByBo(bo)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:client:edit") + @Log(title = "客户端管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysClientBo bo) { + return toAjax(sysClientService.updateClientStatus(bo.getClientId(), bo.getStatus())); + } + + /** + * 删除客户端管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:client:remove") + @Log(title = "客户端管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(sysClientService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java new file mode 100644 index 0000000..c73c386 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java @@ -0,0 +1,137 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +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.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; +import org.dromara.system.service.ISysConfigService; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 参数配置 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController { + + private final ISysConfigService configService; + + /** + * 获取参数配置列表 + */ + @SaCheckPermission("system:config:list") + @GetMapping("/list") + public TableDataInfo list(SysConfigBo config, PageQuery pageQuery) { + return configService.selectPageConfigList(config, pageQuery); + } + + /** + * 导出参数配置列表 + */ + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:config:export") + @PostMapping("/export") + public void export(SysConfigBo config, HttpServletResponse response) { + List list = configService.selectConfigList(config); + ExcelUtil.exportExcel(list, "参数数据", SysConfigVo.class, response); + } + + /** + * 根据参数编号获取详细信息 + * + * @param configId 参数ID + */ + @SaCheckPermission("system:config:query") + @GetMapping(value = "/{configId}") + public R getInfo(@PathVariable Long configId) { + return R.ok(configService.selectConfigById(configId)); + } + + /** + * 根据参数键名查询参数值 + * + * @param configKey 参数Key + */ + @GetMapping(value = "/configKey/{configKey}") + public R getConfigKey(@PathVariable String configKey) { + return R.ok("操作成功", configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置 + */ + @SaCheckPermission("system:config:add") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysConfigBo config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.insertConfig(config); + return R.ok(); + } + + /** + * 修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysConfigBo config) { + if (!configService.checkConfigKeyUnique(config)) { + return R.fail("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.updateConfig(config); + return R.ok(); + } + + /** + * 根据参数键名修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping("/updateByKey") + public R updateByKey(@RequestBody SysConfigBo config) { + configService.updateConfig(config); + return R.ok(); + } + + /** + * 删除参数配置 + * + * @param configIds 参数ID串 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public R remove(@PathVariable Long[] configIds) { + configService.deleteConfigByIds(configIds); + return R.ok(); + } + + /** + * 刷新参数缓存 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + configService.resetConfigCache(); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java new file mode 100644 index 0000000..45b8418 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java @@ -0,0 +1,140 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysPostService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 部门信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController { + + private final ISysDeptService deptService; + private final ISysPostService postService; + + /** + * 获取部门列表 + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list") + public R> list(SysDeptBo dept) { + List depts = deptService.selectDeptList(dept); + return R.ok(depts); + } + + /** + * 查询部门列表(排除节点) + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list/exclude/{deptId}") + public R> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) { + List depts = deptService.selectDeptList(new SysDeptBo()); + depts.removeIf(d -> d.getDeptId().equals(deptId) + || StringUtils.splitList(d.getAncestors()).contains(Convert.toStr(deptId))); + return R.ok(depts); + } + + /** + * 根据部门编号获取详细信息 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:query") + @GetMapping(value = "/{deptId}") + public R getInfo(@PathVariable Long deptId) { + deptService.checkDeptDataScope(deptId); + return R.ok(deptService.selectDeptById(deptId)); + } + + /** + * 新增部门 + */ + @SaCheckPermission("system:dept:add") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDeptBo dept) { + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门 + */ + @SaCheckPermission("system:dept:edit") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDeptBo dept) { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } else if (dept.getParentId().equals(deptId)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } else if (StringUtils.equals(SystemConstants.DISABLE, dept.getStatus())) { + if (deptService.selectNormalChildrenDeptById(deptId) > 0) { + return R.fail("该部门包含未停用的子部门!"); + } else if (deptService.checkDeptExistUser(deptId)) { + return R.fail("该部门下存在已分配用户,不能禁用!"); + } + } + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:remove") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public R remove(@PathVariable Long deptId) { + if (deptService.hasChildByDeptId(deptId)) { + return R.warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) { + return R.warn("部门存在用户,不允许删除"); + } + if (postService.countPostByDeptId(deptId) > 0) { + return R.warn("部门存在岗位,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } + + /** + * 获取部门选择框列表 + * + * @param deptIds 部门ID串 + */ + @SaCheckPermission("system:dept:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] deptIds) { + return R.ok(deptService.selectDeptByIds(deptIds == null ? null : List.of(deptIds))); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java new file mode 100644 index 0000000..5752751 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java @@ -0,0 +1,123 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +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.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.system.service.ISysDictTypeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import jakarta.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController { + + private final ISysDictDataService dictDataService; + private final ISysDictTypeService dictTypeService; + + /** + * 查询字典数据列表 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictDataBo dictData, PageQuery pageQuery) { + return dictDataService.selectPageDictDataList(dictData, pageQuery); + } + + /** + * 导出字典数据列表 + */ + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictDataBo dictData, HttpServletResponse response) { + List list = dictDataService.selectDictDataList(dictData); + ExcelUtil.exportExcel(list, "字典数据", SysDictDataVo.class, response); + } + + /** + * 查询字典数据详细 + * + * @param dictCode 字典code + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictCode}") + public R getInfo(@PathVariable Long dictCode) { + return R.ok(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 根据字典类型查询字典数据信息 + * + * @param dictType 字典类型 + */ + @GetMapping(value = "/type/{dictType}") + public R> dictType(@PathVariable String dictType) { + List data = dictTypeService.selectDictDataByType(dictType); + if (ObjectUtil.isNull(data)) { + data = new ArrayList<>(); + } + return R.ok(data); + } + + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictDataBo dict) { + if (!dictDataService.checkDictDataUnique(dict)) { + return R.fail("新增字典数据'" + dict.getDictValue() + "'失败,字典键值已存在"); + } + dictDataService.insertDictData(dict); + return R.ok(); + } + + /** + * 修改保存字典类型 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictDataBo dict) { + if (!dictDataService.checkDictDataUnique(dict)) { + return R.fail("修改字典数据'" + dict.getDictValue() + "'失败,字典键值已存在"); + } + dictDataService.updateDictData(dict); + return R.ok(); + } + + /** + * 删除字典类型 + * + * @param dictCodes 字典code串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public R remove(@PathVariable Long[] dictCodes) { + dictDataService.deleteDictDataByIds(dictCodes); + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java new file mode 100644 index 0000000..67c1f51 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java @@ -0,0 +1,125 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +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.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictTypeVo; +import org.dromara.system.service.ISysDictTypeService; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController { + + private final ISysDictTypeService dictTypeService; + + /** + * 查询字典类型列表 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictTypeBo dictType, PageQuery pageQuery) { + return dictTypeService.selectPageDictTypeList(dictType, pageQuery); + } + + /** + * 导出字典类型列表 + */ + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictTypeBo dictType, HttpServletResponse response) { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil.exportExcel(list, "字典类型", SysDictTypeVo.class, response); + } + + /** + * 查询字典类型详细 + * + * @param dictId 字典ID + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictId}") + public R getInfo(@PathVariable Long dictId) { + return R.ok(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictTypeBo dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.insertDictType(dict); + return R.ok(); + } + + /** + * 修改字典类型 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictTypeBo dict) { + if (!dictTypeService.checkDictTypeUnique(dict)) { + return R.fail("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.updateDictType(dict); + return R.ok(); + } + + /** + * 删除字典类型 + * + * @param dictIds 字典ID串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public R remove(@PathVariable Long[] dictIds) { + dictTypeService.deleteDictTypeByIds(dictIds); + return R.ok(); + } + + /** + * 刷新字典缓存 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + dictTypeService.resetDictCache(); + return R.ok(); + } + + /** + * 获取字典选择框列表 + */ + @GetMapping("/optionselect") + public R> optionselect() { + List dictTypes = dictTypeService.selectDictTypeAll(); + return R.ok(dictTypes); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java new file mode 100644 index 0000000..c53e366 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java @@ -0,0 +1,178 @@ +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 cn.hutool.core.lang.tree.Tree; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.MenuTreeSelectVo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; +import org.dromara.system.service.ISysMenuService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 菜单信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + + private final ISysMenuService menuService; + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("/getRouters") + public R> getRouters() { + List menus = menuService.selectMenuTreeByUserId(LoginHelper.getUserId()); + return R.ok(menuService.buildMenus(menus)); + } + + /** + * 获取菜单列表 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + TenantConstants.TENANT_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:menu:list") + @GetMapping("/list") + public R> list(SysMenuBo menu) { + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); + return R.ok(menus); + } + + /** + * 根据菜单编号获取详细信息 + * + * @param menuId 菜单ID + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + TenantConstants.TENANT_ADMIN_ROLE_KEY + }, mode = SaMode.OR) + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/{menuId}") + public R getInfo(@PathVariable Long menuId) { + return R.ok(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表 + */ + @SaCheckPermission("system:menu:query") + @GetMapping("/treeselect") + public R>> treeselect(SysMenuBo menu) { + List menus = menuService.selectMenuList(menu, LoginHelper.getUserId()); + return R.ok(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public R roleMenuTreeselect(@PathVariable("roleId") Long roleId) { + List menus = menuService.selectMenuList(LoginHelper.getUserId()); + MenuTreeSelectVo selectVo = new MenuTreeSelectVo(); + selectVo.setCheckedKeys(menuService.selectMenuListByRoleId(roleId)); + selectVo.setMenus(menuService.buildMenuTreeSelect(menus)); + return R.ok(selectVo); + } + + /** + * 加载对应租户套餐菜单列表树 + * + * @param packageId 租户套餐ID + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/tenantPackageMenuTreeselect/{packageId}") + public R tenantPackageMenuTreeselect(@PathVariable("packageId") Long packageId) { + List menus = menuService.selectMenuList(LoginHelper.getUserId()); + MenuTreeSelectVo selectVo = new MenuTreeSelectVo(); + selectVo.setCheckedKeys(menuService.selectMenuListByPackageId(packageId)); + selectVo.setMenus(menuService.buildMenuTreeSelect(menus)); + return R.ok(selectVo); + } + + /** + * 新增菜单 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:add") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysMenuBo menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:edit") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysMenuBo menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (menu.getMenuId().equals(menu.getParentId())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + * + * @param menuId 菜单ID + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @SaCheckPermission("system:menu:remove") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public R remove(@PathVariable("menuId") Long menuId) { + if (menuService.hasChildByMenuId(menuId)) { + return R.warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) { + return R.warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java new file mode 100644 index 0000000..5d65137 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java @@ -0,0 +1,90 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.service.DictService; +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.sse.utils.SseMessageUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; +import org.dromara.system.service.ISysNoticeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 公告 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController { + + private final ISysNoticeService noticeService; + private final DictService dictService; + + /** + * 获取通知公告列表 + */ + @SaCheckPermission("system:notice:list") + @GetMapping("/list") + public TableDataInfo list(SysNoticeBo notice, PageQuery pageQuery) { + return noticeService.selectPageNoticeList(notice, pageQuery); + } + + /** + * 根据通知公告编号获取详细信息 + * + * @param noticeId 公告ID + */ + @SaCheckPermission("system:notice:query") + @GetMapping(value = "/{noticeId}") + public R getInfo(@PathVariable Long noticeId) { + return R.ok(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告 + */ + @SaCheckPermission("system:notice:add") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysNoticeBo notice) { + int rows = noticeService.insertNotice(notice); + if (rows <= 0) { + return R.fail(); + } + String type = dictService.getDictLabel("sys_notice_type", notice.getNoticeType()); + SseMessageUtils.publishAll("[" + type + "] " + notice.getNoticeTitle()); + return R.ok(); + } + + /** + * 修改通知公告 + */ + @SaCheckPermission("system:notice:edit") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysNoticeBo notice) { + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + * + * @param noticeIds 公告ID串 + */ + @SaCheckPermission("system:notice:remove") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public R remove(@PathVariable Long[] noticeIds) { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java new file mode 100644 index 0000000..24ddaff --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java @@ -0,0 +1,105 @@ +package org.dromara.system.controller.system; + +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.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.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; +import org.dromara.system.service.ISysOssConfigService; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 对象存储配置 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/resource/oss/config") +public class SysOssConfigController extends BaseController { + + private final ISysOssConfigService ossConfigService; + + /** + * 查询对象存储配置列表 + */ + @SaCheckPermission("system:ossConfig:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) { + return ossConfigService.queryPageList(bo, pageQuery); + } + + /** + * 获取对象存储配置详细信息 + * + * @param ossConfigId OSS配置ID + */ + @SaCheckPermission("system:ossConfig:list") + @GetMapping("/{ossConfigId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long ossConfigId) { + return R.ok(ossConfigService.queryById(ossConfigId)); + } + + /** + * 新增对象存储配置 + */ + @SaCheckPermission("system:ossConfig:add") + @Log(title = "对象存储配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.insertByBo(bo)); + } + + /** + * 修改对象存储配置 + */ + @SaCheckPermission("system:ossConfig:edit") + @Log(title = "对象存储配置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.updateByBo(bo)); + } + + /** + * 删除对象存储配置 + * + * @param ossConfigIds OSS配置ID串 + */ + @SaCheckPermission("system:ossConfig:remove") + @Log(title = "对象存储配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossConfigIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossConfigIds) { + return toAjax(ossConfigService.deleteWithValidByIds(List.of(ossConfigIds), true)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:ossConfig:edit") + @Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysOssConfigBo bo) { + return toAjax(ossConfigService.updateOssConfigStatus(bo)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java new file mode 100644 index 0000000..81200c1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java @@ -0,0 +1,108 @@ +package org.dromara.system.controller.system; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.QueryGroup; +import org.dromara.common.web.core.BaseController; +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.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssUploadVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +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 java.io.IOException; +import java.util.Arrays; +import java.util.List; + +/** + * 文件上传 控制层 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/resource/oss") +public class SysOssController extends BaseController { + + private final ISysOssService ossService; + + /** + * 查询OSS对象存储列表 + */ + @SaCheckPermission("system:oss:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) { + return ossService.queryPageList(bo, pageQuery); + } + + /** + * 查询OSS对象基于id串 + * + * @param ossIds OSS对象ID串 + */ + @SaCheckPermission("system:oss:query") + @GetMapping("/listByIds/{ossIds}") + public R> listByIds(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + List list = ossService.listByIds(Arrays.asList(ossIds)); + return R.ok(list); + } + + /** + * 上传OSS对象存储 + * + * @param file 文件 + */ + @SaCheckPermission("system:oss:upload") + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) + @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R upload(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + SysOssVo oss = ossService.upload(file); + SysOssUploadVo uploadVo = new SysOssUploadVo(); + uploadVo.setUrl(oss.getUrl()); + uploadVo.setFileName(oss.getOriginalName()); + uploadVo.setOssId(oss.getOssId().toString()); + return R.ok(uploadVo); + } + + /** + * 下载OSS对象 + * + * @param ossId OSS对象ID + */ + @SaCheckPermission("system:oss:download") + @GetMapping("/download/{ossId}") + public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException { + ossService.download(ossId, response); + } + + /** + * 删除OSS对象存储 + * + * @param ossIds OSS对象ID串 + */ + @SaCheckPermission("system:oss:remove") + @Log(title = "OSS对象存储", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + return toAjax(ossService.deleteWithValidByIds(List.of(ossIds), true)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java new file mode 100644 index 0000000..5333a4a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java @@ -0,0 +1,133 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +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.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.service.ISysPostService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController { + + private final ISysPostService postService; + + /** + * 获取岗位列表 + */ + @SaCheckPermission("system:post:list") + @GetMapping("/list") + public TableDataInfo list(SysPostBo post, PageQuery pageQuery) { + return postService.selectPagePostList(post, pageQuery); + } + + /** + * 导出岗位列表 + */ + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:post:export") + @PostMapping("/export") + public void export(SysPostBo post, HttpServletResponse response) { + List list = postService.selectPostList(post); + ExcelUtil.exportExcel(list, "岗位数据", SysPostVo.class, response); + } + + /** + * 根据岗位编号获取详细信息 + * + * @param postId 岗位ID + */ + @SaCheckPermission("system:post:query") + @GetMapping(value = "/{postId}") + public R getInfo(@PathVariable Long postId) { + return R.ok(postService.selectPostById(postId)); + } + + /** + * 新增岗位 + */ + @SaCheckPermission("system:post:add") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysPostBo post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位 + */ + @SaCheckPermission("system:post:edit") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysPostBo post) { + if (!postService.checkPostNameUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (!postService.checkPostCodeUnique(post)) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } else if (SystemConstants.DISABLE.equals(post.getStatus()) + && postService.countUserPostById(post.getPostId()) > 0) { + return R.fail("该岗位下存在已分配用户,不能禁用!"); + } + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + * + * @param postIds 岗位ID串 + */ + @SaCheckPermission("system:post:remove") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public R remove(@PathVariable Long[] postIds) { + return toAjax(postService.deletePostByIds(postIds)); + } + + /** + * 获取岗位选择框列表 + * + * @param postIds 岗位ID串 + * @param deptId 部门id + */ + @SaCheckPermission("system:post:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] postIds, @RequestParam(required = false) Long deptId) { + List list = new ArrayList<>(); + if (ObjectUtil.isNotNull(deptId)) { + SysPostBo post = new SysPostBo(); + post.setDeptId(deptId); + list = postService.selectPostList(post); + } else if (postIds != null) { + list = postService.selectPostByIds(List.of(postIds)); + } + return R.ok(list); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java new file mode 100644 index 0000000..9a85b5a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java @@ -0,0 +1,137 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.io.FileUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.MimeTypeUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +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.helper.DataPermissionHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.bo.SysUserPasswordBo; +import org.dromara.system.domain.bo.SysUserProfileBo; +import org.dromara.system.domain.vo.AvatarVo; +import org.dromara.system.domain.vo.ProfileVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysOssService; +import org.dromara.system.service.ISysUserService; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Arrays; + +/** + * 个人信息 业务处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController { + + private final ISysUserService userService; + private final ISysOssService ossService; + + /** + * 个人信息 + */ + @GetMapping + public R profile() { + SysUserVo user = userService.selectUserById(LoginHelper.getUserId()); + ProfileVo profileVo = new ProfileVo(); + profileVo.setUser(user); + profileVo.setRoleGroup(userService.selectUserRoleGroup(user.getUserId())); + profileVo.setPostGroup(userService.selectUserPostGroup(user.getUserId())); + LoginUser loginUser = LoginHelper.getLoginUser(); + profileVo.setWarehouseLoginUser(loginUser.getWarehouseLoginUser()); + return R.ok(profileVo); + } + + + /** + * 修改用户信息 + */ + @RepeatSubmit + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public R updateProfile(@Validated @RequestBody SysUserProfileBo profile) { + SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class); + user.setUserId(LoginHelper.getUserId()); + String username = LoginHelper.getUsername(); + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + username + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + username + "'失败,邮箱账号已存在"); + } + int rows = DataPermissionHelper.ignore(() -> userService.updateUserProfile(user)); + if (rows > 0) { + return R.ok(); + } + return R.fail("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + * + * @param bo 新旧密码 + */ + @RepeatSubmit + @ApiEncrypt + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public R updatePwd(@Validated @RequestBody SysUserPasswordBo bo) { + SysUserVo user = userService.selectUserById(LoginHelper.getUserId()); + String password = user.getPassword(); + if (!BCrypt.checkpw(bo.getOldPassword(), password)) { + return R.fail("修改密码失败,旧密码错误"); + } + if (BCrypt.checkpw(bo.getNewPassword(), password)) { + return R.fail("新密码不能与旧密码相同"); + } + int rows = DataPermissionHelper.ignore(() -> userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(bo.getNewPassword()))); + if (rows > 0) { + return R.ok(); + } + return R.fail("修改密码异常,请联系管理员"); + } + + /** + * 头像上传 + * + * @param avatarfile 用户头像 + */ + @RepeatSubmit + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R avatar(@RequestPart("avatarfile") MultipartFile avatarfile) { + if (!avatarfile.isEmpty()) { + String extension = FileUtil.extName(avatarfile.getOriginalFilename()); + if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) { + return R.fail("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式"); + } + SysOssVo oss = ossService.upload(avatarfile); + String avatar = oss.getUrl(); + boolean updateSuccess = DataPermissionHelper.ignore(() -> userService.updateUserAvatar(LoginHelper.getUserId(), oss.getOssId())); + if (updateSuccess) { + AvatarVo avatarVo = new AvatarVo(); + avatarVo.setImgUrl(avatar); + return R.ok(avatarVo); + } + } + return R.fail("上传图片异常,请联系管理员"); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java new file mode 100644 index 0000000..d4a9dc8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java @@ -0,0 +1,229 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +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.SysUserRole; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.DeptTreeSelectVo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysDeptService; +import org.dromara.system.service.ISysRoleService; +import org.dromara.system.service.ISysUserService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 角色信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController { + + private final ISysRoleService roleService; + private final ISysUserService userService; + private final ISysDeptService deptService; + + /** + * 获取角色信息列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/list") + public TableDataInfo list(SysRoleBo role, PageQuery pageQuery) { + return roleService.selectPageRoleList(role, pageQuery); + } + + /** + * 导出角色信息列表 + */ + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:role:export") + @PostMapping("/export") + public void export(SysRoleBo role, HttpServletResponse response) { + List list = roleService.selectRoleList(role); + ExcelUtil.exportExcel(list, "角色数据", SysRoleVo.class, response); + } + + /** + * 根据角色编号获取详细信息 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:query") + @GetMapping(value = "/{roleId}") + public R getInfo(@PathVariable Long roleId) { + roleService.checkRoleDataScope(roleId); + return R.ok(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色 + */ + @SaCheckPermission("system:role:add") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + return toAjax(roleService.insertRole(role)); + + } + + /** + * 修改保存角色 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (!roleService.checkRoleKeyUnique(role)) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + + if (roleService.updateRole(role) > 0) { + roleService.cleanOnlineUserByRole(role.getRoleId()); + return R.ok(); + } + return R.fail("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + + /** + * 修改保存数据权限 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public R dataScope(@RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysRoleBo role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.updateRoleStatus(role.getRoleId(), role.getStatus())); + } + + /** + * 删除角色 + * + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:role:remove") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public R remove(@PathVariable Long[] roleIds) { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + + /** + * 获取角色选择框列表 + * + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:role:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] roleIds) { + return R.ok(roleService.selectRoleByIds(roleIds == null ? null : List.of(roleIds))); + } + + /** + * 查询已分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUserBo user, PageQuery pageQuery) { + return userService.selectAllocatedList(user, pageQuery); + } + + /** + * 查询未分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUserBo user, PageQuery pageQuery) { + return userService.selectUnallocatedList(user, pageQuery); + } + + /** + * 取消授权用户 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public R cancelAuthUser(@RequestBody SysUserRole userRole) { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public R cancelAuthUserAll(Long roleId, Long[] userIds) { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 批量选择用户授权 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public R selectAuthUserAll(Long roleId, Long[] userIds) { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + + /** + * 获取对应角色部门树列表 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:list") + @GetMapping(value = "/deptTree/{roleId}") + public R roleDeptTreeselect(@PathVariable("roleId") Long roleId) { + DeptTreeSelectVo selectVo = new DeptTreeSelectVo(); + selectVo.setCheckedKeys(deptService.selectDeptListByRoleId(roleId)); + selectVo.setDepts(deptService.selectDeptTreeList(new SysDeptBo())); + return R.ok(selectVo); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java new file mode 100644 index 0000000..d7e023b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java @@ -0,0 +1,218 @@ +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 com.baomidou.lock.annotation.Lock4j; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +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.encrypt.annotation.ApiEncrypt; +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.tenant.helper.TenantHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.service.ISysTenantService; +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") +@ConditionalOnProperty(value = "tenant.enable", havingValue = "true") +public class SysTenantController extends BaseController { + + private final ISysTenantService tenantService; + + /** + * 查询租户列表 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:list") + @GetMapping("/list") + public TableDataInfo list(SysTenantBo bo, PageQuery pageQuery) { + return tenantService.queryPageList(bo, pageQuery); + } + + /** + * 导出租户列表 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:export") + @Log(title = "租户管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SysTenantBo bo, HttpServletResponse response) { + List list = tenantService.queryList(bo); + ExcelUtil.exportExcel(list, "租户", SysTenantVo.class, response); + } + + /** + * 获取租户详细信息 + * + * @param id 主键 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tenantService.queryById(id)); + } + + /** + * 新增租户 + */ + @ApiEncrypt + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:add") + @Log(title = "租户管理", businessType = BusinessType.INSERT) + @Lock4j + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysTenantBo bo) { + if (!tenantService.checkCompanyNameUnique(bo)) { + return R.fail("新增租户'" + bo.getCompanyName() + "'失败,企业名称已存在"); + } + return toAjax(TenantHelper.ignore(() -> tenantService.insertByBo(bo))); + } + + /** + * 修改租户 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:edit") + @Log(title = "租户管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysTenantBo bo) { + tenantService.checkTenantAllowed(bo.getTenantId()); + if (!tenantService.checkCompanyNameUnique(bo)) { + return R.fail("修改租户'" + bo.getCompanyName() + "'失败,公司名称已存在"); + } + return toAjax(tenantService.updateByBo(bo)); + } + + /** + * 状态修改 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:edit") + @Log(title = "租户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysTenantBo bo) { + tenantService.checkTenantAllowed(bo.getTenantId()); + return toAjax(tenantService.updateTenantStatus(bo)); + } + + /** + * 删除租户 + * + * @param ids 主键串 + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:remove") + @Log(title = "租户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tenantService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 动态切换租户 + * + * @param tenantId 租户ID + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @GetMapping("/dynamic/{tenantId}") + public R dynamicTenant(@NotBlank(message = "租户ID不能为空") @PathVariable String tenantId) { + TenantHelper.setDynamic(tenantId, true); + return R.ok(); + } + + /** + * 清除动态租户 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @GetMapping("/dynamic/clear") + public R dynamicClear() { + TenantHelper.clearDynamic(); + return R.ok(); + } + + + /** + * 同步租户套餐 + * + * @param tenantId 租户id + * @param packageId 套餐id + */ + @SaCheckRole(value = { + TenantConstants.SUPER_ADMIN_ROLE_KEY, + "Settled" + }, mode = SaMode.OR) + @SaCheckPermission("system:tenant:edit") + @Log(title = "租户管理", businessType = BusinessType.UPDATE) + @GetMapping("/syncTenantPackage") + public R syncTenantPackage(@NotBlank(message = "租户ID不能为空") String tenantId, + @NotNull(message = "套餐ID不能为空") Long packageId) { + return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId))); + } + + /** + * 同步租户字典 + */ + @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY) + @Log(title = "租户管理", businessType = BusinessType.INSERT) + @GetMapping("/syncTenantDict") + public R syncTenantDict() { + if (!TenantHelper.isEnable()) { + return R.fail("当前未开启租户模式"); + } + tenantService.syncTenantDict(); + return R.ok("同步租户字典成功"); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserBalanceController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserBalanceController.java new file mode 100644 index 0000000..1602cfb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserBalanceController.java @@ -0,0 +1,47 @@ +package org.dromara.system.controller.system; + + + +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; + +import lombok.RequiredArgsConstructor; +import org.dromara.system.service.IUserTransferService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + + + +@Validated +@RestController +@RequestMapping("/system/user/balance") +@RequiredArgsConstructor +public class SysUserBalanceController { + + private final IUserTransferService sysUserService; + + /** + * 余额转冻结 + */ + @PostMapping("/transfer/balanceToFreeze") + @SaIgnore + public R balanceToFreeze(@NotNull(message = "转出用户ID不能为空") Long fromUserId, + @NotNull(message = "转入用户ID不能为空") Long toUserId, + @NotNull(message = "金额不能为空") Long amount) { + boolean result = sysUserService.transferBalanceToFreeze(fromUserId, toUserId, amount); + return result ? R.ok("转账成功") : R.fail("转账失败"); + } + + /** + * 冻结转余额 + */ + @PostMapping("/transfer/freezeToBalance") + @SaIgnore + public R freezeToBalance(@NotNull(message = "转出用户ID不能为空") Long fromUserId, + @NotNull(message = "转入用户ID不能为空") Long toUserId, + @NotNull(message = "金额不能为空") Long amount) { + boolean result = sysUserService.transferFreezeToBalance(fromUserId, toUserId, amount); + return result ? R.ok("转账成功") : R.fail("转账失败"); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java new file mode 100644 index 0000000..f9d39ad --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java @@ -0,0 +1,339 @@ +package org.dromara.system.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +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.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.*; +import org.dromara.system.listener.SysUserImportListener; +import org.dromara.system.service.*; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.*; + +/** + * 用户信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController { + + private final ISysUserService userService; + private final ISysRoleService roleService; + private final ISysPostService postService; + private final ISysDeptService deptService; + private final ISysTenantService tenantService; + + /** + * 获取用户列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list") + public TableDataInfo list(SysUserBo user, PageQuery pageQuery) { + return userService.selectPageUserList(user, pageQuery); + } + + @GetMapping("/getUserWarehouseNameList") + public Map getUserWarehouseNameList(){ + Long userId = LoginHelper.getUserId(); + Map map = new HashMap(); + map.put("u",userId); + map.put("warehouseNameList",userService.selectUserWarehouseNameList()); + return map; + } + + /** + * 获取当前登录用户的自营仓库名称 + * @return + */ + @GetMapping("/getUserWarehouseName") + public Map getUserWarehouseName(){ + SysUserVo vo = userService.selectUserById(LoginHelper.getUserId()); + Map map = new HashMap(); + map.put("code",200); + if(StringUtils.isNotEmpty(vo.getWarehouseName())){ + map.put("userWarehouseName",vo.getWarehouseName()); + }else{ + map.put("userWarehouseName",""); + map.put("markName","默认仓库名称"+ UUID.randomUUID()); + } + return map; + } + + @PutMapping("/editUserWarehouseName") + public Map editUserWarehouseName(String warehouseName){ + Map map = new HashMap(); + SysUserBo bo = new SysUserBo(); + bo.setUserId(LoginHelper.getUserId()); + bo.setWarehouseName(warehouseName); + userService.updateUser(bo); + map.put("code",200); + map.put("msg","设置成功,仓库名称:"+warehouseName); + return map; + } + + /** + * 导出用户列表 + */ + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:user:export") + @PostMapping("/export") + public void export(SysUserBo user, HttpServletResponse response) { + List list = userService.selectUserExportList(user); + ExcelUtil.exportExcel(list, "用户数据", SysUserExportVo.class, response); + } + + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:user:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { + ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport)); + return R.ok(result.getAnalysis()); + } + + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response); + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("/getInfo") + public R getInfo() { + UserInfoVo userInfoVo = new UserInfoVo(); + LoginUser loginUser = LoginHelper.getLoginUser(); + if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { + // 超级管理员 如果重新加载用户信息需清除动态租户 + TenantHelper.clearDynamic(); + } + SysUserVo user = userService.selectUserById(loginUser.getUserId()); + if (ObjectUtil.isNull(user)) { + return R.fail("没有权限访问用户数据!"); + } + userInfoVo.setUser(user); + userInfoVo.setPermissions(loginUser.getMenuPermission()); + userInfoVo.setRoles(loginUser.getRolePermission()); + return R.ok(userInfoVo); + } + + /** + * 根据用户编号获取详细信息 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping(value = {"/", "/{userId}"}) + public R getInfo(@PathVariable(value = "userId", required = false) Long userId) { + SysUserInfoVo userInfoVo = new SysUserInfoVo(); + if (ObjectUtil.isNotNull(userId)) { + userService.checkUserDataScope(userId); + SysUserVo sysUser = userService.selectUserById(userId); + userInfoVo.setUser(sysUser); + userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId)); + Long deptId = sysUser.getDeptId(); + if (ObjectUtil.isNotNull(deptId)) { + SysPostBo postBo = new SysPostBo(); + postBo.setDeptId(deptId); + userInfoVo.setPosts(postService.selectPostList(postBo)); + userInfoVo.setPostIds(postService.selectPostListByUserId(userId)); + } + } + SysRoleBo roleBo = new SysRoleBo(); + roleBo.setStatus(SystemConstants.NORMAL); + List roles = roleService.selectRoleList(roleBo); + userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin())); + return R.ok(userInfoVo); + } + + /** + * 新增用户 + */ + @SaCheckPermission("system:user:add") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysUserBo user) { + deptService.checkDeptDataScope(user.getDeptId()); + if (!userService.checkUserNameUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + if (TenantHelper.isEnable()) { + if (!tenantService.checkAccountBalance(TenantHelper.getTenantId())) { + return R.fail("当前租户下用户名额不足,请联系管理员"); + } + } + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.insertUser(user)); + } + + /** + * 修改用户 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + deptService.checkDeptDataScope(user.getDeptId()); + if (!userService.checkUserNameUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + return toAjax(userService.updateUser(user)); + } + + /** + * 删除用户 + * + * @param userIds 角色ID串 + */ + @SaCheckPermission("system:user:remove") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public R remove(@PathVariable Long[] userIds) { + if (ArrayUtil.contains(userIds, LoginHelper.getUserId())) { + return R.fail("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + /** + * 根据用户ID串批量获取用户基础信息 + * + * @param userIds 用户ID串 + * @param deptId 部门ID + */ + @SaCheckPermission("system:user:query") + @GetMapping("/optionselect") + public R> optionselect(@RequestParam(required = false) Long[] userIds, + @RequestParam(required = false) Long deptId) { + return R.ok(userService.selectUserByIds(ArrayUtil.isEmpty(userIds) ? null : List.of(userIds), deptId)); + } + + /** + * 重置密码 + */ + @ApiEncrypt + @SaCheckPermission("system:user:resetPwd") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/resetPwd") + public R resetPwd(@RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.resetUserPwd(user.getUserId(), user.getPassword())); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysUserBo user) { + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + return toAjax(userService.updateUserStatus(user.getUserId(), user.getStatus())); + } + + /** + * 根据用户编号获取授权角色 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping("/authRole/{userId}") + public R authRole(@PathVariable Long userId) { + userService.checkUserDataScope(userId); + SysUserVo user = userService.selectUserById(userId); + List roles = roleService.selectRolesAuthByUserId(userId); + SysUserInfoVo userInfoVo = new SysUserInfoVo(); + userInfoVo.setUser(user); + userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin())); + return R.ok(userInfoVo); + } + + /** + * 用户授权角色 + * + * @param userId 用户Id + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public R insertAuthRole(Long userId, Long[] roleIds) { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return R.ok(); + } + + /** + * 获取部门树列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/deptTree") + public R>> deptTree(SysDeptBo dept) { + return R.ok(deptService.selectDeptTreeList(dept)); + } + + /** + * 获取部门下的所有用户信息 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list/dept/{deptId}") + public R> listByDept(@PathVariable @NotNull Long deptId) { + return R.ok(userService.selectUserListByDept(deptId)); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java new file mode 100644 index 0000000..e398a20 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java @@ -0,0 +1,47 @@ +package org.dromara.system.domain; + +import org.dromara.common.core.utils.StringUtils; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 缓存信息 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class SysCache { + + /** + * 缓存名称 + */ + private String cacheName = ""; + + /** + * 缓存键名 + */ + private String cacheKey = ""; + + /** + * 缓存内容 + */ + private String cacheValue = ""; + + /** + * 备注 + */ + private String remark = ""; + + public SysCache(String cacheName, String remark) { + this.cacheName = cacheName; + this.remark = remark; + } + + public SysCache(String cacheName, String cacheKey, String cacheValue) { + this.cacheName = StringUtils.replace(cacheName, ":", ""); + this.cacheKey = StringUtils.replace(cacheKey, cacheName, ""); + this.cacheValue = cacheValue; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java new file mode 100644 index 0000000..ee2475d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java @@ -0,0 +1,77 @@ +package org.dromara.system.domain; + +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 授权管理对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_client") +public class SysClient extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 客户端id + */ + private String clientId; + + /** + * 客户端key + */ + private String clientKey; + + /** + * 客户端秘钥 + */ + private String clientSecret; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + private Long activeTimeout; + + /** + * token固定超时时间 + */ + private Long timeout; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java new file mode 100644 index 0000000..6fcb88f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.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_config + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_config") +public class SysConfig extends TenantEntity { + + /** + * 参数主键 + */ + @TableId(value = "config_id") + private Long configId; + + /** + * 参数名称 + */ + private String configName; + + /** + * 参数键名 + */ + private String configKey; + + /** + * 参数键值 + */ + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + private String configType; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java new file mode 100644 index 0000000..b94fd8a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java @@ -0,0 +1,83 @@ +package org.dromara.system.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; + +/** + * 部门表 sys_dept + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dept") +public class SysDept extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门ID + */ + @TableId(value = "dept_id") + private Long deptId; + + /** + * 父部门ID + */ + private Long parentId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 部门类别编码 + */ + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人 + */ + private Long leader; + + /** + * 联系电话 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 部门状态:0正常,1停用 + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 祖级列表 + */ + private String ancestors; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java new file mode 100644 index 0000000..2df5596 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java @@ -0,0 +1,191 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.util.ArrayList; +import java.util.List; + +/** + * 菜单权限表 sys_menu + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_menu") +public class SysMenu extends BaseEntity { + + /** + * 菜单ID + */ + @TableId(value = "menu_id") + private Long menuId; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限字符串 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 备注 + */ + private String remark; + + /** + * 父菜单名称 + */ + @TableField(exist = false) + private String parentName; + + /** + * 子菜单 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + + /** + * 获取路由名称 + */ + public String getRouteName() { + String routerName = StringUtils.capitalize(path); + // 非外链并且是一级目录(类型为目录) + if (isMenuFrame()) { + routerName = StringUtils.EMPTY; + } + return routerName; + } + + /** + * 获取路由地址 + */ + public String getRouterPath() { + String routerPath = this.path; + // 内链打开外网方式 + if (getParentId() != 0L && isInnerLink()) { + routerPath = innerLinkReplaceEach(routerPath); + } + // 非外链并且是一级目录(类型为目录) + if (0L == getParentId() && SystemConstants.TYPE_DIR.equals(getMenuType()) + && SystemConstants.NO_FRAME.equals(getIsFrame())) { + routerPath = "/" + this.path; + } + // 非外链并且是一级目录(类型为菜单) + else if (isMenuFrame()) { + routerPath = "/"; + } + return routerPath; + } + + /** + * 获取组件信息 + */ + public String getComponentInfo() { + String component = SystemConstants.LAYOUT; + if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) { + component = this.component; + } else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && isInnerLink()) { + component = SystemConstants.INNER_LINK; + } else if (StringUtils.isEmpty(this.component) && isParentView()) { + component = SystemConstants.PARENT_VIEW; + } + return component; + } + + /** + * 是否为菜单内部跳转 + */ + public boolean isMenuFrame() { + return getParentId() == 0L && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME); + } + + /** + * 是否为内链组件 + */ + public boolean isInnerLink() { + return isFrame.equals(SystemConstants.NO_FRAME) && StringUtils.ishttp(path); + } + + /** + * 是否为parent_view组件 + */ + public boolean isParentView() { + return getParentId() != 0L && SystemConstants.TYPE_DIR.equals(menuType); + } + + /** + * 内链域名特殊字符替换 + */ + public static String innerLinkReplaceEach(String path) { + return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":"}, + new String[]{"", "", "", "/", "/"}); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java new file mode 100644 index 0000000..41a8c59 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java @@ -0,0 +1,115 @@ +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; + +/** + * 操作日志记录表 oper_log + * + * @author Lion Li + */ + +@Data +@TableName("sys_oper_log") +public class SysOperLog implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + @TableId(value = "oper_id") + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 操作模块 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求url + */ + private String operUrl; + + /** + * 操作地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java new file mode 100644 index 0000000..2c985da --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java @@ -0,0 +1,61 @@ +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_post + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_post") +public class SysPost extends TenantEntity { + + /** + * 岗位序号 + */ + @TableId(value = "post_id") + private Long postId; + + /** + * 部门id + */ + private Long deptId; + + /** + * 岗位编码 + */ + private String postCode; + + /** + * 岗位名称 + */ + private String postName; + + /** + * 岗位类别编码 + */ + private String postCategory; + + /** + * 岗位排序 + */ + 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/SysRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java new file mode 100644 index 0000000..a7c0ad5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java @@ -0,0 +1,79 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.tenant.core.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 角色表 sys_role + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_role") +public class SysRole extends TenantEntity { + + /** + * 角色ID + */ + @TableId(value = "role_id") + private Long roleId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色权限 + */ + private String roleKey; + + /** + * 角色排序 + */ + private Integer roleSort; + + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + private String dataScope; + + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + + public SysRole(Long roleId) { + this.roleId = roleId; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java new file mode 100644 index 0000000..ba77694 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和部门关联 sys_role_dept + * + * @author Lion Li + */ + +@Data +@TableName("sys_role_dept") +public class SysRoleDept { + + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + + /** + * 部门ID + */ + private Long deptId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java new file mode 100644 index 0000000..ba28f17 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 角色和菜单关联 sys_role_menu + * + * @author Lion Li + */ + +@Data +@TableName("sys_role_menu") +public class SysRoleMenu { + + /** + * 角色ID + */ + @TableId(type = IdType.INPUT) + private Long roleId; + + /** + * 菜单ID + */ + private Long menuId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java new file mode 100644 index 0000000..10f2936 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java @@ -0,0 +1,136 @@ +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.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 社会化关系对象 sys_social + * + * @author thiszhc + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_social") +public class SysSocial extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 的唯一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; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java new file mode 100644 index 0000000..9800c30 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java @@ -0,0 +1,103 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.util.Date; + +/** + * 租户对象 sys_tenant + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_tenant") +public class SysTenant extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 联系人 + */ + private String contactUserName; + + /** + * 联系电话 + */ + private String contactPhone; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 统一社会信用代码 + */ + private String licenseNumber; + + /** + * 地址 + */ + private String address; + + /** + * 域名 + */ + private String domain; + + /** + * 企业简介 + */ + private String intro; + + /** + * 备注 + */ + private String remark; + + /** + * 租户套餐编号 + */ + private Long packageId; + + /** + * 过期时间 + */ + private Date expireTime; + + /** + * 用户数量(-1不限制) + */ + private Long accountCount; + + /** + * 租户状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java new file mode 100644 index 0000000..5f58e3e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java @@ -0,0 +1,60 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.io.Serial; + +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 租户套餐对象 sys_tenant_package + * + * @author Michelle.Chung + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_tenant_package") +public class SysTenantPackage extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 租户套餐id + */ + @TableId(value = "package_id") + private Long packageId; + + /** + * 套餐名称 + */ + private String packageName; + + /** + * 关联菜单id + */ + private String menuIds; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private Boolean menuCheckStrictly; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java new file mode 100644 index 0000000..e8289e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java @@ -0,0 +1,140 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.tenant.core.TenantEntity; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 用户对象 sys_user + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_user") +public class SysUser extends TenantEntity { + + /** + * 用户ID + */ + @TableId(value = "user_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; + + /** + * 用户性别 + */ + private String sex; + + /** + * 用户头像 + */ + private Long avatar; + + /** + * 密码 + */ + @TableField( + insertStrategy = FieldStrategy.NOT_EMPTY, + updateStrategy = FieldStrategy.NOT_EMPTY, + whereStrategy = FieldStrategy.NOT_EMPTY + ) + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private Date loginDate; + + /** + * 备注 + */ + private String remark; + + /** + * openID + * @param userId + */ + private String openId; + + /** + * 余额 + */ + private BigDecimal balance; + + /** + * 冻结资金 + */ + private BigDecimal freeze; + + /** + * 自营书品仓库名称 + */ + private String warehouseName; + + @TableField(exist = false) + private String shopName; + + + public SysUser(Long userId) { + this.userId = userId; + } + + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ID.equals(this.userId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java new file mode 100644 index 0000000..ba30eb6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java @@ -0,0 +1,63 @@ +package org.dromara.system.domain; + +import lombok.Data; + +/** + * 当前在线会话 + * + * @author Lion Li + */ +@Data +public class SysUserOnline { + + /** + * 会话编号 + */ + private String tokenId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 用户名称 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地址 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java new file mode 100644 index 0000000..119c117 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和岗位关联 sys_user_post + * + * @author Lion Li + */ + +@Data +@TableName("sys_user_post") +public class SysUserPost { + + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * 岗位ID + */ + private Long postId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java new file mode 100644 index 0000000..0a50e80 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java @@ -0,0 +1,29 @@ +package org.dromara.system.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * 用户和角色关联 sys_user_role + * + * @author Lion Li + */ + +@Data +@TableName("sys_user_role") +public class SysUserRole { + + /** + * 用户ID + */ + @TableId(type = IdType.INPUT) + private Long userId; + + /** + * 角色ID + */ + private Long roleId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java new file mode 100644 index 0000000..257935d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java @@ -0,0 +1,59 @@ +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.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysConfig; + +/** + * 参数配置业务对象 sys_config + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysConfig.class, reverseConvertGenerate = false) +public class SysConfigBo extends BaseEntity { + + /** + * 参数主键 + */ + private Long configId; + + /** + * 参数名称 + */ + @NotBlank(message = "参数名称不能为空") + @Size(min = 0, max = 100, message = "参数名称不能超过{max}个字符") + private String configName; + + /** + * 参数键名 + */ + @NotBlank(message = "参数键名不能为空") + @Size(min = 0, max = 100, message = "参数键名长度不能超过{max}个字符") + private String configKey; + + /** + * 参数键值 + */ + @NotBlank(message = "参数键值不能为空") + @Size(min = 0, max = 500, message = "参数键值长度不能超过{max}个字符") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + private String configType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java new file mode 100644 index 0000000..042946c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java @@ -0,0 +1,80 @@ +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.SysDictData; + +/** + * 字典数据业务对象 sys_dict_data + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysDictData.class, reverseConvertGenerate = false) +public class SysDictDataBo extends BaseEntity { + + /** + * 字典编码 + */ + private Long dictCode; + + /** + * 字典排序 + */ + private Integer dictSort; + + /** + * 字典标签 + */ + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过{max}个字符") + private String dictLabel; + + /** + * 字典键值 + */ + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过{max}个字符") + private String dictValue; + + /** + * 字典类型 + */ + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过{max}个字符") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + @Size(min = 0, max = 100, message = "样式属性长度不能超过{max}个字符") + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + private String isDefault; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java new file mode 100644 index 0000000..4646162 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java @@ -0,0 +1,87 @@ +package org.dromara.system.domain.bo; + +import org.dromara.system.domain.SysLogininfor; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 系统访问记录业务对象 sys_logininfor + * + * @author Michelle.Chung + */ + +@Data +@AutoMapper(target = SysLogininfor.class, reverseConvertGenerate = false) +public class SysLogininforBo { + + /** + * 访问ID + */ + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + private String userName; + + /** + * 客户端 + */ + private String clientKey; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录状态(0成功 1失败) + */ + private String status; + + /** + * 提示消息 + */ + private String msg; + + /** + * 访问时间 + */ + private Date loginTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java new file mode 100644 index 0000000..fbaafaa --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java @@ -0,0 +1,110 @@ +package org.dromara.system.domain.bo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +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.SysMenu; + +/** + * 菜单权限业务对象 sys_menu + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysMenu.class, reverseConvertGenerate = false) +public class SysMenuBo extends BaseEntity { + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 菜单名称 + */ + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过{max}个字符") + private String menuName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 路由地址 + */ + @Size(min = 0, max = 200, message = "路由地址不能超过{max}个字符") + private String path; + + /** + * 组件路径 + */ + @Size(min = 0, max = 200, message = "组件路径不能超过{max}个字符") + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + @NotBlank(message = "菜单类型不能为空") + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + @Size(min = 0, max = 100, message = "权限标识长度不能超过{max}个字符") + @Pattern(regexp = RegexConstants.PERMISSION_STRING, message = "权限标识必须符合 tool:build:list 格式") + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java new file mode 100644 index 0000000..f16400a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java @@ -0,0 +1,127 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.log.event.OperLogEvent; +import org.dromara.system.domain.SysOperLog; +import io.github.linpeilie.annotations.AutoMapper; +import io.github.linpeilie.annotations.AutoMappers; +import lombok.Data; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * 操作日志记录业务对象 sys_oper_log + * + * @author Michelle.Chung + * @date 2023-02-07 + */ + +@Data +@AutoMappers({ + @AutoMapper(target = SysOperLog.class, reverseConvertGenerate = false), + @AutoMapper(target = OperLogEvent.class) +}) +public class SysOperLogBo { + + /** + * 日志主键 + */ + private Long operId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 模块标题 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 方法名称 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求URL + */ + private String operUrl; + + /** + * 主机地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + + /** + * 消耗时间 + */ + private Long costTime; + + /** + * 请求参数 + */ + private Map params = new HashMap<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java new file mode 100644 index 0000000..3dc4328 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java @@ -0,0 +1,109 @@ +package org.dromara.system.domain.bo; + +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysOssConfig; +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; + +/** + * 对象存储配置业务对象 sys_oss_config + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysOssConfig.class, reverseConvertGenerate = false) +public class SysOssConfigBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long ossConfigId; + + /** + * 配置key + */ + @NotBlank(message = "配置key不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "configKey长度必须介于{min}和{max} 之间") + private String configKey; + + /** + * accessKey + */ + @NotBlank(message = "accessKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "accessKey长度必须介于{min}和{max} 之间") + private String accessKey; + + /** + * 秘钥 + */ + @NotBlank(message = "secretKey不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "secretKey长度必须介于{min}和{max} 之间") + private String secretKey; + + /** + * 桶名称 + */ + @NotBlank(message = "桶名称不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "bucketName长度必须介于{min}和{max}之间") + private String bucketName; + + /** + * 前缀 + */ + private String prefix; + + /** + * 访问站点 + */ + @NotBlank(message = "访问站点不能为空", groups = {AddGroup.class, EditGroup.class}) + @Size(min = 2, max = 100, message = "endpoint长度必须介于{min}和{max}之间") + private String endpoint; + + /** + * 自定义域名 + */ + private String domain; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + + /** + * 是否默认(0=是,1=否) + */ + private String status; + + /** + * 域 + */ + private String region; + + /** + * 扩展字段 + */ + private String ext1; + + /** + * 备注 + */ + private String remark; + + /** + * 桶权限类型(0private 1public 2custom) + */ + @NotBlank(message = "桶权限类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String accessPolicy; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java new file mode 100644 index 0000000..3207bad --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java @@ -0,0 +1,94 @@ +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 lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysRole; + +/** + * 角色信息业务对象 sys_role + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysRole.class, reverseConvertGenerate = false) +public class SysRoleBo extends BaseEntity { + + /** + * 角色ID + */ + private Long roleId; + + /** + * 角色名称 + */ + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过{max}个字符") + private String roleName; + + /** + * 角色权限字符串 + */ + @NotBlank(message = "角色权限字符串不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过{max}个字符") + private String roleKey; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer roleSort; + + /** + * 数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限) + */ + private String dataScope; + + /** + * 菜单树选择项是否关联显示 + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示 + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 菜单组 + */ + private Long[] menuIds; + + /** + * 部门组(数据权限) + */ + private Long[] deptIds; + + public SysRoleBo(Long roleId) { + this.roleId = roleId; + } + + 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/bo/SysTenantBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java new file mode 100644 index 0000000..e3ac642 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java @@ -0,0 +1,114 @@ +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.SysTenant; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.util.Date; + +import org.dromara.common.mybatis.core.domain.BaseEntity; + +/** + * 租户业务对象 sys_tenant + * + * @author Michelle.Chung + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysTenant.class, reverseConvertGenerate = false) +public class SysTenantBo extends BaseEntity { + + /** + * id + */ + @NotNull(message = "id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 联系人 + */ + @NotBlank(message = "联系人不能为空", groups = { AddGroup.class, EditGroup.class }) + private String contactUserName; + + /** + * 联系电话 + */ + @NotBlank(message = "联系电话不能为空", groups = { AddGroup.class, EditGroup.class }) + private String contactPhone; + + /** + * 企业名称 + */ + @NotBlank(message = "企业名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String companyName; + + /** + * 用户名(创建系统用户) + */ + @NotBlank(message = "用户名不能为空", groups = { AddGroup.class }) + private String username; + + /** + * 密码(创建系统用户) + */ + @NotBlank(message = "密码不能为空", groups = { AddGroup.class }) + private String password; + + /** + * 统一社会信用代码 + */ + private String licenseNumber; + + /** + * 地址 + */ + private String address; + + /** + * 域名 + */ + private String domain; + + /** + * 企业简介 + */ + private String intro; + + /** + * 备注 + */ + private String remark; + + /** + * 租户套餐编号 + */ + @NotNull(message = "租户套餐不能为空", groups = { AddGroup.class }) + private Long packageId; + + /** + * 过期时间 + */ + private Date expireTime; + + /** + * 用户数量(-1不限制) + */ + private Long accountCount; + + /** + * 租户状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java new file mode 100644 index 0000000..51ca09a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java @@ -0,0 +1,142 @@ +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.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.xss.Xss; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.system.domain.SysUser; + +import java.math.BigDecimal; + +/** + * 用户信息业务对象 sys_user + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = SysUser.class, reverseConvertGenerate = false) +public class SysUserBo extends BaseEntity { + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") + private String userName; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @NotBlank(message = "用户昵称不能为空") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 密码 + */ + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 备注 + */ + private String remark; + + /** + * 角色组 + */ + @Size(min = 1, message = "用户角色不能为空") + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + /** + * 排除不查询的用户(工作流用) + */ + private String excludeUserIds; + + /** + * 余额 + */ + private BigDecimal balance; + + /** + * 冻结资金 + */ + private BigDecimal freeze; + + /** + * 自营书品仓库名称 + */ + private String warehouseName; + + /** + * 角色权限 + */ + private String roleKey; + + + public SysUserBo(Long userId) { + this.userId = userId; + } + + public boolean isSuperAdmin() { + return SystemConstants.SUPER_ADMIN_ID.equals(this.userId); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java new file mode 100644 index 0000000..84203ce --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java @@ -0,0 +1,57 @@ +package org.dromara.system.domain.bo; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import org.dromara.common.core.constant.RegexConstants; +import org.dromara.common.core.xss.Xss; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.sensitive.annotation.Sensitive; +import org.dromara.common.sensitive.core.SensitiveStrategy; + +/** + * 个人信息业务处理 + * + * @author Michelle.Chung + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SysUserProfileBo extends BaseEntity { + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + /** + * 用户邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL) + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + + /** + * 手机号码 + */ + @Pattern(regexp = RegexConstants.MOBILE, message = "手机号格式不正确") + @Sensitive(strategy = SensitiveStrategy.PHONE) + private String phonenumber; + + /** + * 用户性别(0男 1女 2未知) + */ + private String sex; + + /** + * 自营书品仓库名称 + */ + private String warehouseName; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java new file mode 100644 index 0000000..6f7db28 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java @@ -0,0 +1,26 @@ +package org.dromara.system.domain.vo; + +import cn.hutool.core.lang.tree.Tree; +import lombok.Data; + +import java.util.List; + +/** + * 角色部门列表树信息 + * + * @author Michelle.Chung + */ +@Data +public class DeptTreeSelectVo { + + /** + * 选中部门列表 + */ + private List checkedKeys; + + /** + * 下拉树结构列表 + */ + private List> depts; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java new file mode 100644 index 0000000..0724538 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java @@ -0,0 +1,26 @@ +package org.dromara.system.domain.vo; + +import cn.hutool.core.lang.tree.Tree; +import lombok.Data; + +import java.util.List; + +/** + * 角色菜单列表树信息 + * + * @author Michelle.Chung + */ +@Data +public class MenuTreeSelectVo { + + /** + * 选中菜单列表 + */ + private List checkedKeys; + + /** + * 菜单下拉树结构列表 + */ + private List> menus; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java new file mode 100644 index 0000000..f720cd7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java @@ -0,0 +1,61 @@ +package org.dromara.system.domain.vo; + +import org.dromara.common.core.utils.StringUtils; +import lombok.Data; + +/** + * 路由显示信息 + * + * @author ruoyi + */ + +@Data +public class MetaVo { + + /** + * 设置该路由在侧边栏和面包屑中展示的名字 + */ + private String title; + + /** + * 设置该路由的图标,对应路径src/assets/icons/svg + */ + private String icon; + + /** + * 设置为true,则不会被 缓存 + */ + private boolean noCache; + + /** + * 内链地址(http(s)://开头) + */ + private String link; + + public MetaVo(String title, String icon) { + this.title = title; + this.icon = icon; + } + + public MetaVo(String title, String icon, boolean noCache) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + } + + public MetaVo(String title, String icon, String link) { + this.title = title; + this.icon = icon; + this.link = link; + } + + public MetaVo(String title, String icon, boolean noCache, String link) { + this.title = title; + this.icon = icon; + this.noCache = noCache; + if (StringUtils.ishttp(link)) { + this.link = link; + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java new file mode 100644 index 0000000..a6849b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java @@ -0,0 +1,36 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +import java.util.Map; + +/** + * 用户个人信息 + * + * @author Michelle.Chung + */ +@Data +public class ProfileVo { + + /** + * 用户信息 + */ + private SysUserVo user; + + /** + * 用户所属角色组 + */ + private String roleGroup; + + /** + * 用户所属岗位组 + */ + private String postGroup; + + /** + * 新仓库系统登录信息 + */ + private Map warehouseLoginUser; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java new file mode 100644 index 0000000..0d576ef --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java @@ -0,0 +1,62 @@ +package org.dromara.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.util.List; + +/** + * 路由配置信息 + * + * @author Lion Li + */ +@Data +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class RouterVo { + + /** + * 路由名字 + */ + private String name; + + /** + * 路由地址 + */ + private String path; + + /** + * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现 + */ + private boolean hidden; + + /** + * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + */ + private String redirect; + + /** + * 组件地址 + */ + private String component; + + /** + * 路由参数:如 {"id": 1, "name": "ry"} + */ + private String query; + + /** + * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + */ + private Boolean alwaysShow; + + /** + * 其他元素 + */ + private MetaVo meta; + + /** + * 子路由 + */ + private List children; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java new file mode 100644 index 0000000..34f24eb --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java @@ -0,0 +1,90 @@ +package org.dromara.system.domain.vo; + +import org.dromara.system.domain.SysClient; +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.List; + + +/** + * 授权管理视图对象 sys_client + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysClient.class) +public class SysClientVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 客户端id + */ + @ExcelProperty(value = "客户端id") + private String clientId; + + /** + * 客户端key + */ + @ExcelProperty(value = "客户端key") + private String clientKey; + + /** + * 客户端秘钥 + */ + @ExcelProperty(value = "客户端秘钥") + private String clientSecret; + + /** + * 授权类型 + */ + @ExcelProperty(value = "授权类型") + private List grantTypeList; + + /** + * 授权类型 + */ + private String grantType; + + /** + * 设备类型 + */ + private String deviceType; + + /** + * token活跃超时时间 + */ + @ExcelProperty(value = "token活跃超时时间") + private Long activeTimeout; + + /** + * token固定超时时间 + */ + @ExcelProperty(value = "token固定超时时间") + private Long timeout; + + /** + * 状态(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/SysConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java new file mode 100644 index 0000000..f896000 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java @@ -0,0 +1,72 @@ +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.SysConfig; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 参数配置视图对象 sys_config + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysConfig.class) +public class SysConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 参数主键 + */ + @ExcelProperty(value = "参数主键") + private Long configId; + + /** + * 参数名称 + */ + @ExcelProperty(value = "参数名称") + private String configName; + + /** + * 参数键名 + */ + @ExcelProperty(value = "参数键名") + private String configKey; + + /** + * 参数键值 + */ + @ExcelProperty(value = "参数键值") + private String configValue; + + /** + * 系统内置(Y是 N否) + */ + @ExcelProperty(value = "系统内置", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String configType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java new file mode 100644 index 0000000..c56fb09 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java @@ -0,0 +1,102 @@ +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.SysDept; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 部门视图对象 sys_dept + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDept.class) +public class SysDeptVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 父部门id + */ + private Long parentId; + + /** + * 父部门名称 + */ + private String parentName; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 部门类别编码 + */ + @ExcelProperty(value = "部门类别编码") + private String deptCategory; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 负责人ID + */ + private Long leader; + + /** + * 负责人 + */ + @ExcelProperty(value = "负责人") + private String leaderName; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String phone; + + /** + * 邮箱 + */ + @ExcelProperty(value = "邮箱") + private String email; + + /** + * 部门状态(0正常 1停用) + */ + @ExcelProperty(value = "部门状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java new file mode 100644 index 0000000..83ea619 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java @@ -0,0 +1,88 @@ +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.SysDictData; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 字典数据视图对象 sys_dict_data + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictData.class) +public class SysDictDataVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典编码 + */ + @ExcelProperty(value = "字典编码") + private Long dictCode; + + /** + * 字典排序 + */ + @ExcelProperty(value = "字典排序") + private Integer dictSort; + + /** + * 字典标签 + */ + @ExcelProperty(value = "字典标签") + private String dictLabel; + + /** + * 字典键值 + */ + @ExcelProperty(value = "字典键值") + private String dictValue; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + private String cssClass; + + /** + * 表格回显样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + @ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isDefault; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java new file mode 100644 index 0000000..e6a184f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java @@ -0,0 +1,59 @@ +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.SysDictType; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 字典类型视图对象 sys_dict_type + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysDictType.class) +public class SysDictTypeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 字典主键 + */ + @ExcelProperty(value = "字典主键") + private Long dictId; + + /** + * 字典名称 + */ + @ExcelProperty(value = "字典名称") + private String dictName; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + private String dictType; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java new file mode 100644 index 0000000..de19aea --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java @@ -0,0 +1,106 @@ +package org.dromara.system.domain.vo; + +import java.util.Date; +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.SysLogininfor; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + + +/** + * 系统访问记录视图对象 sys_logininfor + * + * @author Michelle.Chung + * @date 2023-02-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysLogininfor.class) +public class SysLogininforVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 访问ID + */ + @ExcelProperty(value = "序号") + private Long infoId; + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "用户账号") + private String userName; + + /** + * 客户端 + */ + @ExcelProperty(value = "客户端") + private String clientKey; + + /** + * 设备类型 + */ + @ExcelProperty(value = "设备类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_device_type") + private String deviceType; + + /** + * 登录状态(0成功 1失败) + */ + @ExcelProperty(value = "登录状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_common_status") + private String status; + + /** + * 登录IP地址 + */ + @ExcelProperty(value = "登录地址") + private String ipaddr; + + /** + * 登录地点 + */ + @ExcelProperty(value = "登录地点") + private String loginLocation; + + /** + * 浏览器类型 + */ + @ExcelProperty(value = "浏览器") + private String browser; + + /** + * 操作系统 + */ + @ExcelProperty(value = "操作系统") + private String os; + + + /** + * 提示消息 + */ + @ExcelProperty(value = "提示消息") + private String msg; + + /** + * 访问时间 + */ + @ExcelProperty(value = "访问时间") + private Date loginTime; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java new file mode 100644 index 0000000..5214a33 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java @@ -0,0 +1,116 @@ +package org.dromara.system.domain.vo; + +import org.dromara.system.domain.SysMenu; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + + +/** + * 菜单权限视图对象 sys_menu + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysMenu.class) +public class SysMenuVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 菜单ID + */ + private Long menuId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer orderNum; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 菜单类型(M目录 C菜单 F按钮) + */ + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限标识 + */ + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 子菜单 + */ + private List children = new ArrayList<>(); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java new file mode 100644 index 0000000..e7cfde4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java @@ -0,0 +1,97 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import org.dromara.system.domain.SysOssConfig; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 对象存储配置视图对象 sys_oss_config + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysOssConfig.class) +public class SysOssConfigVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + 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(Y=是,N=否) + */ + 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/vo/SysOssUploadVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java new file mode 100644 index 0000000..11e0ff8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java @@ -0,0 +1,28 @@ +package org.dromara.system.domain.vo; + +import lombok.Data; + +/** + * 上传对象信息 + * + * @author Michelle.Chung + */ +@Data +public class SysOssUploadVo { + + /** + * URL地址 + */ + private String url; + + /** + * 文件名 + */ + private String fileName; + + /** + * 对象存储主键 + */ + private String ossId; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java new file mode 100644 index 0000000..8d5c429 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java @@ -0,0 +1,72 @@ +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.SysOss; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * OSS对象存储视图对象 sys_oss + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysOss.class) +public class SysOssVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 对象存储主键 + */ + private Long ossId; + + /** + * 文件名 + */ + private String fileName; + + /** + * 原名 + */ + private String originalName; + + /** + * 文件后缀名 + */ + private String fileSuffix; + + /** + * URL地址 + */ + private String url; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 上传人 + */ + private Long createBy; + + /** + * 上传人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy") + private String createByName; + + /** + * 服务商 + */ + private String service; + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java new file mode 100644 index 0000000..69be547 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java @@ -0,0 +1,91 @@ +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.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysPost; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 岗位信息视图对象 sys_post + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysPost.class) +public class SysPostVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 岗位ID + */ + @ExcelProperty(value = "岗位序号") + private Long postId; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 岗位编码 + */ + @ExcelProperty(value = "岗位编码") + private String postCode; + + /** + * 岗位名称 + */ + @ExcelProperty(value = "岗位名称") + private String postName; + + /** + * 岗位类别编码 + */ + @ExcelProperty(value = "类别编码") + private String postCategory; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "岗位排序") + private Integer postSort; + + /** + * 状态(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; + + /** + * 部门名 + */ + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java new file mode 100644 index 0000000..6a45315 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java @@ -0,0 +1,115 @@ +package org.dromara.system.domain.vo; + +import java.util.Date; +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.SysTenant; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 租户视图对象 sys_tenant + * + * @author Michelle.Chung + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = SysTenant.class) +public class SysTenantVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 租户编号 + */ + @ExcelProperty(value = "租户编号") + private String tenantId; + + /** + * 联系人 + */ + @ExcelProperty(value = "联系人") + private String contactUserName; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String contactPhone; + + /** + * 企业名称 + */ + @ExcelProperty(value = "企业名称") + private String companyName; + + /** + * 统一社会信用代码 + */ + @ExcelProperty(value = "统一社会信用代码") + private String licenseNumber; + + /** + * 地址 + */ + @ExcelProperty(value = "地址") + private String address; + + /** + * 域名 + */ + @ExcelProperty(value = "域名") + private String domain; + + /** + * 企业简介 + */ + @ExcelProperty(value = "企业简介") + private String intro; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 租户套餐编号 + */ + @ExcelProperty(value = "租户套餐编号") + private Long packageId; + + /** + * 过期时间 + */ + @ExcelProperty(value = "过期时间") + private Date expireTime; + + /** + * 用户数量(-1不限制) + */ + @ExcelProperty(value = "用户数量") + private Long accountCount; + + /** + * 租户状态(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/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java new file mode 100644 index 0000000..37ec6b7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java @@ -0,0 +1,96 @@ +package org.dromara.system.domain.vo; + +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 io.github.linpeilie.annotations.ReverseAutoMapping; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 用户对象导出VO + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class SysUserExportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 最后登录IP + */ + @ExcelProperty(value = "最后登录IP") + private String loginIp; + + /** + * 最后登录时间 + */ + @ExcelProperty(value = "最后登录时间") + private Date loginDate; + + /** + * 部门名称 + */ + @ExcelProperty(value = "部门名称") + private String deptName; + + /** + * 负责人 + */ + @ExcelProperty(value = "部门负责人") + private String leaderName; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java new file mode 100644 index 0000000..c34a23c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java @@ -0,0 +1,76 @@ +package org.dromara.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 用户对象导入VO + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +// @Accessors(chain = true) // 导入不允许使用 会找不到set方法 +public class SysUserImportVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + /** + * 部门ID + */ + @ExcelProperty(value = "部门编号") + private Long deptId; + + /** + * 用户账号 + */ + @ExcelProperty(value = "登录名称") + private String userName; + + /** + * 用户昵称 + */ + @ExcelProperty(value = "用户名称") + private String nickName; + + /** + * 用户邮箱 + */ + @ExcelProperty(value = "用户邮箱") + private String email; + + /** + * 手机号码 + */ + @ExcelProperty(value = "手机号码") + private String phonenumber; + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java new file mode 100644 index 0000000..48f141f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java @@ -0,0 +1,164 @@ +package org.dromara.system.domain.vo; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.dromara.common.sensitive.annotation.Sensitive; +import org.dromara.common.sensitive.core.SensitiveStrategy; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.system.domain.SysUser; +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; + + +/** + * 用户信息视图对象 sys_user + * + * @author Michelle.Chung + */ +@Data +@AutoMapper(target = SysUser.class) +public class SysUserVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 部门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; + + /** + * 头像地址 + */ + @Translation(type = TransConstant.OSS_ID_TO_URL) + private Long avatar; + + /** + * 密码 + */ + @JsonIgnore + @JsonProperty + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private Date loginDate; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 部门名 + */ + @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "deptId") + private String deptName; + + /** + * 角色对象 + */ + private List roles; + + /** + * 角色组 + */ + private Long[] roleIds; + + /** + * 岗位组 + */ + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + @JsonIgnore + @JsonProperty + private String openId; + + /** + * 余额 + */ + private BigDecimal balance; + + /** + * 冻结资金 + */ + private BigDecimal freeze; + + /** + * 自营书品仓库名称 + */ + private String warehouseName; + + /** + * 仓库商品数量 + */ + private String allNum; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java new file mode 100644 index 0000000..25b62a9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java @@ -0,0 +1,127 @@ +package org.dromara.system.listener; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.BCrypt; +import cn.hutool.http.HtmlUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.excel.core.ExcelListener; +import org.dromara.common.excel.core.ExcelResult; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserImportVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.ISysUserService; +import lombok.extern.slf4j.Slf4j; + +import java.util.List; + +/** + * 系统用户自定义导入 + * + * @author Lion Li + */ +@Slf4j +public class SysUserImportListener extends AnalysisEventListener implements ExcelListener { + + private final ISysUserService userService; + + private final String password; + + private final Boolean isUpdateSupport; + + private final Long operUserId; + + private int successNum = 0; + private int failureNum = 0; + private final StringBuilder successMsg = new StringBuilder(); + private final StringBuilder failureMsg = new StringBuilder(); + + public SysUserImportListener(Boolean isUpdateSupport) { + String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword"); + this.userService = SpringUtils.getBean(ISysUserService.class); + this.password = BCrypt.hashpw(initPassword); + this.isUpdateSupport = isUpdateSupport; + this.operUserId = LoginHelper.getUserId(); + } + + @Override + public void invoke(SysUserImportVo userVo, AnalysisContext context) { + SysUserVo sysUser = this.userService.selectUserByUserName(userVo.getUserName()); + try { + // 验证是否存在这个用户 + if (ObjectUtil.isNull(sysUser)) { + SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class); + ValidatorUtils.validate(user); + user.setPassword(password); + user.setCreateBy(operUserId); + userService.insertUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 导入成功"); + } else if (isUpdateSupport) { + Long userId = sysUser.getUserId(); + SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class); + user.setUserId(userId); + ValidatorUtils.validate(user); + userService.checkUserAllowed(user.getUserId()); + userService.checkUserDataScope(user.getUserId()); + user.setUpdateBy(operUserId); + userService.updateUser(user); + successNum++; + successMsg.append("
").append(successNum).append("、账号 ").append(user.getUserName()).append(" 更新成功"); + } else { + failureNum++; + failureMsg.append("
").append(failureNum).append("、账号 ").append(sysUser.getUserName()).append(" 已存在"); + } + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、账号 " + HtmlUtil.cleanHtmlTag(userVo.getUserName()) + " 导入失败:"; + String message = e.getMessage(); + if (e instanceof ConstraintViolationException cvException) { + message = StreamUtils.join(cvException.getConstraintViolations(), ConstraintViolation::getMessage, ", "); + } + failureMsg.append(msg).append(message); + log.error(msg, e); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + + } + + @Override + public ExcelResult getExcelResult() { + return new ExcelResult<>() { + + @Override + public String getAnalysis() { + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + } else { + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + @Override + public List getList() { + return null; + } + + @Override + public List getErrorList() { + return null; + } + }; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java new file mode 100644 index 0000000..15bcfb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java @@ -0,0 +1,15 @@ +package org.dromara.system.mapper; + +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 授权管理Mapper接口 + * + * @author Michelle.Chung + * @date 2023-05-15 + */ +public interface SysClientMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java new file mode 100644 index 0000000..7298db3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java @@ -0,0 +1,29 @@ +package org.dromara.system.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysDictData; +import org.dromara.system.domain.vo.SysDictDataVo; + +import java.util.List; + +/** + * 字典表 数据层 + * + * @author Lion Li + */ +public interface SysDictDataMapper extends BaseMapperPlus { + + /** + * 根据字典类型查询字典数据列表 + * + * @param dictType 字典类型 + * @return 符合条件的字典数据列表 + */ + default List selectDictDataByType(String dictType) { + return selectVoList( + new LambdaQueryWrapper() + .eq(SysDictData::getDictType, dictType) + .orderByAsc(SysDictData::getDictSort)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java new file mode 100644 index 0000000..9a9bdd5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.system.domain.SysDictType; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.vo.SysDictTypeVo; + +/** + * 字典表 数据层 + * + * @author Lion Li + */ +public interface SysDictTypeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java new file mode 100644 index 0000000..205413b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java @@ -0,0 +1,76 @@ +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 org.apache.ibatis.annotations.Param; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.vo.SysMenuVo; + +import java.util.List; + +/** + * 菜单表 数据层 + * + * @author Lion Li + */ +public interface SysMenuMapper extends BaseMapperPlus { + + /** + * 根据用户查询系统菜单列表 + * + * @param queryWrapper 查询条件 + * @return 菜单列表 + */ + List selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + List selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + List selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询菜单 + * + * @return 菜单列表 + */ + default List selectMenuTreeAll() { + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU) + .eq(SysMenu::getStatus, SystemConstants.NORMAL) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum); + return this.selectList(lqw); + } + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @param menuCheckStrictly 菜单树选择项是否关联显示 + * @return 选中菜单列表 + */ + List selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java new file mode 100644 index 0000000..1e27b77 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysNotice; +import org.dromara.system.domain.vo.SysNoticeVo; + +/** + * 通知公告表 数据层 + * + * @author Lion Li + */ +public interface SysNoticeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java new file mode 100644 index 0000000..5d20404 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOperLog; +import org.dromara.system.domain.vo.SysOperLogVo; + +/** + * 操作日志 数据层 + * + * @author Lion Li + */ +public interface SysOperLogMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java new file mode 100644 index 0000000..f93d34d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java @@ -0,0 +1,16 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOssConfig; +import org.dromara.system.domain.vo.SysOssConfigVo; + +/** + * 对象存储配置Mapper接口 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +public interface SysOssConfigMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java new file mode 100644 index 0000000..3da621d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysOss; +import org.dromara.system.domain.vo.SysOssVo; + +/** + * 文件上传 数据层 + * + * @author Lion Li + */ +public interface SysOssMapper extends BaseMapperPlus { +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java new file mode 100644 index 0000000..60da074 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java @@ -0,0 +1,43 @@ +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.SysPost; +import org.dromara.system.domain.vo.SysPostVo; + +import java.util.List; + +/** + * 岗位信息 数据层 + * + * @author Lion Li + */ +public interface SysPostMapper extends BaseMapperPlus { + + /** + * 分页查询岗位列表 + * + * @param page 分页对象 + * @param queryWrapper 查询条件 + * @return 包含岗位信息的分页结果 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "create_by") + }) + Page selectPagePostList(@Param("page") Page page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + List selectPostsByUserId(Long userId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java new file mode 100644 index 0000000..3de0bb6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRoleDept; + +/** + * 角色与部门关联表 数据层 + * + * @author Lion Li + */ +public interface SysRoleDeptMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java new file mode 100644 index 0000000..0a657b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java @@ -0,0 +1,13 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysRoleMenu; + +/** + * 角色与菜单关联表 数据层 + * + * @author Lion Li + */ +public interface SysRoleMenuMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java new file mode 100644 index 0000000..7e1167a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.system.domain.SysTenant; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 租户Mapper接口 + * + * @author Michelle.Chung + */ +public interface SysTenantMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java new file mode 100644 index 0000000..10ca170 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java @@ -0,0 +1,14 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysTenantPackage; +import org.dromara.system.domain.vo.SysTenantPackageVo; + +/** + * 租户套餐Mapper接口 + * + * @author Michelle.Chung + */ +public interface SysTenantPackageMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java new file mode 100644 index 0000000..8340348 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java @@ -0,0 +1,23 @@ +package org.dromara.system.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.system.domain.SysUserRole; + +import java.util.List; + +/** + * 用户与角色关联表 数据层 + * + * @author Lion Li + */ +public interface SysUserRoleMapper extends BaseMapperPlus { + + /** + * 根据角色ID查询关联的用户ID列表 + * + * @param roleId 角色ID + * @return 关联到指定角色的用户ID列表 + */ + List selectUserIdsByRoleId(Long roleId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java new file mode 100644 index 0000000..546c3f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java @@ -0,0 +1,60 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.bo.SysClientBo; +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 Michelle.Chung + * @date 2023-06-18 + */ +public interface ISysClientService { + + /** + * 查询客户端管理 + */ + SysClientVo queryById(Long id); + + /** + * 查询客户端信息基于客户端id + */ + SysClientVo queryByClientId(String clientId); + + /** + * 查询客户端管理列表 + */ + TableDataInfo queryPageList(SysClientBo bo, PageQuery pageQuery); + + /** + * 查询客户端管理列表 + */ + List queryList(SysClientBo bo); + + /** + * 新增客户端管理 + */ + Boolean insertByBo(SysClientBo bo); + + /** + * 修改客户端管理 + */ + Boolean updateByBo(SysClientBo bo); + + /** + * 修改状态 + */ + int updateClientStatus(String clientId, String status); + + /** + * 校验并批量删除客户端管理信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java new file mode 100644 index 0000000..f7efda7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java @@ -0,0 +1,87 @@ +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.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; + +import java.util.List; + +/** + * 参数配置 服务层 + * + * @author Lion Li + */ +public interface ISysConfigService { + + + TableDataInfo selectPageConfigList(SysConfigBo config, PageQuery pageQuery); + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + SysConfigVo selectConfigById(Long configId); + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数键名 + * @return 参数键值 + */ + String selectConfigByKey(String configKey); + + /** + * 获取注册开关 + * @param tenantId 租户id + * @return true开启,false关闭 + */ + boolean selectRegisterEnabled(String tenantId); + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + List selectConfigList(SysConfigBo config); + + /** + * 新增参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + String insertConfig(SysConfigBo bo); + + /** + * 修改参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + String updateConfig(SysConfigBo bo); + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + void deleteConfigByIds(Long[] configIds); + + /** + * 重置参数缓存数据 + */ + void resetConfigCache(); + + /** + * 校验参数键名是否唯一 + * + * @param config 参数信息 + * @return 结果 + */ + boolean checkConfigKeyUnique(SysConfigBo config); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java new file mode 100644 index 0000000..3f252f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java @@ -0,0 +1,26 @@ +package org.dromara.system.service; + +/** + * 通用 数据权限 服务 + * + * @author Lion Li + */ +public interface ISysDataScopeService { + + /** + * 获取角色自定义权限 + * + * @param roleId 角色id + * @return 部门id组 + */ + String getRoleCustom(Long roleId); + + /** + * 获取部门及以下权限 + * + * @param deptId 部门id + * @return 部门id组 + */ + String getDeptAndChild(Long deptId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java new file mode 100644 index 0000000..bf16642 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java @@ -0,0 +1,125 @@ +package org.dromara.system.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.system.domain.bo.SysDeptBo; +import org.dromara.system.domain.vo.SysDeptVo; + +import java.util.List; + +/** + * 部门管理 服务层 + * + * @author Lion Li + */ +public interface ISysDeptService { + /** + * 查询部门管理数据 + * + * @param dept 部门信息 + * @return 部门信息集合 + */ + List selectDeptList(SysDeptBo dept); + + /** + * 查询部门树结构信息 + * + * @param dept 部门信息 + * @return 部门树信息集合 + */ + List> selectDeptTreeList(SysDeptBo dept); + + /** + * 构建前端所需要下拉树结构 + * + * @param depts 部门列表 + * @return 下拉树结构列表 + */ + List> buildDeptTreeSelect(List depts); + + /** + * 根据角色ID查询部门树信息 + * + * @param roleId 角色ID + * @return 选中部门列表 + */ + List selectDeptListByRoleId(Long roleId); + + /** + * 根据部门ID查询信息 + * + * @param deptId 部门ID + * @return 部门信息 + */ + SysDeptVo selectDeptById(Long deptId); + + /** + * 通过部门ID串查询部门 + * + * @param deptIds 部门id串 + * @return 部门列表信息 + */ + List selectDeptByIds(List deptIds); + + /** + * 根据ID查询所有子部门数(正常状态) + * + * @param deptId 部门ID + * @return 子部门数 + */ + long selectNormalChildrenDeptById(Long deptId); + + /** + * 是否存在部门子节点 + * + * @param deptId 部门ID + * @return 结果 + */ + boolean hasChildByDeptId(Long deptId); + + /** + * 查询部门是否存在用户 + * + * @param deptId 部门ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkDeptExistUser(Long deptId); + + /** + * 校验部门名称是否唯一 + * + * @param dept 部门信息 + * @return 结果 + */ + boolean checkDeptNameUnique(SysDeptBo dept); + + /** + * 校验部门是否有数据权限 + * + * @param deptId 部门id + */ + void checkDeptDataScope(Long deptId); + + /** + * 新增保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + int insertDept(SysDeptBo bo); + + /** + * 修改保存部门信息 + * + * @param bo 部门信息 + * @return 结果 + */ + int updateDept(SysDeptBo bo); + + /** + * 删除部门管理信息 + * + * @param deptId 部门ID + * @return 结果 + */ + int deleteDeptById(Long deptId); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java new file mode 100644 index 0000000..3b32d6c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java @@ -0,0 +1,95 @@ +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.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysDictTypeVo; + +import java.util.List; + +/** + * 字典 业务层 + * + * @author Lion Li + */ +public interface ISysDictTypeService { + + + TableDataInfo selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery); + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + List selectDictTypeList(SysDictTypeBo dictType); + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + List selectDictTypeAll(); + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + List selectDictDataByType(String dictType); + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + SysDictTypeVo selectDictTypeById(Long dictId); + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + SysDictTypeVo selectDictTypeByType(String dictType); + + /** + * 批量删除字典信息 + * + * @param dictIds 需要删除的字典ID + */ + void deleteDictTypeByIds(Long[] dictIds); + + /** + * 重置字典缓存数据 + */ + void resetDictCache(); + + /** + * 新增保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + List insertDictType(SysDictTypeBo bo); + + /** + * 修改保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + List updateDictType(SysDictTypeBo bo); + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + boolean checkDictTypeUnique(SysDictTypeBo dictType); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java new file mode 100644 index 0000000..6b3b7a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java @@ -0,0 +1,47 @@ +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.SysLogininforBo; +import org.dromara.system.domain.vo.SysLogininforVo; + +import java.util.List; + +/** + * 系统访问日志情况信息 服务层 + * + * @author Lion Li + */ +public interface ISysLogininforService { + + + TableDataInfo selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery); + + /** + * 新增系统登录日志 + * + * @param bo 访问日志对象 + */ + void insertLogininfor(SysLogininforBo bo); + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + List selectLogininforList(SysLogininforBo logininfor); + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + int deleteLogininforByIds(Long[] infoIds); + + /** + * 清空系统登录日志 + */ + void cleanLogininfor(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java new file mode 100644 index 0000000..72d705e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java @@ -0,0 +1,147 @@ +package org.dromara.system.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; + +import java.util.List; +import java.util.Set; + +/** + * 菜单 业务层 + * + * @author Lion Li + */ +public interface ISysMenuService { + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(Long userId); + + /** + * 根据用户查询系统菜单列表 + * + * @param menu 菜单信息 + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuList(SysMenuBo menu, Long userId); + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectMenuPermsByUserId(Long userId); + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + Set selectMenuPermsByRoleId(Long roleId); + + /** + * 根据用户ID查询菜单树信息 + * + * @param userId 用户ID + * @return 菜单列表 + */ + List selectMenuTreeByUserId(Long userId); + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + List selectMenuListByRoleId(Long roleId); + + /** + * 根据租户套餐ID查询菜单树信息 + * + * @param packageId 租户套餐ID + * @return 选中菜单列表 + */ + List selectMenuListByPackageId(Long packageId); + + /** + * 构建前端路由所需要的菜单 + * + * @param menus 菜单列表 + * @return 路由列表 + */ + List buildMenus(List menus); + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + List> buildMenuTreeSelect(List menus); + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + SysMenuVo selectMenuById(Long menuId); + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean hasChildByMenuId(Long menuId); + + /** + * 查询菜单是否存在角色 + * + * @param menuId 菜单ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkMenuExistRole(Long menuId); + + /** + * 新增保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + int insertMenu(SysMenuBo bo); + + /** + * 修改保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + int updateMenu(SysMenuBo bo); + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + int deleteMenuById(Long menuId); + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + boolean checkMenuNameUnique(SysMenuBo menu); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java new file mode 100644 index 0000000..8ec999d --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java @@ -0,0 +1,67 @@ +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.SysNoticeBo; +import org.dromara.system.domain.vo.SysNoticeVo; + +import java.util.List; + +/** + * 公告 服务层 + * + * @author Lion Li + */ +public interface ISysNoticeService { + + + TableDataInfo selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery); + + /** + * 查询公告信息 + * + * @param noticeId 公告ID + * @return 公告信息 + */ + SysNoticeVo selectNoticeById(Long noticeId); + + /** + * 查询公告列表 + * + * @param notice 公告信息 + * @return 公告集合 + */ + List selectNoticeList(SysNoticeBo notice); + + /** + * 新增公告 + * + * @param bo 公告信息 + * @return 结果 + */ + int insertNotice(SysNoticeBo bo); + + /** + * 修改公告 + * + * @param bo 公告信息 + * @return 结果 + */ + int updateNotice(SysNoticeBo bo); + + /** + * 删除公告信息 + * + * @param noticeId 公告ID + * @return 结果 + */ + int deleteNoticeById(Long noticeId); + + /** + * 批量删除公告信息 + * + * @param noticeIds 需要删除的公告ID + * @return 结果 + */ + int deleteNoticeByIds(Long[] noticeIds); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java new file mode 100644 index 0000000..9573510 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java @@ -0,0 +1,54 @@ +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.SysOperLogBo; +import org.dromara.system.domain.vo.SysOperLogVo; + +import java.util.List; + +/** + * 操作日志 服务层 + * + * @author Lion Li + */ +public interface ISysOperLogService { + + TableDataInfo selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery); + + /** + * 新增操作日志 + * + * @param bo 操作日志对象 + */ + void insertOperlog(SysOperLogBo bo); + + /** + * 查询系统操作日志集合 + * + * @param operLog 操作日志对象 + * @return 操作日志集合 + */ + List selectOperLogList(SysOperLogBo operLog); + + /** + * 批量删除系统操作日志 + * + * @param operIds 需要删除的操作日志ID + * @return 结果 + */ + int deleteOperLogByIds(Long[] operIds); + + /** + * 查询操作日志详细 + * + * @param operId 操作ID + * @return 操作日志对象 + */ + SysOperLogVo selectOperLogById(Long operId); + + /** + * 清空操作日志 + */ + void cleanOperLog(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java new file mode 100644 index 0000000..2f6dfc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java @@ -0,0 +1,64 @@ +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.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; + +import java.util.Collection; + +/** + * 对象存储配置Service接口 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +public interface ISysOssConfigService { + + /** + * 初始化OSS配置 + */ + void init(); + + /** + * 查询单个 + */ + SysOssConfigVo queryById(Long ossConfigId); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(SysOssConfigBo bo, PageQuery pageQuery); + + /** + * 根据新增业务对象插入对象存储配置 + * + * @param bo 对象存储配置新增业务对象 + * @return 结果 + */ + Boolean insertByBo(SysOssConfigBo bo); + + /** + * 根据编辑业务对象修改对象存储配置 + * + * @param bo 对象存储配置编辑业务对象 + * @return 结果 + */ + Boolean updateByBo(SysOssConfigBo bo); + + /** + * 校验并删除数据 + * + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return 结果 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 启用停用状态 + */ + int updateOssConfigStatus(SysOssConfigBo bo); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java new file mode 100644 index 0000000..0116df5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java @@ -0,0 +1,28 @@ +package org.dromara.system.service; + +import java.util.Set; + +/** + * 用户权限处理 + * + * @author Lion Li + */ +public interface ISysPermissionService { + + /** + * 获取角色数据权限 + * + * @param userId 用户id + * @return 角色权限信息 + */ + Set getRolePermission(Long userId); + + /** + * 获取菜单数据权限 + * + * @param userId 用户id + * @return 菜单权限信息 + */ + Set getMenuPermission(Long userId); + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java new file mode 100644 index 0000000..a760d49 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java @@ -0,0 +1,130 @@ +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.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; + +import java.util.List; + +/** + * 岗位信息 服务层 + * + * @author Lion Li + */ +public interface ISysPostService { + + + TableDataInfo selectPagePostList(SysPostBo post, PageQuery pageQuery); + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位列表 + */ + List selectPostList(SysPostBo post); + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 岗位ID + */ + List selectPostsByUserId(Long userId); + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + List selectPostAll(); + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + SysPostVo selectPostById(Long postId); + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + List selectPostListByUserId(Long userId); + + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + List selectPostByIds(List postIds); + + /** + * 校验岗位名称 + * + * @param post 岗位信息 + * @return 结果 + */ + boolean checkPostNameUnique(SysPostBo post); + + /** + * 校验岗位编码 + * + * @param post 岗位信息 + * @return 结果 + */ + boolean checkPostCodeUnique(SysPostBo post); + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + long countUserPostById(Long postId); + + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 结果 + */ + long countPostByDeptId(Long deptId); + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + int deletePostById(Long postId); + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + int deletePostByIds(Long[] postIds); + + /** + * 新增保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + int insertPost(SysPostBo bo); + + /** + * 修改保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + int updatePost(SysPostBo bo); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java new file mode 100644 index 0000000..a5e6e4c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java @@ -0,0 +1,202 @@ +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.SysRole; +import org.dromara.system.domain.SysUserRole; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; + +import java.util.List; +import java.util.Set; + +/** + * 角色业务层 + * + * @author Lion Li + */ +public interface ISysRoleService { + + + TableDataInfo selectPageRoleList(SysRoleBo role, PageQuery pageQuery); + + /** + * 根据条件分页查询角色数据 + * + * @param role 角色信息 + * @return 角色数据集合信息 + */ + List selectRoleList(SysRoleBo role); + + /** + * 根据用户ID查询角色列表 + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesByUserId(Long userId); + + /** + * 根据用户ID查询角色列表(包含被授权状态) + * + * @param userId 用户ID + * @return 角色列表 + */ + List selectRolesAuthByUserId(Long userId); + + /** + * 根据用户ID查询角色权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + Set selectRolePermissionByUserId(Long userId); + + /** + * 查询所有角色 + * + * @return 角色列表 + */ + List selectRoleAll(); + + /** + * 根据用户ID获取角色选择框列表 + * + * @param userId 用户ID + * @return 选中角色ID列表 + */ + List selectRoleListByUserId(Long userId); + + /** + * 通过角色ID查询角色 + * + * @param roleId 角色ID + * @return 角色对象信息 + */ + SysRoleVo selectRoleById(Long roleId); + + /** + * 通过角色ID串查询角色 + * + * @param roleIds 角色ID串 + * @return 角色列表信息 + */ + List selectRoleByIds(List roleIds); + + /** + * 校验角色名称是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + boolean checkRoleNameUnique(SysRoleBo role); + + /** + * 校验角色权限是否唯一 + * + * @param role 角色信息 + * @return 结果 + */ + boolean checkRoleKeyUnique(SysRoleBo role); + + /** + * 校验角色是否允许操作 + * + * @param role 角色信息 + */ + void checkRoleAllowed(SysRoleBo role); + + /** + * 校验角色是否有数据权限 + * + * @param roleId 角色id + */ + void checkRoleDataScope(Long roleId); + + /** + * 通过角色ID查询角色使用数量 + * + * @param roleId 角色ID + * @return 结果 + */ + long countUserRoleByRoleId(Long roleId); + + /** + * 新增保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + int insertRole(SysRoleBo bo); + + /** + * 修改保存角色信息 + * + * @param bo 角色信息 + * @return 结果 + */ + int updateRole(SysRoleBo bo); + + /** + * 修改角色状态 + * + * @param roleId 角色ID + * @param status 角色状态 + * @return 结果 + */ + int updateRoleStatus(Long roleId, String status); + + /** + * 修改数据权限信息 + * + * @param bo 角色信息 + * @return 结果 + */ + int authDataScope(SysRoleBo bo); + + /** + * 通过角色ID删除角色 + * + * @param roleId 角色ID + * @return 结果 + */ + int deleteRoleById(Long roleId); + + /** + * 批量删除角色信息 + * + * @param roleIds 需要删除的角色ID + * @return 结果 + */ + int deleteRoleByIds(Long[] roleIds); + + /** + * 取消授权用户角色 + * + * @param userRole 用户和角色关联信息 + * @return 结果 + */ + int deleteAuthUser(SysUserRole userRole); + + /** + * 批量取消授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要取消授权的用户数据ID + * @return 结果 + */ + int deleteAuthUsers(Long roleId, Long[] userIds); + + /** + * 批量选择授权用户角色 + * + * @param roleId 角色ID + * @param userIds 需要删除的用户数据ID + * @return 结果 + */ + int insertAuthUsers(Long roleId, Long[] userIds); + + void cleanOnlineUserByRole(Long roleId); + + void cleanOnlineUser(List userIds); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java new file mode 100644 index 0000000..cc7016e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java @@ -0,0 +1,53 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.SysSocialVo; + +import java.util.List; + +/** + * 社会化关系Service接口 + * + * @author thiszhc + */ +public interface ISysSocialService { + + + /** + * 查询社会化关系 + */ + SysSocialVo queryById(String id); + + /** + * 查询社会化关系列表 + */ + List queryList(SysSocialBo bo); + + /** + * 查询社会化关系列表 + */ + List queryListByUserId(Long userId); + + /** + * 新增授权关系 + */ + Boolean insertByBo(SysSocialBo bo); + + /** + * 更新社会化关系 + */ + Boolean updateByBo(SysSocialBo bo); + + /** + * 删除社会化关系信息 + */ + Boolean deleteWithValidById(Long id); + + + /** + * 根据 authId 查询 + */ + List selectByAuthId(String authId); + + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java new file mode 100644 index 0000000..f697829 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java @@ -0,0 +1,87 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.domain.bo.SysTenantBo; +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 Michelle.Chung + */ +public interface ISysTenantService { + + /** + * 查询租户 + */ + SysTenantVo queryById(Long id); + + /** + * 基于租户ID查询租户 + */ + SysTenantVo queryByTenantId(String tenantId); + + /** + * 查询租户列表 + */ + TableDataInfo queryPageList(SysTenantBo bo, PageQuery pageQuery); + + /** + * 查询租户列表 + */ + List queryList(SysTenantBo bo); + + /** + * 新增租户 + */ + Boolean insertByBo(SysTenantBo bo); + + /** + * 修改租户 + */ + Boolean updateByBo(SysTenantBo bo); + + /** + * 修改租户状态 + */ + int updateTenantStatus(SysTenantBo bo); + + /** + * 校验租户是否允许操作 + */ + void checkTenantAllowed(String tenantId); + + /** + * 校验并批量删除租户信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 校验企业名称是否唯一 + */ + boolean checkCompanyNameUnique(SysTenantBo bo); + + /** + * 校验账号余额 + */ + boolean checkAccountBalance(String tenantId); + + /** + * 校验有效期 + */ + boolean checkExpireTime(String tenantId); + + /** + * 同步租户套餐 + */ + Boolean syncTenantPackage(String tenantId, Long packageId); + + /** + * 同步租户字典 + */ + void syncTenantDict(); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java new file mode 100644 index 0000000..024b142 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java @@ -0,0 +1,238 @@ +package org.dromara.system.service; + +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.bo.SysUserBo; +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 + */ +public interface ISysUserService { + + + TableDataInfo selectPageUserList(SysUserBo user, PageQuery pageQuery); + + + List selectUserWarehouseNameList(); + /** + * 根据条件分页查询用户列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + List selectUserExportList(SysUserBo user); + + /** + * 根据条件分页查询已分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + TableDataInfo selectAllocatedList(SysUserBo user, PageQuery pageQuery); + + /** + * 根据条件分页查询未分配用户角色列表 + * + * @param user 用户信息 + * @return 用户信息集合信息 + */ + TableDataInfo selectUnallocatedList(SysUserBo user, PageQuery pageQuery); + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + SysUserVo selectUserByUserName(String userName); + + /** + * 通过手机号查询用户 + * + * @param phoneNumber 用户名 + * @return 用户对象信息 + */ + SysUserVo selectUserByPhonenumber(String phoneNumber); + + /** + * 通过用户ID查询用户 + * + * @param userId 用户ID + * @return 用户对象信息 + */ + SysUserVo selectUserById(Long userId); + + /** + * 通过用户ID串查询用户 + * + * @param userIds 用户ID串 + * @param deptId 部门id + * @return 用户列表信息 + */ + List selectUserByIds(List userIds, Long deptId); + + /** + * 根据用户ID查询用户所属角色组 + * + * @param userId 用户ID + * @return 结果 + */ + String selectUserRoleGroup(Long userId); + + /** + * 根据用户ID查询用户所属岗位组 + * + * @param userId 用户ID + * @return 结果 + */ + String selectUserPostGroup(Long userId); + + /** + * 校验用户名称是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkUserNameUnique(SysUserBo user); + + /** + * 校验手机号码是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkPhoneUnique(SysUserBo user); + + /** + * 校验email是否唯一 + * + * @param user 用户信息 + * @return 结果 + */ + boolean checkEmailUnique(SysUserBo user); + + /** + * 校验用户是否允许操作 + * + * @param userId 用户ID + */ + void checkUserAllowed(Long userId); + + /** + * 校验用户是否有数据权限 + * + * @param userId 用户id + */ + void checkUserDataScope(Long userId); + + /** + * 新增用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int insertUser(SysUserBo user); + + /** + * 注册用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + boolean registerUser(SysUserBo user, String tenantId); + + /** + * 修改用户信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUser(SysUserBo user); + + /** + * 用户授权角色 + * + * @param userId 用户ID + * @param roleIds 角色组 + */ + void insertUserAuth(Long userId, Long[] roleIds); + + /** + * 修改用户状态 + * + * @param userId 用户ID + * @param status 帐号状态 + * @return 结果 + */ + int updateUserStatus(Long userId, String status); + + /** + * 修改用户基本信息 + * + * @param user 用户信息 + * @return 结果 + */ + int updateUserProfile(SysUserBo user); + + /** + * 修改用户头像 + * + * @param userId 用户ID + * @param avatar 头像地址 + * @return 结果 + */ + boolean updateUserAvatar(Long userId, Long avatar); + + /** + * 重置用户密码 + * + * @param userId 用户ID + * @param password 密码 + * @return 结果 + */ + int resetUserPwd(Long userId, String password); + + /** + * 通过用户ID删除用户 + * + * @param userId 用户ID + * @return 结果 + */ + int deleteUserById(Long userId); + + /** + * 批量删除用户信息 + * + * @param userIds 需要删除的用户ID + * @return 结果 + */ + int deleteUserByIds(Long[] userIds); + + /** + * 通过部门id查询当前部门所有用户 + * + * @param deptId 部门id + * @return 结果 + */ + List selectUserListByDept(Long deptId); + + + boolean updateOpenIdByPhoneNumber(String phoneNumber, String openid); + + SysUserVo selectUserByOpenid(String openid, String phoneNumber); + + void insertUserOpenId(String openid, String phonenumber); + + + List selectUserName(); + + SysUserVo selectUserByUserId(Long userId); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IUserTransferService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IUserTransferService.java new file mode 100644 index 0000000..29f330b --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/IUserTransferService.java @@ -0,0 +1,40 @@ +package org.dromara.system.service; + +import org.dromara.system.domain.UserTransferDTO; + + +import java.math.BigDecimal; + +/** + * 用户资金转移服务 + */ +public interface IUserTransferService { + + /** + * 从余额转到冻结资金 + * @param fromUserId 转出用户ID + * @param toUserId 转入用户ID + * @param amount 金额(分) + * @return 是否成功 + */ + boolean transferBalanceToFreeze(Long fromUserId, Long toUserId, Long amount); + + /** + * 从冻结资金转到余额 + * @param fromUserId 转出用户ID + * @param toUserId 转入用户ID + * @param amount 金额(分) + * @return 是否成功 + */ + boolean transferFreezeToBalance(Long fromUserId, Long toUserId, Long amount); + + /** + * 修改用户余额 + * + * @param userId 用户ID + * @param balance 金额 + * @return 影响行数 + */ + int updateBalance(Long userId, Long balance); + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java new file mode 100644 index 0000000..4f6e676 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java @@ -0,0 +1,151 @@ +package org.dromara.system.service.impl; + +import cn.hutool.crypto.SecureUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +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 lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheNames; +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.system.domain.SysClient; +import org.dromara.system.domain.bo.SysClientBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.mapper.SysClientMapper; +import org.dromara.system.service.ISysClientService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; + +/** + * 客户端管理Service业务层处理 + * + * @author Michelle.Chung + * @date 2023-06-18 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysClientServiceImpl implements ISysClientService { + + private final SysClientMapper baseMapper; + + /** + * 查询客户端管理 + */ + @Override + public SysClientVo queryById(Long id) { + SysClientVo vo = baseMapper.selectVoById(id); + vo.setGrantTypeList(List.of(vo.getGrantType().split(","))); + return vo; + } + + + /** + * 查询客户端管理 + */ + @Cacheable(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") + @Override + public SysClientVo queryByClientId(String clientId) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysClient::getClientId, clientId)); + } + + /** + * 查询客户端管理列表 + */ + @Override + public TableDataInfo queryPageList(SysClientBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + result.getRecords().forEach(r -> r.setGrantTypeList(List.of(r.getGrantType().split(",")))); + return TableDataInfo.build(result); + } + + /** + * 查询客户端管理列表 + */ + @Override + public List queryList(SysClientBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysClientBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getClientId()), SysClient::getClientId, bo.getClientId()); + lqw.eq(StringUtils.isNotBlank(bo.getClientKey()), SysClient::getClientKey, bo.getClientKey()); + lqw.eq(StringUtils.isNotBlank(bo.getClientSecret()), SysClient::getClientSecret, bo.getClientSecret()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysClient::getStatus, bo.getStatus()); + lqw.orderByAsc(SysClient::getId); + return lqw; + } + + /** + * 新增客户端管理 + */ + @Override + public Boolean insertByBo(SysClientBo bo) { + SysClient add = MapstructUtils.convert(bo, SysClient.class); + validEntityBeforeSave(add); + add.setGrantType(String.join(",", bo.getGrantTypeList())); + // 生成clientid + String clientKey = bo.getClientKey(); + String clientSecret = bo.getClientSecret(); + add.setClientId(SecureUtil.md5(clientKey + clientSecret)); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改客户端管理 + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#bo.clientId") + @Override + public Boolean updateByBo(SysClientBo bo) { + SysClient update = MapstructUtils.convert(bo, SysClient.class); + validEntityBeforeSave(update); + update.setGrantType(String.join(",", bo.getGrantTypeList())); + return baseMapper.updateById(update) > 0; + } + + /** + * 修改状态 + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId") + @Override + public int updateClientStatus(String clientId, String status) { + return baseMapper.update(null, + new LambdaUpdateWrapper() + .set(SysClient::getStatus, status) + .eq(SysClient::getClientId, clientId)); + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysClient entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除客户端管理 + */ + @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, allEntries = true) + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java new file mode 100644 index 0000000..966a8f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java @@ -0,0 +1,216 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.dynamic.datasource.annotation.DS; +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.constant.CacheNames; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.ConfigService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.core.utils.SpringUtils; +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.redis.utils.CacheUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysConfig; +import org.dromara.system.domain.bo.SysConfigBo; +import org.dromara.system.domain.vo.SysConfigVo; +import org.dromara.system.mapper.SysConfigMapper; +import org.dromara.system.service.ISysConfigService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * 参数配置 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysConfigServiceImpl implements ISysConfigService, ConfigService { + + private final SysConfigMapper baseMapper; + + @Override + public TableDataInfo selectPageConfigList(SysConfigBo config, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(config); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 查询参数配置信息 + * + * @param configId 参数配置ID + * @return 参数配置信息 + */ + @Override + @DS("master") + public SysConfigVo selectConfigById(Long configId) { + return baseMapper.selectVoById(configId); + } + + /** + * 根据键名查询参数配置信息 + * + * @param configKey 参数key + * @return 参数键值 + */ + // @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey") + @Override + public String selectConfigByKey(String configKey) { + SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper().eq(SysConfig::getConfigKey, configKey)); + return ObjectUtils.notNullGetter(retConfig, SysConfig::getConfigValue, StringUtils.EMPTY); + } + + /** + * 获取注册开关 + * @param tenantId 租户id + * @return true开启,false关闭 + */ + @Override + public boolean selectRegisterEnabled(String tenantId) { + SysConfig retConfig = TenantHelper.dynamic(tenantId, () -> { + return baseMapper.selectOne(new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, "sys.account.registerUser")); + }); + if (ObjectUtil.isNull(retConfig)) { + return false; + } + return Convert.toBool(retConfig.getConfigValue()); + } + + /** + * 查询参数配置列表 + * + * @param config 参数配置信息 + * @return 参数配置集合 + */ + @Override + public List selectConfigList(SysConfigBo config) { + LambdaQueryWrapper lqw = buildQueryWrapper(config); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysConfigBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getConfigName()), SysConfig::getConfigName, bo.getConfigName()); + lqw.eq(StringUtils.isNotBlank(bo.getConfigType()), SysConfig::getConfigType, bo.getConfigType()); + lqw.like(StringUtils.isNotBlank(bo.getConfigKey()), SysConfig::getConfigKey, bo.getConfigKey()); + lqw.between(params.get("beginTime") != null && params.get("endTime") != null, + SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime")); + lqw.orderByAsc(SysConfig::getConfigId); + return lqw; + } + + /** + * 新增参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey") + @Override + public String insertConfig(SysConfigBo bo) { + SysConfig config = MapstructUtils.convert(bo, SysConfig.class); + int row = baseMapper.insert(config); + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改参数配置 + * + * @param bo 参数配置信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey") + @Override + public String updateConfig(SysConfigBo bo) { + int row = 0; + SysConfig config = MapstructUtils.convert(bo, SysConfig.class); + if (config.getConfigId() != null) { + SysConfig temp = baseMapper.selectById(config.getConfigId()); + if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) { + CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey()); + } + row = baseMapper.updateById(config); + } else { + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); + row = baseMapper.update(config, new LambdaQueryWrapper() + .eq(SysConfig::getConfigKey, config.getConfigKey())); + } + if (row > 0) { + return config.getConfigValue(); + } + throw new ServiceException("操作失败"); + } + + /** + * 批量删除参数信息 + * + * @param configIds 需要删除的参数ID + */ + @Override + public void deleteConfigByIds(Long[] configIds) { + for (Long configId : configIds) { + SysConfig config = baseMapper.selectById(configId); + if (StringUtils.equals(SystemConstants.YES, config.getConfigType())) { + throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey())); + } + CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey()); + } + baseMapper.deleteByIds(Arrays.asList(configIds)); + } + + /** + * 重置参数缓存数据 + */ + @Override + public void resetConfigCache() { + CacheUtils.clear(CacheNames.SYS_CONFIG); + } + + /** + * 校验参数键名是否唯一 + * + * @param config 参数配置信息 + * @return 结果 + */ + @Override + public boolean checkConfigKeyUnique(SysConfigBo config) { + long configId = ObjectUtils.notNull(config.getConfigId(), -1L); + SysConfig info = baseMapper.selectOne(new LambdaQueryWrapper().eq(SysConfig::getConfigKey, config.getConfigKey())); + if (ObjectUtil.isNotNull(info) && info.getConfigId() != configId) { + return false; + } + return true; + } + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + @Override + public String getConfigValue(String configKey) { + return SpringUtils.getAopProxy(this).selectConfigByKey(configKey); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java new file mode 100644 index 0000000..12a5072 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java @@ -0,0 +1,78 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.system.domain.SysDept; +import org.dromara.system.domain.SysRoleDept; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysRoleDeptMapper; +import org.dromara.system.service.ISysDataScopeService; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 数据权限 实现 + *

+ * 注意: 此Service内不允许调用标注`数据权限`注解的方法 + * 例如: deptMapper.selectList 此 selectList 方法标注了`数据权限`注解 会出现循环解析的问题 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service("sdss") +public class SysDataScopeServiceImpl implements ISysDataScopeService { + + private final SysRoleDeptMapper roleDeptMapper; + private final SysDeptMapper deptMapper; + + /** + * 获取角色自定义权限 + * + * @param roleId 角色Id + * @return 部门Id组 + */ + @Cacheable(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId", condition = "#roleId != null") + @Override + public String getRoleCustom(Long roleId) { + if (ObjectUtil.isNull(roleId)) { + return "-1"; + } + List list = roleDeptMapper.selectList( + new LambdaQueryWrapper() + .select(SysRoleDept::getDeptId) + .eq(SysRoleDept::getRoleId, roleId)); + if (CollUtil.isNotEmpty(list)) { + return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId())); + } + return "-1"; + } + + /** + * 获取部门及以下权限 + * + * @param deptId 部门Id + * @return 部门Id组 + */ + @Cacheable(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId", condition = "#deptId != null") + @Override + public String getDeptAndChild(Long deptId) { + if (ObjectUtil.isNull(deptId)) { + return "-1"; + } + List deptList = deptMapper.selectListByParentId(deptId); + List ids = StreamUtils.toList(deptList, SysDept::getDeptId); + ids.add(deptId); + if (CollUtil.isNotEmpty(ids)) { + return StreamUtils.join(ids, Convert::toStr); + } + return "-1"; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java new file mode 100644 index 0000000..e44fdbc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java @@ -0,0 +1,157 @@ +package org.dromara.system.service.impl; + +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 org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ObjectUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.system.domain.SysDictData; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.system.domain.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.mapper.SysDictDataMapper; +import org.dromara.system.service.ISysDictDataService; +import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CachePut; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 字典 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDictDataServiceImpl implements ISysDictDataService { + + private final SysDictDataMapper baseMapper; + + @Override + public TableDataInfo selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictData); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询字典数据 + * + * @param dictData 字典数据信息 + * @return 字典数据集合信息 + */ + @Override + public List selectDictDataList(SysDictDataBo dictData) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictData); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysDictDataBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getDictSort() != null, SysDictData::getDictSort, bo.getDictSort()); + lqw.like(StringUtils.isNotBlank(bo.getDictLabel()), SysDictData::getDictLabel, bo.getDictLabel()); + lqw.eq(StringUtils.isNotBlank(bo.getDictType()), SysDictData::getDictType, bo.getDictType()); + lqw.orderByAsc(SysDictData::getDictSort); + return lqw; + } + + /** + * 根据字典类型和字典键值查询字典数据信息 + * + * @param dictType 字典类型 + * @param dictValue 字典键值 + * @return 字典标签 + */ + @Override + public String selectDictLabel(String dictType, String dictValue) { + return baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysDictData::getDictLabel) + .eq(SysDictData::getDictType, dictType) + .eq(SysDictData::getDictValue, dictValue)) + .getDictLabel(); + } + + /** + * 根据字典数据ID查询信息 + * + * @param dictCode 字典数据ID + * @return 字典数据 + */ + @Override + public SysDictDataVo selectDictDataById(Long dictCode) { + return baseMapper.selectVoById(dictCode); + } + + /** + * 批量删除字典数据信息 + * + * @param dictCodes 需要删除的字典数据ID + */ + @Override + public void deleteDictDataByIds(Long[] dictCodes) { + for (Long dictCode : dictCodes) { + SysDictData data = baseMapper.selectById(dictCode); + baseMapper.deleteById(dictCode); + CacheUtils.evict(CacheNames.SYS_DICT, data.getDictType()); + } + } + + /** + * 新增保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List insertDictData(SysDictDataBo bo) { + SysDictData data = MapstructUtils.convert(bo, SysDictData.class); + int row = baseMapper.insert(data); + if (row > 0) { + return baseMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改保存字典数据信息 + * + * @param bo 字典数据信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List updateDictData(SysDictDataBo bo) { + SysDictData data = MapstructUtils.convert(bo, SysDictData.class); + int row = baseMapper.updateById(data); + if (row > 0) { + return baseMapper.selectDictDataByType(data.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 校验字典键值是否唯一 + * + * @param dict 字典数据 + * @return 结果 + */ + @Override + public boolean checkDictDataUnique(SysDictDataBo dict) { + Long dictCode = ObjectUtils.notNull(dict.getDictCode(), -1L); + SysDictData entity = baseMapper.selectOne(new LambdaQueryWrapper() + .eq(SysDictData::getDictType, dict.getDictType()).eq(SysDictData::getDictValue, dict.getDictValue())); + if (ObjectUtil.isNotNull(entity) && !dictCode.equals(entity.getDictCode())) { + return false; + } + return true; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java new file mode 100644 index 0000000..1be0b7f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java @@ -0,0 +1,258 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +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 com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.DictService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +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.redis.utils.CacheUtils; +import org.dromara.system.domain.SysDictData; +import org.dromara.system.domain.SysDictType; +import org.dromara.system.domain.bo.SysDictTypeBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysDictTypeVo; +import org.dromara.system.mapper.SysDictDataMapper; +import org.dromara.system.mapper.SysDictTypeMapper; +import org.dromara.system.service.ISysDictTypeService; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 字典 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService { + + private final SysDictTypeMapper baseMapper; + private final SysDictDataMapper dictDataMapper; + + @Override + public TableDataInfo selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictType); + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 根据条件分页查询字典类型 + * + * @param dictType 字典类型信息 + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeList(SysDictTypeBo dictType) { + LambdaQueryWrapper lqw = buildQueryWrapper(dictType); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysDictTypeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getDictName()), SysDictType::getDictName, bo.getDictName()); + lqw.like(StringUtils.isNotBlank(bo.getDictType()), SysDictType::getDictType, bo.getDictType()); + lqw.between(params.get("beginTime") != null && params.get("endTime") != null, + SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime")); + lqw.orderByAsc(SysDictType::getDictId); + return lqw; + } + + /** + * 根据所有字典类型 + * + * @return 字典类型集合信息 + */ + @Override + public List selectDictTypeAll() { + return baseMapper.selectVoList(); + } + + /** + * 根据字典类型查询字典数据 + * + * @param dictType 字典类型 + * @return 字典数据集合信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType") + @Override + public List selectDictDataByType(String dictType) { + List dictDatas = dictDataMapper.selectDictDataByType(dictType); + if (CollUtil.isNotEmpty(dictDatas)) { + return dictDatas; + } + return null; + } + + /** + * 根据字典类型ID查询信息 + * + * @param dictId 字典类型ID + * @return 字典类型 + */ + @Override + public SysDictTypeVo selectDictTypeById(Long dictId) { + return baseMapper.selectVoById(dictId); + } + + /** + * 根据字典类型查询信息 + * + * @param dictType 字典类型 + * @return 字典类型 + */ + @Override + public SysDictTypeVo selectDictTypeByType(String dictType) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysDictType::getDictType, dictType)); + } + + /** + * 批量删除字典类型信息 + * + * @param dictIds 需要删除的字典ID + */ + @Override + public void deleteDictTypeByIds(Long[] dictIds) { + for (Long dictId : dictIds) { + SysDictType dictType = baseMapper.selectById(dictId); + if (dictDataMapper.exists(new LambdaQueryWrapper() + .eq(SysDictData::getDictType, dictType.getDictType()))) { + throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName())); + } + CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType()); + } + baseMapper.deleteByIds(Arrays.asList(dictIds)); + } + + /** + * 重置字典缓存数据 + */ + @Override + public void resetDictCache() { + CacheUtils.clear(CacheNames.SYS_DICT); + } + + /** + * 新增保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + public List insertDictType(SysDictTypeBo bo) { + SysDictType dict = MapstructUtils.convert(bo, SysDictType.class); + int row = baseMapper.insert(dict); + if (row > 0) { + // 新增 type 下无 data 数据 返回空防止缓存穿透 + return new ArrayList<>(); + } + throw new ServiceException("操作失败"); + } + + /** + * 修改保存字典类型信息 + * + * @param bo 字典类型信息 + * @return 结果 + */ + @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType") + @Override + @Transactional(rollbackFor = Exception.class) + public List updateDictType(SysDictTypeBo bo) { + SysDictType dict = MapstructUtils.convert(bo, SysDictType.class); + SysDictType oldDict = baseMapper.selectById(dict.getDictId()); + dictDataMapper.update(null, new LambdaUpdateWrapper() + .set(SysDictData::getDictType, dict.getDictType()) + .eq(SysDictData::getDictType, oldDict.getDictType())); + int row = baseMapper.updateById(dict); + if (row > 0) { + CacheUtils.evict(CacheNames.SYS_DICT, oldDict.getDictType()); + return dictDataMapper.selectDictDataByType(dict.getDictType()); + } + throw new ServiceException("操作失败"); + } + + /** + * 校验字典类型称是否唯一 + * + * @param dictType 字典类型 + * @return 结果 + */ + @Override + public boolean checkDictTypeUnique(SysDictTypeBo dictType) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysDictType::getDictType, dictType.getDictType()) + .ne(ObjectUtil.isNotNull(dictType.getDictId()), SysDictType::getDictId, dictType.getDictId())); + return !exist; + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + @Override + public String getDictLabel(String dictType, String dictValue, String separator) { + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); + if (StringUtils.containsAny(dictValue, separator)) { + return Arrays.stream(dictValue.split(separator)) + .map(v -> map.getOrDefault(v, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictValue, StringUtils.EMPTY); + } + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + @Override + public String getDictValue(String dictType, String dictLabel, String separator) { + List datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType); + Map map = StreamUtils.toMap(datas, SysDictDataVo::getDictLabel, SysDictDataVo::getDictValue); + if (StringUtils.containsAny(dictLabel, separator)) { + return Arrays.stream(dictLabel.split(separator)) + .map(l -> map.getOrDefault(l, StringUtils.EMPTY)) + .collect(Collectors.joining(separator)); + } else { + return map.getOrDefault(dictLabel, StringUtils.EMPTY); + } + } + + @Override + public Map getAllDictByDictType(String dictType) { + List list = selectDictDataByType(dictType); + return StreamUtils.toMap(list, SysDictDataVo::getDictValue, SysDictDataVo::getDictLabel); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java new file mode 100644 index 0000000..72b497e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java @@ -0,0 +1,175 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.LogininforEvent; +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.SysLogininfor; +import org.dromara.system.domain.bo.SysLogininforBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysLogininforVo; +import org.dromara.system.mapper.SysLogininforMapper; +import org.dromara.system.service.ISysClientService; +import org.dromara.system.service.ISysLogininforService; +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 +@Slf4j +@Service +public class SysLogininforServiceImpl implements ISysLogininforService { + + private final SysLogininforMapper baseMapper; + + private final ISysClientService clientService; + + /** + * 记录登录信息 + * + * @param logininforEvent 登录事件 + */ + @Async + @EventListener + public void recordLogininfor(LogininforEvent logininforEvent) { + HttpServletRequest request = logininforEvent.getRequest(); + final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent")); + final String ip = ServletUtils.getClientIP(request); + // 客户端信息 + String clientId = request.getHeader(LoginHelper.CLIENT_KEY); + SysClientVo client = null; + if (StringUtils.isNotBlank(clientId)) { + client = clientService.queryByClientId(clientId); + } + + String address = AddressUtils.getRealAddressByIP(ip); + StringBuilder s = new StringBuilder(); + s.append(getBlock(ip)); + s.append(address); + s.append(getBlock(logininforEvent.getUsername())); + s.append(getBlock(logininforEvent.getStatus())); + s.append(getBlock(logininforEvent.getMessage())); + // 打印信息到日志 + log.info(s.toString(), logininforEvent.getArgs()); + // 获取客户端操作系统 + String os = userAgent.getOs().getName(); + // 获取客户端浏览器 + String browser = userAgent.getBrowser().getName(); + // 封装对象 + SysLogininforBo logininfor = new SysLogininforBo(); + logininfor.setTenantId(logininforEvent.getTenantId()); + logininfor.setUserName(logininforEvent.getUsername()); + if (ObjectUtil.isNotNull(client)) { + logininfor.setClientKey(client.getClientKey()); + logininfor.setDeviceType(client.getDeviceType()); + } + logininfor.setIpaddr(ip); + logininfor.setLoginLocation(address); + logininfor.setBrowser(browser); + logininfor.setOs(os); + logininfor.setMsg(logininforEvent.getMessage()); + // 日志状态 + if (StringUtils.equalsAny(logininforEvent.getStatus(), Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) { + logininfor.setStatus(Constants.SUCCESS); + } else if (Constants.LOGIN_FAIL.equals(logininforEvent.getStatus())) { + logininfor.setStatus(Constants.FAIL); + } + // 插入数据 + insertLogininfor(logininfor); + } + + private String getBlock(Object msg) { + if (msg == null) { + msg = ""; + } + return "[" + msg.toString() + "]"; + } + + @Override + public TableDataInfo selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery) { + Map params = logininfor.getParams(); + LambdaQueryWrapper lqw = new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr()) + .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus()) + .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime")); + if (StringUtils.isBlank(pageQuery.getOrderByColumn())) { + lqw.orderByDesc(SysLogininfor::getInfoId); + } + Page page = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(page); + } + + /** + * 新增系统登录日志 + * + * @param bo 访问日志对象 + */ + @Override + public void insertLogininfor(SysLogininforBo bo) { + SysLogininfor logininfor = MapstructUtils.convert(bo, SysLogininfor.class); + logininfor.setLoginTime(new Date()); + baseMapper.insert(logininfor); + } + + /** + * 查询系统登录日志集合 + * + * @param logininfor 访问日志对象 + * @return 登录记录集合 + */ + @Override + public List selectLogininforList(SysLogininforBo logininfor) { + Map params = logininfor.getParams(); + return baseMapper.selectVoList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr()) + .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus()) + .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName()) + .between(params.get("beginTime") != null && params.get("endTime") != null, + SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime")) + .orderByDesc(SysLogininfor::getInfoId)); + } + + /** + * 批量删除系统登录日志 + * + * @param infoIds 需要删除的登录日志ID + * @return 结果 + */ + @Override + public int deleteLogininforByIds(Long[] infoIds) { + return baseMapper.deleteByIds(Arrays.asList(infoIds)); + } + + /** + * 清空系统登录日志 + */ + @Override + public void cleanLogininfor() { + baseMapper.delete(new LambdaQueryWrapper<>()); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java new file mode 100644 index 0000000..40643e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,372 @@ +package org.dromara.system.service.impl; + +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.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +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.core.utils.TreeBuildUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysMenu; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysRoleMenu; +import org.dromara.system.domain.SysTenantPackage; +import org.dromara.system.domain.bo.SysMenuBo; +import org.dromara.system.domain.vo.MetaVo; +import org.dromara.system.domain.vo.RouterVo; +import org.dromara.system.domain.vo.SysMenuVo; +import org.dromara.system.mapper.SysMenuMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysRoleMenuMapper; +import org.dromara.system.mapper.SysTenantPackageMapper; +import org.dromara.system.service.ISysMenuService; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 菜单 业务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysMenuServiceImpl implements ISysMenuService { + + private final SysMenuMapper baseMapper; + private final SysRoleMapper roleMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysTenantPackageMapper tenantPackageMapper; + + /** + * 根据用户查询系统菜单列表 + * + * @param userId 用户ID + * @return 菜单列表 + */ + @Override + public List selectMenuList(Long userId) { + return selectMenuList(new SysMenuBo(), userId); + } + + /** + * 查询系统菜单列表 + * + * @param menu 菜单信息 + * @return 菜单列表 + */ + @Override + public List selectMenuList(SysMenuBo menu, Long userId) { + List menuList; + // 管理员显示所有菜单信息 + if (LoginHelper.isSuperAdmin(userId)) { + menuList = baseMapper.selectVoList(new LambdaQueryWrapper() + .like(StringUtils.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName()) + .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible()) + .eq(StringUtils.isNotBlank(menu.getStatus()), SysMenu::getStatus, menu.getStatus()) + .orderByAsc(SysMenu::getParentId) + .orderByAsc(SysMenu::getOrderNum)); + } else { + QueryWrapper wrapper = Wrappers.query(); + wrapper.inSql("r.role_id", "select role_id from sys_user_role where user_id = " + userId) + .like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName()) + .eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible()) + .eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus()) + .orderByAsc("m.parent_id") + .orderByAsc("m.order_num"); + List list = baseMapper.selectMenuListByUserId(wrapper); + menuList = MapstructUtils.convert(list, SysMenuVo.class); + } + return menuList; + } + + /** + * 根据用户ID查询权限 + * + * @param userId 用户ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByUserId(Long userId) { + List perms = baseMapper.selectMenuPermsByUserId(userId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(StringUtils.splitList(perm.trim())); + } + } + return permsSet; + } + + /** + * 根据角色ID查询权限 + * + * @param roleId 角色ID + * @return 权限列表 + */ + @Override + public Set selectMenuPermsByRoleId(Long roleId) { + List perms = baseMapper.selectMenuPermsByRoleId(roleId); + Set permsSet = new HashSet<>(); + for (String perm : perms) { + if (StringUtils.isNotEmpty(perm)) { + permsSet.addAll(StringUtils.splitList(perm.trim())); + } + } + return permsSet; + } + + /** + * 根据用户ID查询菜单 + * + * @param userId 用户名称 + * @return 菜单列表 + */ + @Override + public List selectMenuTreeByUserId(Long userId) { + List menus; + if (LoginHelper.isSuperAdmin(userId)) { + menus = baseMapper.selectMenuTreeAll(); + } else { + menus = baseMapper.selectMenuTreeByUserId(userId); + } + return getChildPerms(menus, 0); + } + + /** + * 根据角色ID查询菜单树信息 + * + * @param roleId 角色ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByRoleId(Long roleId) { + SysRole role = roleMapper.selectById(roleId); + return baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly()); + } + + /** + * 根据租户套餐ID查询菜单树信息 + * + * @param packageId 租户套餐ID + * @return 选中菜单列表 + */ + @Override + public List selectMenuListByPackageId(Long packageId) { + SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); + List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); + if (CollUtil.isEmpty(menuIds)) { + return List.of(); + } + List parentIds = null; + if (tenantPackage.getMenuCheckStrictly()) { + parentIds = baseMapper.selectObjs(new LambdaQueryWrapper() + .select(SysMenu::getParentId) + .in(SysMenu::getMenuId, menuIds), x -> {return Convert.toLong(x);}); + } + return baseMapper.selectObjs(new LambdaQueryWrapper() + .in(SysMenu::getMenuId, menuIds) + .notIn(CollUtil.isNotEmpty(parentIds), SysMenu::getMenuId, parentIds), x -> {return Convert.toLong(x);}); + } + + /** + * 构建前端路由所需要的菜单 + * 路由name命名规则 path首字母转大写 + id + * + * @param menus 菜单列表 + * @return 路由列表 + */ + @Override + public List buildMenus(List menus) { + List routers = new LinkedList<>(); + for (SysMenu menu : menus) { + String name = menu.getRouteName() + menu.getMenuId(); + RouterVo router = new RouterVo(); + router.setHidden("1".equals(menu.getVisible())); + router.setName(name); + router.setPath(menu.getRouterPath()); + router.setComponent(menu.getComponentInfo()); + router.setQuery(menu.getQueryParam()); + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + List cMenus = menu.getChildren(); + if (CollUtil.isNotEmpty(cMenus) && SystemConstants.TYPE_DIR.equals(menu.getMenuType())) { + router.setAlwaysShow(true); + router.setRedirect("noRedirect"); + router.setChildren(buildMenus(cMenus)); + } else if (menu.isMenuFrame()) { + String frameName = StringUtils.capitalize(menu.getPath()) + menu.getMenuId(); + router.setMeta(null); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + children.setPath(menu.getPath()); + children.setComponent(menu.getComponent()); + children.setName(frameName); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath())); + children.setQuery(menu.getQueryParam()); + childrenList.add(children); + router.setChildren(childrenList); + } else if (menu.getParentId().intValue() == 0 && menu.isInnerLink()) { + router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); + router.setPath("/"); + List childrenList = new ArrayList<>(); + RouterVo children = new RouterVo(); + String routerPath = SysMenu.innerLinkReplaceEach(menu.getPath()); + String innerLinkName = StringUtils.capitalize(routerPath) + menu.getMenuId(); + children.setPath(routerPath); + children.setComponent(SystemConstants.INNER_LINK); + children.setName(innerLinkName); + children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath())); + childrenList.add(children); + router.setChildren(childrenList); + } + routers.add(router); + } + return routers; + } + + /** + * 构建前端所需要下拉树结构 + * + * @param menus 菜单列表 + * @return 下拉树结构列表 + */ + @Override + public List> buildMenuTreeSelect(List menus) { + if (CollUtil.isEmpty(menus)) { + return CollUtil.newArrayList(); + } + return TreeBuildUtils.build(menus, (menu, tree) -> { + Tree menuTree = tree.setId(menu.getMenuId()) + .setParentId(menu.getParentId()) + .setName(menu.getMenuName()) + .setWeight(menu.getOrderNum()); + menuTree.put("menuType", menu.getMenuType()); + menuTree.put("icon", menu.getIcon()); + }); + } + + /** + * 根据菜单ID查询信息 + * + * @param menuId 菜单ID + * @return 菜单信息 + */ + @Override + public SysMenuVo selectMenuById(Long menuId) { + return baseMapper.selectVoById(menuId); + } + + /** + * 是否存在菜单子节点 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean hasChildByMenuId(Long menuId) { + return baseMapper.exists(new LambdaQueryWrapper().eq(SysMenu::getParentId, menuId)); + } + + /** + * 查询菜单使用数量 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public boolean checkMenuExistRole(Long menuId) { + return roleMenuMapper.exists(new LambdaQueryWrapper().eq(SysRoleMenu::getMenuId, menuId)); + } + + /** + * 新增保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + @Override + public int insertMenu(SysMenuBo bo) { + SysMenu menu = MapstructUtils.convert(bo, SysMenu.class); + return baseMapper.insert(menu); + } + + /** + * 修改保存菜单信息 + * + * @param bo 菜单信息 + * @return 结果 + */ + @Override + public int updateMenu(SysMenuBo bo) { + SysMenu menu = MapstructUtils.convert(bo, SysMenu.class); + return baseMapper.updateById(menu); + } + + /** + * 删除菜单管理信息 + * + * @param menuId 菜单ID + * @return 结果 + */ + @Override + public int deleteMenuById(Long menuId) { + return baseMapper.deleteById(menuId); + } + + /** + * 校验菜单名称是否唯一 + * + * @param menu 菜单信息 + * @return 结果 + */ + @Override + public boolean checkMenuNameUnique(SysMenuBo menu) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysMenu::getMenuName, menu.getMenuName()) + .eq(SysMenu::getParentId, menu.getParentId()) + .ne(ObjectUtil.isNotNull(menu.getMenuId()), SysMenu::getMenuId, menu.getMenuId())); + return !exist; + } + + /** + * 根据父节点的ID获取所有子节点 + * + * @param list 分类表 + * @param parentId 传入的父节点ID + * @return String + */ + private List getChildPerms(List list, int parentId) { + List returnList = new ArrayList<>(); + for (SysMenu t : list) { + // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 + if (t.getParentId() == parentId) { + recursionFn(list, t); + returnList.add(t); + } + } + return returnList; + } + + /** + * 递归列表 + */ + private void recursionFn(List list, SysMenu t) { + // 得到子节点列表 + List childList = StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId())); + t.setChildren(childList); + for (SysMenu tChild : childList) { + // 判断是否有子节点 + if (list.stream().anyMatch(n -> n.getParentId().equals(tChild.getMenuId()))) { + recursionFn(list, tChild); + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java new file mode 100644 index 0000000..a67b04e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java @@ -0,0 +1,177 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +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 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.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.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.constant.OssConstant; +import org.dromara.common.redis.utils.CacheUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.system.domain.SysOssConfig; +import org.dromara.system.domain.bo.SysOssConfigBo; +import org.dromara.system.domain.vo.SysOssConfigVo; +import org.dromara.system.mapper.SysOssConfigMapper; +import org.dromara.system.service.ISysOssConfigService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; + +/** + * 对象存储配置Service业务层处理 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class SysOssConfigServiceImpl implements ISysOssConfigService { + + private final SysOssConfigMapper baseMapper; + + /** + * 项目启动时,初始化参数到缓存,加载配置类 + */ + @Override + public void init() { + List list = baseMapper.selectList(); + // 加载OSS初始化配置 + for (SysOssConfig config : list) { + String configKey = config.getConfigKey(); + if ("0".equals(config.getStatus())) { + RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey); + } + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); + } + } + + @Override + public SysOssConfigVo queryById(Long ossConfigId) { + return baseMapper.selectVoById(ossConfigId); + } + + @Override + public TableDataInfo queryPageList(SysOssConfigBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + + private LambdaQueryWrapper buildQueryWrapper(SysOssConfigBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getConfigKey()), SysOssConfig::getConfigKey, bo.getConfigKey()); + lqw.like(StringUtils.isNotBlank(bo.getBucketName()), SysOssConfig::getBucketName, bo.getBucketName()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysOssConfig::getStatus, bo.getStatus()); + lqw.orderByAsc(SysOssConfig::getOssConfigId); + return lqw; + } + + @Override + public Boolean insertByBo(SysOssConfigBo bo) { + SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class); + validEntityBeforeSave(config); + boolean flag = baseMapper.insert(config) > 0; + if (flag) { + // 从数据库查询完整的数据做缓存 + config = baseMapper.selectById(config.getOssConfigId()); + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); + } + return flag; + } + + @Override + public Boolean updateByBo(SysOssConfigBo bo) { + SysOssConfig config = MapstructUtils.convert(bo, SysOssConfig.class); + validEntityBeforeSave(config); + LambdaUpdateWrapper luw = new LambdaUpdateWrapper<>(); + luw.set(ObjectUtil.isNull(config.getPrefix()), SysOssConfig::getPrefix, ""); + luw.set(ObjectUtil.isNull(config.getRegion()), SysOssConfig::getRegion, ""); + luw.set(ObjectUtil.isNull(config.getExt1()), SysOssConfig::getExt1, ""); + luw.set(ObjectUtil.isNull(config.getRemark()), SysOssConfig::getRemark, ""); + luw.eq(SysOssConfig::getOssConfigId, config.getOssConfigId()); + boolean flag = baseMapper.update(config, luw) > 0; + if (flag) { + // 从数据库查询完整的数据做缓存 + config = baseMapper.selectById(config.getOssConfigId()); + CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config)); + } + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(SysOssConfig entity) { + if (StringUtils.isNotEmpty(entity.getConfigKey()) + && !checkConfigKeyUnique(entity)) { + throw new ServiceException("操作配置'" + entity.getConfigKey() + "'失败, 配置key已存在!"); + } + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + if (CollUtil.containsAny(ids, OssConstant.SYSTEM_DATA_IDS)) { + throw new ServiceException("系统内置, 不可删除!"); + } + } + List list = CollUtil.newArrayList(); + for (Long configId : ids) { + SysOssConfig config = baseMapper.selectById(configId); + list.add(config); + } + boolean flag = baseMapper.deleteByIds(ids) > 0; + if (flag) { + list.forEach(sysOssConfig -> + CacheUtils.evict(CacheNames.SYS_OSS_CONFIG, sysOssConfig.getConfigKey())); + } + return flag; + } + + /** + * 判断configKey是否唯一 + */ + private boolean checkConfigKeyUnique(SysOssConfig sysOssConfig) { + long ossConfigId = ObjectUtils.notNull(sysOssConfig.getOssConfigId(), -1L); + SysOssConfig info = baseMapper.selectOne(new LambdaQueryWrapper() + .select(SysOssConfig::getOssConfigId, SysOssConfig::getConfigKey) + .eq(SysOssConfig::getConfigKey, sysOssConfig.getConfigKey())); + if (ObjectUtil.isNotNull(info) && info.getOssConfigId() != ossConfigId) { + return false; + } + return true; + } + + /** + * 启用禁用状态 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public int updateOssConfigStatus(SysOssConfigBo bo) { + SysOssConfig sysOssConfig = MapstructUtils.convert(bo, SysOssConfig.class); + int row = baseMapper.update(null, new LambdaUpdateWrapper() + .set(SysOssConfig::getStatus, "1")); + row += baseMapper.updateById(sysOssConfig); + if (row > 0) { + RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, sysOssConfig.getConfigKey()); + } + return row; + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java new file mode 100644 index 0000000..c2eb08c --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java @@ -0,0 +1,269 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.convert.Convert; +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 jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.CacheNames; +import org.dromara.common.core.domain.dto.OssDTO; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.OssService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.common.oss.enumd.AccessPolicyType; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.system.domain.SysOss; +import org.dromara.system.domain.bo.SysOssBo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.mapper.SysOssMapper; +import org.dromara.system.service.ISysOssService; +import org.jetbrains.annotations.NotNull; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 文件上传 服务层实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysOssServiceImpl implements ISysOssService, OssService { + + private final SysOssMapper baseMapper; + + /** + * 查询OSS对象存储列表 + * + * @param bo OSS对象存储分页查询对象 + * @param pageQuery 分页查询实体类 + * @return 结果 + */ + @Override + public TableDataInfo queryPageList(SysOssBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + List filterResult = StreamUtils.toList(result.getRecords(), this::matchingUrl); + result.setRecords(filterResult); + return TableDataInfo.build(result); + } + + /** + * 根据一组 ossIds 获取对应的 SysOssVo 列表 + * + * @param ossIds 一组文件在数据库中的唯一标识集合 + * @return 包含 SysOssVo 对象的列表 + */ + @Override + public List listByIds(Collection ossIds) { + List list = new ArrayList<>(); + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); + for (Long id : ossIds) { + SysOssVo vo = ossService.getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + list.add(this.matchingUrl(vo)); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + list.add(vo); + } + } + } + return list; + } + + /** + * 根据一组 ossIds 获取对应文件的 URL 列表 + * + * @param ossIds 以逗号分隔的 ossId 字符串 + * @return 以逗号分隔的文件 URL 字符串 + */ + @Override + public String selectUrlByIds(String ossIds) { + List list = new ArrayList<>(); + SysOssServiceImpl ossService = SpringUtils.getAopProxy(this); + for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { + SysOssVo vo = ossService.getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + list.add(this.matchingUrl(vo).getUrl()); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + list.add(vo.getUrl()); + } + } + } + return String.join(StringUtils.SEPARATOR, list); + } + + @Override + public List selectByIds(String ossIds) { + List list = new ArrayList<>(); + for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { + SysOssVo vo = SpringUtils.getAopProxy(this).getById(id); + if (ObjectUtil.isNotNull(vo)) { + try { + vo.setUrl(this.matchingUrl(vo).getUrl()); + list.add(BeanUtil.toBean(vo, OssDTO.class)); + } catch (Exception ignored) { + // 如果oss异常无法连接则将数据直接返回 + list.add(BeanUtil.toBean(vo, OssDTO.class)); + } + } + } + return list; + } + + private LambdaQueryWrapper buildQueryWrapper(SysOssBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName()); + lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName()); + lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix()); + lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + lqw.eq(ObjectUtil.isNotNull(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy()); + lqw.eq(StringUtils.isNotBlank(bo.getService()), SysOss::getService, bo.getService()); + lqw.orderByAsc(SysOss::getOssId); + return lqw; + } + + /** + * 根据 ossId 从缓存或数据库中获取 SysOssVo 对象 + * + * @param ossId 文件在数据库中的唯一标识 + * @return SysOssVo 对象,包含文件信息 + */ + @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId") + @Override + public SysOssVo getById(Long ossId) { + return baseMapper.selectVoById(ossId); + } + + + /** + * 文件下载方法,支持一次性下载完整文件 + * + * @param ossId OSS对象ID + * @param response HttpServletResponse对象,用于设置响应头和向客户端发送文件内容 + */ + @Override + public void download(Long ossId, HttpServletResponse response) throws IOException { + SysOssVo sysOss = SpringUtils.getAopProxy(this).getById(ossId); + if (ObjectUtil.isNull(sysOss)) { + throw new ServiceException("文件数据不存在!"); + } + FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName()); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8"); + OssClient storage = OssFactory.instance(sysOss.getService()); + storage.download(sysOss.getFileName(), response.getOutputStream(), response::setContentLengthLong); + } + + /** + * 上传 MultipartFile 到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的 MultipartFile 对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + * @throws ServiceException 如果上传过程中发生异常,则抛出 ServiceException 异常 + */ + @Override + public SysOssVo upload(MultipartFile file) { + String originalfileName = file.getOriginalFilename(); + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + OssClient storage = OssFactory.instance(); + UploadResult uploadResult; + try { + uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType()); + } catch (IOException e) { + throw new ServiceException(e.getMessage()); + } + // 保存文件信息 + return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult); + } + + /** + * 上传文件到对象存储服务,并保存文件信息到数据库 + * + * @param file 要上传的文件对象 + * @return 上传成功后的 SysOssVo 对象,包含文件信息 + */ + @Override + public SysOssVo upload(File file) { + String originalfileName = file.getName(); + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + OssClient storage = OssFactory.instance(); + UploadResult uploadResult = storage.uploadSuffix(file, suffix); + // 保存文件信息 + return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult); + } + + @NotNull + private SysOssVo buildResultEntity(String originalfileName, String suffix, String configKey, UploadResult uploadResult) { + SysOss oss = new SysOss(); + oss.setUrl(uploadResult.getUrl()); + oss.setFileSuffix(suffix); + oss.setFileName(uploadResult.getFilename()); + oss.setOriginalName(originalfileName); + oss.setService(configKey); + baseMapper.insert(oss); + SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class); + return this.matchingUrl(sysOssVo); + } + + /** + * 删除OSS对象存储 + * + * @param ids OSS对象ID串 + * @param isValid 判断是否需要校验 + * @return 结果 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + } + List list = baseMapper.selectByIds(ids); + for (SysOss sysOss : list) { + OssClient storage = OssFactory.instance(sysOss.getService()); + storage.delete(sysOss.getUrl()); + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 桶类型为 private 的URL 修改为临时URL时长为120s + * + * @param oss OSS对象 + * @return oss 匹配Url的OSS对象 + */ + private SysOssVo matchingUrl(SysOssVo oss) { + OssClient storage = OssFactory.instance(oss.getService()); + // 仅修改桶类型为 private 的URL,临时URL时长为120s + if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) { + oss.setUrl(storage.getPrivateUrl(oss.getFileName(), Duration.ofSeconds(120))); + } + return oss; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java new file mode 100644 index 0000000..5888985 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java @@ -0,0 +1,249 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.PostService; +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.system.domain.SysDept; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.SysUserPost; +import org.dromara.system.domain.bo.SysPostBo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysPostMapper; +import org.dromara.system.mapper.SysUserPostMapper; +import org.dromara.system.service.ISysPostService; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.List; + +/** + * 岗位信息 服务层处理 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysPostServiceImpl implements ISysPostService, PostService { + + private final SysPostMapper baseMapper; + private final SysDeptMapper deptMapper; + private final SysUserPostMapper userPostMapper; + + @Override + public TableDataInfo selectPagePostList(SysPostBo post, PageQuery pageQuery) { + Page page = baseMapper.selectPagePostList(pageQuery.build(), buildQueryWrapper(post)); + return TableDataInfo.build(page); + } + + /** + * 查询岗位信息集合 + * + * @param post 岗位信息 + * @return 岗位信息集合 + */ + @Override + public List selectPostList(SysPostBo post) { + return baseMapper.selectVoList(buildQueryWrapper(post)); + } + + /** + * 查询用户所属岗位组 + * + * @param userId 用户ID + * @return 岗位ID + */ + @Override + public List selectPostsByUserId(Long userId) { + return baseMapper.selectPostsByUserId(userId); + } + + /** + * 根据查询条件构建查询包装器 + * + * @param bo 查询条件对象 + * @return 构建好的查询包装器 + */ + private LambdaQueryWrapper buildQueryWrapper(SysPostBo bo) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.like(StringUtils.isNotBlank(bo.getPostCode()), SysPost::getPostCode, bo.getPostCode()) + .like(StringUtils.isNotBlank(bo.getPostCategory()), SysPost::getPostCategory, bo.getPostCategory()) + .like(StringUtils.isNotBlank(bo.getPostName()), SysPost::getPostName, bo.getPostName()) + .eq(StringUtils.isNotBlank(bo.getStatus()), SysPost::getStatus, bo.getStatus()) + .orderByAsc(SysPost::getPostSort); + if (ObjectUtil.isNotNull(bo.getDeptId())) { + //优先单部门搜索 + wrapper.eq(SysPost::getDeptId, bo.getDeptId()); + } else if (ObjectUtil.isNotNull(bo.getBelongDeptId())) { + //部门树搜索 + wrapper.and(x -> { + List deptList = deptMapper.selectListByParentId(bo.getBelongDeptId()); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(bo.getBelongDeptId()); + x.in(SysPost::getDeptId, deptIds); + }); + } + return wrapper; + } + + /** + * 查询所有岗位 + * + * @return 岗位列表 + */ + @Override + public List selectPostAll() { + return baseMapper.selectVoList(new QueryWrapper<>()); + } + + /** + * 通过岗位ID查询岗位信息 + * + * @param postId 岗位ID + * @return 角色对象信息 + */ + @Override + public SysPostVo selectPostById(Long postId) { + return baseMapper.selectVoById(postId); + } + + /** + * 根据用户ID获取岗位选择框列表 + * + * @param userId 用户ID + * @return 选中岗位ID列表 + */ + @Override + public List selectPostListByUserId(Long userId) { + List list = baseMapper.selectPostsByUserId(userId); + return StreamUtils.toList(list, SysPostVo::getPostId); + } + + /** + * 通过岗位ID串查询岗位 + * + * @param postIds 岗位id串 + * @return 岗位列表信息 + */ + @Override + public List selectPostByIds(List postIds) { + return baseMapper.selectVoList(new LambdaQueryWrapper() + .select(SysPost::getPostId, SysPost::getPostName, SysPost::getPostCode) + .eq(SysPost::getStatus, SystemConstants.NORMAL) + .in(CollUtil.isNotEmpty(postIds), SysPost::getPostId, postIds)); + } + + /** + * 校验岗位名称是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostNameUnique(SysPostBo post) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysPost::getPostName, post.getPostName()) + .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId())); + return !exist; + } + + /** + * 校验岗位编码是否唯一 + * + * @param post 岗位信息 + * @return 结果 + */ + @Override + public boolean checkPostCodeUnique(SysPostBo post) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysPost::getPostCode, post.getPostCode()) + .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId())); + return !exist; + } + + /** + * 通过岗位ID查询岗位使用数量 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public long countUserPostById(Long postId) { + return userPostMapper.selectCount(new LambdaQueryWrapper().eq(SysUserPost::getPostId, postId)); + } + + /** + * 通过部门ID查询岗位使用数量 + * + * @param deptId 部门id + * @return 结果 + */ + @Override + public long countPostByDeptId(Long deptId) { + return baseMapper.selectCount(new LambdaQueryWrapper().eq(SysPost::getDeptId, deptId)); + } + + /** + * 删除岗位信息 + * + * @param postId 岗位ID + * @return 结果 + */ + @Override + public int deletePostById(Long postId) { + return baseMapper.deleteById(postId); + } + + /** + * 批量删除岗位信息 + * + * @param postIds 需要删除的岗位ID + * @return 结果 + */ + @Override + public int deletePostByIds(Long[] postIds) { + for (Long postId : postIds) { + SysPost post = baseMapper.selectById(postId); + if (countUserPostById(postId) > 0) { + throw new ServiceException(String.format("%1$s已分配,不能删除!", post.getPostName())); + } + } + return baseMapper.deleteByIds(Arrays.asList(postIds)); + } + + /** + * 新增保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + @Override + public int insertPost(SysPostBo bo) { + SysPost post = MapstructUtils.convert(bo, SysPost.class); + return baseMapper.insert(post); + } + + /** + * 修改保存岗位信息 + * + * @param bo 岗位信息 + * @return 结果 + */ + @Override + public int updatePost(SysPostBo bo) { + SysPost post = MapstructUtils.convert(bo, SysPost.class); + return baseMapper.updateById(post); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java new file mode 100644 index 0000000..8a0d45e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java @@ -0,0 +1,47 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ArrayUtil; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sensitive.core.SensitiveService; +import org.dromara.common.tenant.helper.TenantHelper; +import org.springframework.stereotype.Service; + +/** + * 脱敏服务 + * 默认管理员不过滤 + * 需自行根据业务重写实现 + * + * @author Lion Li + * @version 3.6.0 + */ +@Service +public class SysSensitiveServiceImpl implements SensitiveService { + + /** + * 是否脱敏 + */ + @Override + public boolean isSensitive(String[] roleKey, String[] perms) { + if (!LoginHelper.isLogin()) { + return true; + } + boolean roleExist = ArrayUtil.isNotEmpty(roleKey); + boolean permsExist = ArrayUtil.isNotEmpty(perms); + if (roleExist && permsExist) { + if (StpUtil.hasRoleOr(roleKey) && StpUtil.hasPermissionOr(perms)) { + return false; + } + } else if (roleExist && StpUtil.hasRoleOr(roleKey)) { + return false; + } else if (permsExist && StpUtil.hasPermissionOr(perms)) { + return false; + } + + if (TenantHelper.isEnable()) { + return !LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin(); + } + return !LoginHelper.isSuperAdmin(); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java new file mode 100644 index 0000000..23dd052 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java @@ -0,0 +1,168 @@ +package org.dromara.system.service.impl; + +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 lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.dto.TaskAssigneeDTO; +import org.dromara.common.core.domain.model.TaskAssigneeBody; +import org.dromara.common.core.service.TaskAssigneeService; +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.system.domain.SysDept; +import org.dromara.system.domain.SysPost; +import org.dromara.system.domain.SysRole; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysDeptVo; +import org.dromara.system.domain.vo.SysPostVo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysDeptMapper; +import org.dromara.system.mapper.SysPostMapper; +import org.dromara.system.mapper.SysRoleMapper; +import org.dromara.system.mapper.SysUserMapper; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 工作流设计器获取任务执行人 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysTaskAssigneeServiceImpl implements TaskAssigneeService { + + private final SysPostMapper postMapper; + private final SysDeptMapper deptMapper; + private final SysUserMapper userMapper; + private final SysRoleMapper roleMapper; + + /** + * 查询角色并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectRolesByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("r.del_flag", SystemConstants.NORMAL) + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "r.role_name", taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "r.role_key", taskQuery.getHandlerName()) + .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()), + "r.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime()) + .orderByAsc("r.role_sort").orderByAsc("r.create_time"); + Page page = roleMapper.selectPageRoleList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysRoleVo::getRoleId, SysRoleVo::getRoleKey, SysRoleVo::getRoleName, null, SysRoleVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 查询岗位并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectPostsByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysPost::getPostCategory, taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysPost::getPostName, taskQuery.getHandlerName()) + .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()), + SysPost::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime()); + if (StringUtils.isNotBlank(taskQuery.getGroupId())) { + Long belongDeptId = Long.valueOf(taskQuery.getGroupId()); + wrapper.and(x -> { + List deptList = deptMapper.selectListByParentId(belongDeptId); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(belongDeptId); + x.in(SysPost::getDeptId, deptIds); + }); + } + Page page = postMapper.selectPagePostList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysPostVo::getPostId, SysPostVo::getPostCategory, SysPostVo::getPostName, SysPostVo::getDeptId, SysPostVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + /** + * 查询部门并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectDeptsByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery() + .eq(SysDept::getDelFlag, SystemConstants.NORMAL) + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), SysDept::getDeptCategory, taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), SysDept::getDeptName, taskQuery.getHandlerName()) + .between(StringUtils.isNotBlank(taskQuery.getBeginTime()) && StringUtils.isNotBlank(taskQuery.getEndTime()), + SysDept::getCreateTime, taskQuery.getBeginTime(), taskQuery.getEndTime()) + .orderByAsc(SysDept::getAncestors) + .orderByAsc(SysDept::getParentId) + .orderByAsc(SysDept::getOrderNum) + .orderByAsc(SysDept::getDeptId); + if (StringUtils.isNotBlank(taskQuery.getGroupId())) { + //部门树搜索 + wrapper.and(x -> { + Long parentId = Long.valueOf(taskQuery.getGroupId()); + List deptList = deptMapper.selectListByParentId(parentId); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(parentId); + x.in(SysDept::getDeptId, deptIds); + }); + } + Page page = deptMapper.selectPageDeptList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysDeptVo::getDeptId, SysDeptVo::getDeptCategory, SysDeptVo::getDeptName, SysDeptVo::getParentId, SysDeptVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + + + /** + * 查询用户并返回任务指派的列表,支持分页 + * + * @param taskQuery 查询条件 + * @return 办理人 + */ + @Override + public TaskAssigneeDTO selectUsersByTaskAssigneeList(TaskAssigneeBody taskQuery) { + PageQuery pageQuery = new PageQuery(taskQuery.getPageSize(), taskQuery.getPageNum()); + QueryWrapper wrapper = Wrappers.query(); + wrapper.eq("u.del_flag", SystemConstants.NORMAL) + .like(StringUtils.isNotBlank(taskQuery.getHandlerCode()), "u.user_name", taskQuery.getHandlerCode()) + .like(StringUtils.isNotBlank(taskQuery.getHandlerName()), "u.nick_name", taskQuery.getHandlerName()) + .between(taskQuery.getBeginTime() != null && taskQuery.getEndTime() != null, + "u.create_time", taskQuery.getBeginTime(), taskQuery.getEndTime()) + .orderByAsc("u.user_id"); + if (StringUtils.isNotBlank(taskQuery.getGroupId())) { + //部门树搜索 + wrapper.and(x -> { + Long parentId = Long.valueOf(taskQuery.getGroupId()); + List deptList = deptMapper.selectListByParentId(parentId); + List deptIds = StreamUtils.toList(deptList, SysDept::getDeptId); + deptIds.add(parentId); + x.in("u.dept_id", deptIds); + }); + } + Page page = userMapper.selectPageUserList(pageQuery.build(), wrapper); + // 使用封装的字段映射方法进行转换 + List handlers = TaskAssigneeDTO.convertToHandlerList(page.getRecords(), + SysUserVo::getUserId, SysUserVo::getUserName, SysUserVo::getNickName, SysUserVo::getDeptId, SysUserVo::getCreateTime); + return new TaskAssigneeDTO(page.getTotal(), handlers); + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java new file mode 100644 index 0000000..8d69e96 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java @@ -0,0 +1,157 @@ +package org.dromara.system.service.impl; + +import cn.hutool.core.collection.CollUtil; +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 org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.exception.ServiceException; +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.system.domain.SysTenant; +import org.dromara.system.domain.SysTenantPackage; +import org.dromara.system.domain.bo.SysTenantPackageBo; +import org.dromara.system.domain.vo.SysTenantPackageVo; +import org.dromara.system.mapper.SysTenantMapper; +import org.dromara.system.mapper.SysTenantPackageMapper; +import org.dromara.system.service.ISysTenantPackageService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * 租户套餐Service业务层处理 + * + * @author Michelle.Chung + */ +@RequiredArgsConstructor +@Service +public class SysTenantPackageServiceImpl implements ISysTenantPackageService { + + private final SysTenantPackageMapper baseMapper; + private final SysTenantMapper tenantMapper; + + /** + * 查询租户套餐 + */ + @Override + public SysTenantPackageVo queryById(Long packageId){ + return baseMapper.selectVoById(packageId); + } + + /** + * 查询租户套餐列表 + */ + @Override + public TableDataInfo queryPageList(SysTenantPackageBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @Override + public List selectList() { + return baseMapper.selectVoList(new LambdaQueryWrapper() + .eq(SysTenantPackage::getStatus, SystemConstants.NORMAL)); + } + + /** + * 查询租户套餐列表 + */ + @Override + public List queryList(SysTenantPackageBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysTenantPackageBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getPackageName()), SysTenantPackage::getPackageName, bo.getPackageName()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenantPackage::getStatus, bo.getStatus()); + lqw.orderByAsc(SysTenantPackage::getPackageId); + return lqw; + } + + /** + * 新增租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(SysTenantPackageBo bo) { + SysTenantPackage add = MapstructUtils.convert(bo, SysTenantPackage.class); + // 保存菜单id + List menuIds = Arrays.asList(bo.getMenuIds()); + if (CollUtil.isNotEmpty(menuIds)) { + add.setMenuIds(StringUtils.join(menuIds, ", ")); + } else { + add.setMenuIds(""); + } + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setPackageId(add.getPackageId()); + } + return flag; + } + + /** + * 修改租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(SysTenantPackageBo bo) { + SysTenantPackage update = MapstructUtils.convert(bo, SysTenantPackage.class); + // 保存菜单id + List menuIds = Arrays.asList(bo.getMenuIds()); + if (CollUtil.isNotEmpty(menuIds)) { + update.setMenuIds(StringUtils.join(menuIds, ", ")); + } else { + update.setMenuIds(""); + } + return baseMapper.updateById(update) > 0; + } + + /** + * 校验套餐名称是否唯一 + */ + @Override + public boolean checkPackageNameUnique(SysTenantPackageBo bo) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysTenantPackage::getPackageName, bo.getPackageName()) + .ne(ObjectUtil.isNotNull(bo.getPackageId()), SysTenantPackage::getPackageId, bo.getPackageId())); + return !exist; + } + + /** + * 修改套餐状态 + * + * @param bo 套餐信息 + * @return 结果 + */ + @Override + public int updatePackageStatus(SysTenantPackageBo bo) { + SysTenantPackage tenantPackage = MapstructUtils.convert(bo, SysTenantPackage.class); + return baseMapper.updateById(tenantPackage); + } + + /** + * 批量删除租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + boolean exists = tenantMapper.exists(new LambdaQueryWrapper().in(SysTenant::getPackageId, ids)); + if (exists) { + throw new ServiceException("租户套餐已被使用"); + } + } + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java new file mode 100644 index 0000000..f31bd30 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java @@ -0,0 +1,477 @@ +package org.dromara.system.service.impl; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.RandomUtil; +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.constant.CacheNames; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +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.redis.utils.CacheUtils; +import org.dromara.common.tenant.core.TenantEntity; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.*; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.mapper.*; +import org.dromara.system.service.ISysTenantService; +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.*; + +/** + * 租户Service业务层处理 + * + * @author Michelle.Chung + */ +@RequiredArgsConstructor +@Service +public class SysTenantServiceImpl implements ISysTenantService { + + private final SysTenantMapper baseMapper; + private final SysTenantPackageMapper tenantPackageMapper; + private final SysUserMapper userMapper; + private final SysDeptMapper deptMapper; + private final SysRoleMapper roleMapper; + private final SysRoleMenuMapper roleMenuMapper; + private final SysRoleDeptMapper roleDeptMapper; + private final SysUserRoleMapper userRoleMapper; + private final SysDictTypeMapper dictTypeMapper; + private final SysDictDataMapper dictDataMapper; + private final SysConfigMapper configMapper; + + /** + * 查询租户 + */ + @Override + public SysTenantVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 基于租户ID查询租户 + */ + @Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId") + @Override + public SysTenantVo queryByTenantId(String tenantId) { + return baseMapper.selectVoOne(new LambdaQueryWrapper().eq(SysTenant::getTenantId, tenantId)); + } + + /** + * 查询租户列表 + */ + @Override + public TableDataInfo queryPageList(SysTenantBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询租户列表 + */ + @Override + public List queryList(SysTenantBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SysTenantBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()); + lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName()); + lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone()); + lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName()); + lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber()); + lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress()); + lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro()); + lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain()); + lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId()); + lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime()); + lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus()); + lqw.orderByAsc(SysTenant::getId); + return lqw; + } + + /** + * 新增租户 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean insertByBo(SysTenantBo bo) { + SysTenant add = MapstructUtils.convert(bo, SysTenant.class); + + // 获取所有租户编号 + List tenantIds = baseMapper.selectObjs( + new LambdaQueryWrapper().select(SysTenant::getTenantId), x -> { + return Convert.toStr(x); + }); + String tenantId = generateTenantId(tenantIds); + add.setTenantId(tenantId); + boolean flag = baseMapper.insert(add) > 0; + if (!flag) { + throw new ServiceException("创建租户失败"); + } + bo.setId(add.getId()); + + // 根据套餐创建角色 + Long roleId = createTenantRole(tenantId, bo.getPackageId()); + + // 创建部门: 公司名是部门名称 + SysDept dept = new SysDept(); + dept.setTenantId(tenantId); + dept.setDeptName(bo.getCompanyName()); + dept.setParentId(Constants.TOP_PARENT_ID); + dept.setAncestors(Constants.TOP_PARENT_ID.toString()); + deptMapper.insert(dept); + Long deptId = dept.getDeptId(); + + // 角色和部门关联表 + SysRoleDept roleDept = new SysRoleDept(); + roleDept.setRoleId(roleId); + roleDept.setDeptId(deptId); + roleDeptMapper.insert(roleDept); + + // 创建系统用户 + SysUser user = new SysUser(); + user.setTenantId(tenantId); + user.setUserName(bo.getUsername()); + user.setNickName(bo.getUsername()); + user.setPassword(BCrypt.hashpw(bo.getPassword())); + user.setDeptId(deptId); + userMapper.insert(user); + //新增系统用户后,默认当前用户为部门的负责人 + SysDept sd = new SysDept(); + sd.setLeader(user.getUserId()); + sd.setDeptId(deptId); + deptMapper.updateById(sd); + + // 用户和角色关联表 + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(user.getUserId()); + userRole.setRoleId(roleId); + userRoleMapper.insert(userRole); + + String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID; + List dictTypeList = dictTypeMapper.selectList( + new LambdaQueryWrapper().eq(SysDictType::getTenantId, defaultTenantId)); + List dictDataList = dictDataMapper.selectList( + new LambdaQueryWrapper().eq(SysDictData::getTenantId, defaultTenantId)); + for (SysDictType dictType : dictTypeList) { + dictType.setDictId(null); + dictType.setTenantId(tenantId); + } + for (SysDictData dictData : dictDataList) { + dictData.setDictCode(null); + dictData.setTenantId(tenantId); + } + dictTypeMapper.insertBatch(dictTypeList); + dictDataMapper.insertBatch(dictDataList); + + List sysConfigList = configMapper.selectList( + new LambdaQueryWrapper().eq(SysConfig::getTenantId, defaultTenantId)); + for (SysConfig config : sysConfigList) { + config.setConfigId(null); + config.setTenantId(tenantId); + } + configMapper.insertBatch(sysConfigList); + + // 未开启工作流不执行下方操作 + if (SpringUtils.getProperty("warm-flow.enabled", Boolean.class, false)) { + WorkflowService workflowService = SpringUtils.getBean(WorkflowService.class); + // 新增租户流程定义 + workflowService.syncDef(tenantId); + } + return true; + } + + /** + * 生成租户id + * + * @param tenantIds 已有租户id列表 + * @return 租户id + */ + private String generateTenantId(List tenantIds) { + // 随机生成6位 + String numbers = RandomUtil.randomNumbers(6); + // 判断是否存在,如果存在则重新生成 + if (tenantIds.contains(numbers)) { + return generateTenantId(tenantIds); + } + return numbers; + } + + /** + * 根据租户菜单创建租户角色 + * + * @param tenantId 租户编号 + * @param packageId 租户套餐id + * @return 角色id + */ + private Long createTenantRole(String tenantId, Long packageId) { + // 获取租户套餐 + SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); + if (ObjectUtil.isNull(tenantPackage)) { + throw new ServiceException("套餐不存在"); + } + // 获取套餐菜单id + List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); + + // 创建角色 + SysRole role = new SysRole(); + role.setTenantId(tenantId); + role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME); + role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY); + role.setRoleSort(1); + role.setStatus(SystemConstants.NORMAL); + roleMapper.insert(role); + Long roleId = role.getRoleId(); + + // 创建角色菜单 + List roleMenus = new ArrayList<>(menuIds.size()); + menuIds.forEach(menuId -> { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(roleId); + roleMenu.setMenuId(menuId); + roleMenus.add(roleMenu); + }); + roleMenuMapper.insertBatch(roleMenus); + + return roleId; + } + + /** + * 修改租户 + */ + @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") + @Override + public Boolean updateByBo(SysTenantBo bo) { + SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class); + tenant.setTenantId(null); + tenant.setPackageId(null); + return baseMapper.updateById(tenant) > 0; + } + + /** + * 修改租户状态 + * + * @param bo 租户信息 + * @return 结果 + */ + @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") + @Override + public int updateTenantStatus(SysTenantBo bo) { + SysTenant tenant = new SysTenant(); + tenant.setId(bo.getId()); + tenant.setStatus(bo.getStatus()); + return baseMapper.updateById(tenant); + } + + /** + * 校验租户是否允许操作 + * + * @param tenantId 租户ID + */ + @Override + public void checkTenantAllowed(String tenantId) { + if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + throw new ServiceException("不允许操作管理租户"); + } + } + + /** + * 批量删除租户 + */ + @CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true) + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 做一些业务上的校验,判断是否需要校验 + if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) { + throw new ServiceException("超管租户不能删除"); + } + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 校验企业名称是否唯一 + */ + @Override + public boolean checkCompanyNameUnique(SysTenantBo bo) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(SysTenant::getCompanyName, bo.getCompanyName()) + .ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId())); + return !exist; + } + + /** + * 校验账号余额 + */ + @Override + public boolean checkAccountBalance(String tenantId) { + SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId); + // 如果余额为-1代表不限制 + if (tenant.getAccountCount() == -1) { + return true; + } + Long userNumber = userMapper.selectCount(new LambdaQueryWrapper<>()); + // 如果余额大于0代表还有可用名额 + return tenant.getAccountCount() - userNumber > 0; + } + + /** + * 校验有效期 + */ + @Override + public boolean checkExpireTime(String tenantId) { + SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId); + // 如果未设置过期时间代表不限制 + if (ObjectUtil.isNull(tenant.getExpireTime())) { + return true; + } + // 如果当前时间在过期时间之前则通过 + return new Date().before(tenant.getExpireTime()); + } + + /** + * 同步租户套餐 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean syncTenantPackage(String tenantId, Long packageId) { + SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId); + List roles = roleMapper.selectList( + new LambdaQueryWrapper().eq(SysRole::getTenantId, tenantId)); + List roleIds = new ArrayList<>(roles.size() - 1); + List menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong); + roles.forEach(item -> { + if (TenantConstants.TENANT_ADMIN_ROLE_KEY.equals(item.getRoleKey())) { + List roleMenus = new ArrayList<>(menuIds.size()); + menuIds.forEach(menuId -> { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(item.getRoleId()); + roleMenu.setMenuId(menuId); + roleMenus.add(roleMenu); + }); + roleMenuMapper.delete(new LambdaQueryWrapper().eq(SysRoleMenu::getRoleId, item.getRoleId())); + roleMenuMapper.insertBatch(roleMenus); + } else { + roleIds.add(item.getRoleId()); + } + }); + if (!roleIds.isEmpty()) { + roleMenuMapper.delete( + new LambdaQueryWrapper().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds)); + } + return true; + } + + /** + * 同步租户字典 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void syncTenantDict() { + // 查询超管 所有字典数据 + List dictTypeList = new ArrayList<>(); + List dictDataList = new ArrayList<>(); + TenantHelper.ignore(() -> { + dictTypeList.addAll(dictTypeMapper.selectList()); + dictDataList.addAll(dictDataMapper.selectList()); + }); + Map> typeMap = StreamUtils.groupByKey(dictTypeList, TenantEntity::getTenantId); + Map>> typeDataMap = StreamUtils.groupBy2Key( + dictDataList, TenantEntity::getTenantId, SysDictData::getDictType); + // 管理租户字典数据 + List defaultTypeMap = typeMap.get(TenantConstants.DEFAULT_TENANT_ID); + Map> defaultTypeDataMap = typeDataMap.get(TenantConstants.DEFAULT_TENANT_ID); + + // 获取所有租户编号 + List tenantIds = baseMapper.selectObjs( + new LambdaQueryWrapper().select(SysTenant::getTenantId) + .eq(SysTenant::getStatus, SystemConstants.NORMAL), x -> { + return Convert.toStr(x); + }); + List saveTypeList = new ArrayList<>(); + List saveDataList = new ArrayList<>(); + Set set = new HashSet<>(); + for (String tenantId : tenantIds) { + if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + continue; + } + for (SysDictType dictType : defaultTypeMap) { + List typeList = StreamUtils.toList(typeMap.get(tenantId), SysDictType::getDictType); + List dataList = defaultTypeDataMap.get(dictType.getDictType()); + if (typeList.contains(dictType.getDictType())) { + List dataListTenant = typeDataMap.get(tenantId).get(dictType.getDictType()); + Map map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue); + for (SysDictData dictData : dataList) { + if (!map.containsKey(dictData.getDictValue())) { + SysDictData data = BeanUtil.toBean(dictData, SysDictData.class); + // 设置字典编码为 null + data.setDictCode(null); + data.setTenantId(tenantId); + data.setCreateTime(null); + data.setUpdateTime(null); + set.add(tenantId); + saveDataList.add(data); + } + } + } else { + SysDictType type = BeanUtil.toBean(dictType, SysDictType.class); + type.setDictId(null); + type.setTenantId(tenantId); + type.setCreateTime(null); + type.setUpdateTime(null); + set.add(tenantId); + saveTypeList.add(type); + if (CollUtil.isNotEmpty(dataList)) { + // 筛选出 dictType 对应的 data + for (SysDictData dictData : dataList) { + SysDictData data = BeanUtil.toBean(dictData, SysDictData.class); + // 设置字典编码为 null + data.setDictCode(null); + data.setTenantId(tenantId); + data.setCreateTime(null); + data.setUpdateTime(null); + set.add(tenantId); + saveDataList.add(data); + } + } + } + } + } + TenantHelper.ignore(() -> { + if (CollUtil.isNotEmpty(saveTypeList)) { + dictTypeMapper.insertBatch(saveTypeList); + } + if (CollUtil.isNotEmpty(saveDataList)) { + dictDataMapper.insertBatch(saveDataList); + } + }); + for (String tenantId : set) { + TenantHelper.dynamic(tenantId, () -> CacheUtils.clear(CacheNames.SYS_DICT)); + } + } + +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/UserTransferServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/UserTransferServiceImpl.java new file mode 100644 index 0000000..7c7cdbc --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/UserTransferServiceImpl.java @@ -0,0 +1,127 @@ +package org.dromara.system.service.impl; + +import org.dromara.system.domain.UserTransferDTO; +import org.dromara.system.service.IUserTransferService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.redis.utils.RedisUtils; + +import org.dromara.system.domain.SysUser; + +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.IUserTransferService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; + +import java.math.BigDecimal; + +@Slf4j +@Service +@RequiredArgsConstructor +public class UserTransferServiceImpl implements IUserTransferService { + + private final SysUserMapper baseMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean transferBalanceToFreeze(Long fromUserId, Long toUserId, Long amount) { + // 参数校验 + validateTransferParams(fromUserId, toUserId, amount); + + // 检查用户是否存在且状态正常 + SysUser fromUser = baseMapper.selectById(fromUserId); + SysUser toUser = baseMapper.selectById(toUserId); + + validateUserStatus(fromUser, toUser); + + // 检查余额是否足够 + if (fromUser.getBalance().compareTo(BigDecimal.valueOf(amount)) < 0) { + throw new ServiceException("余额不足"); + } + + // 执行转账 + int affectedRows = baseMapper.transferBalanceToFreeze(fromUserId, toUserId, amount); + + return processTransferResult("余额转冻结", fromUserId, toUserId, amount, affectedRows); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean transferFreezeToBalance(Long fromUserId, Long toUserId, Long amount) { + // 参数校验 + validateTransferParams(fromUserId, toUserId, amount); + + // 检查用户是否存在且状态正常 + SysUser fromUser = baseMapper.selectById(fromUserId); + SysUser toUser = baseMapper.selectById(toUserId); + + validateUserStatus(fromUser, toUser); + + // 检查冻结资金是否足够 + if (fromUser.getFreeze().compareTo(BigDecimal.valueOf(amount)) < 0) { + throw new ServiceException("冻结资金不足"); + } + + // 执行转账 + int affectedRows = baseMapper.transferFreezeToBalance(fromUserId, toUserId, amount); + + return processTransferResult("冻结转余额", fromUserId, toUserId, amount, affectedRows); + } + + /** + * 更新用户余额 + * @param userId 用户ID + * @param balance 新余额(分) + * @return 影响行数 + */ + @Override + public int updateBalance(Long userId, Long balance){ + return baseMapper.updateBalance(userId, balance); + } + + /** + * 校验转账参数 + */ + private void validateTransferParams(Long fromUserId, Long toUserId, Long amount) { + if (fromUserId == null || toUserId == null || amount == null) { + throw new ServiceException("参数不能为空"); + } + if (amount <= 0) { + throw new ServiceException("转账金额必须大于0"); + } + // if (fromUserId.equals(toUserId)) { + // throw new ServiceException("转出用户和转入用户不能相同"); + // } + } + + /** + * 校验用户状态 + */ + private void validateUserStatus(SysUser fromUser, SysUser toUser) { + if (fromUser == null || !"0".equals(fromUser.getDelFlag()) || !"0".equals(fromUser.getStatus())) { + throw new ServiceException("转出用户不存在或状态异常"); + } + if (toUser == null || !"0".equals(toUser.getDelFlag()) || !"0".equals(toUser.getStatus())) { + throw new ServiceException("转入用户不存在或状态异常"); + } + } + + /** + * 处理转账结果 + */ + private boolean processTransferResult(String operation, Long fromUserId, Long toUserId, Long amount, int affectedRows) { + if (affectedRows == 1 || affectedRows == 2) { + log.info("{}成功: fromUserId={}, toUserId={}, amount={}分", + operation, fromUserId, toUserId, amount); + return true; + } else { + log.error("{}失败: fromUserId={}, toUserId={}, amount={}分, affectedRows={}", + operation, fromUserId, toUserId, amount, affectedRows); + throw new ServiceException("转账失败,请稍后重试"); + } + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml new file mode 100644 index 0000000..fd150ad --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml new file mode 100644 index 0000000..9057a0e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml new file mode 100644 index 0000000..6bcce51 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml new file mode 100644 index 0000000..c64b551 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml new file mode 100644 index 0000000..5ef14ee --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml new file mode 100644 index 0000000..8c2c080 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml new file mode 100644 index 0000000..d9b25bd --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml new file mode 100644 index 0000000..322403f --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml new file mode 100644 index 0000000..1705bb2 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml new file mode 100644 index 0000000..b51f6e8 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml @@ -0,0 +1,62 @@ + + + + + + + + + select distinct r.role_id, + r.role_name, + r.role_key, + r.role_sort, + r.data_scope, + r.menu_check_strictly, + r.dept_check_strictly, + r.status, + r.del_flag, + r.create_time, + r.remark + from sys_role r + left join sys_user_role sur on sur.role_id = r.role_id + left join sys_user u on u.user_id = sur.user_id + left join sys_dept d on u.dept_id = d.dept_id + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml new file mode 100644 index 0000000..f01dc5e --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml new file mode 100644 index 0000000..baa4b59 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml new file mode 100644 index 0000000..f2a36a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -0,0 +1,286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE sys_user + SET + balance = CASE + + WHEN #{fromUserId} = #{toUserId} AND user_id = #{fromUserId} + THEN balance - #{amount} + + + WHEN user_id = #{fromUserId} + THEN balance - #{amount} + ELSE balance + END, + + freeze = CASE + + WHEN #{fromUserId} = #{toUserId} AND user_id = #{fromUserId} + THEN freeze + #{amount} + + + WHEN user_id = #{toUserId} + THEN freeze + #{amount} + ELSE freeze + END + WHERE + + del_flag = '0' + AND status = '0' + AND ( + + ( + #{fromUserId} = #{toUserId} + AND user_id = #{fromUserId} + AND balance >= #{amount} + ) + OR + + ( + #{fromUserId} != #{toUserId} + AND user_id IN (#{fromUserId}, #{toUserId}) + AND ( + (user_id = #{fromUserId} AND balance >= #{amount}) + OR user_id = #{toUserId} + ) + ) + ) + + + + + + UPDATE sys_user + SET + balance = CASE + + WHEN #{fromUserId} = #{toUserId} AND user_id = #{fromUserId} + THEN balance + #{amount} + + + WHEN user_id = #{fromUserId} + THEN balance + WHEN user_id = #{toUserId} + THEN balance + #{amount} + ELSE balance + END, + + freeze = CASE + + WHEN #{fromUserId} = #{toUserId} AND user_id = #{fromUserId} + THEN freeze - #{amount} + + + WHEN user_id = #{fromUserId} + THEN freeze - #{amount} + WHEN user_id = #{toUserId} + THEN freeze + ELSE freeze + END + WHERE + + del_flag = '0' + AND status = '0' + AND ( + + ( + #{fromUserId} = #{toUserId} + AND user_id = #{fromUserId} + AND freeze >= #{amount} + ) + OR + + ( + #{fromUserId} != #{toUserId} + AND user_id IN (#{fromUserId}, #{toUserId}) + AND ( + (user_id = #{fromUserId} AND freeze >= #{amount}) + OR user_id = #{toUserId} + ) + ) + ) + + + + UPDATE sys_user + SET balance = #{balance} + where user_id = #{userId} + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml new file mode 100644 index 0000000..bc52d1a --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/README.md b/ruoyi-modules/ruoyi-workflow/README.md new file mode 100644 index 0000000..59096b1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/README.md @@ -0,0 +1,3 @@ +# 工作流说明 + +工作流目前在未成熟阶段 后续仍会经历重构 甚至重写(生产使用前请慎重考虑后续是否要更新维护) \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-workflow/pom.xml b/ruoyi-modules/ruoyi-workflow/pom.xml new file mode 100644 index 0000000..d195faf --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/pom.xml @@ -0,0 +1,84 @@ + + + + org.dromara + ruoyi-modules + ${revision} + ../pom.xml + + 4.0.0 + jar + ruoyi-workflow + + + 工作流模块 + + + + + + org.dromara + ruoyi-common-sse + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-mail + + + + org.dromara + ruoyi-common-sms + + + + org.dromara + ruoyi-common-mybatis + + + org.dromara + ruoyi-common-web + + + org.dromara + ruoyi-common-log + + + org.dromara + ruoyi-common-idempotent + + + org.dromara + ruoyi-common-excel + + + org.dromara + ruoyi-common-translation + + + org.dromara + ruoyi-common-tenant + + + org.dromara + ruoyi-common-security + + + org.dromara.warm + warm-flow-mybatis-plus-sb3-starter + + + org.dromara.warm + warm-flow-plugin-ui-sb-web + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java new file mode 100644 index 0000000..5d24b35 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java @@ -0,0 +1,14 @@ +package org.dromara.workflow.common; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@ConditionalOnProperty(value = "warm-flow.enabled", havingValue = "true") +public @interface ConditionalOnEnable { +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java new file mode 100644 index 0000000..0fe5cfe --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java @@ -0,0 +1,53 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 消息类型枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum MessageTypeEnum { + + /** + * 站内信 + */ + SYSTEM_MESSAGE("1", "站内信"), + + /** + * 邮箱 + */ + EMAIL_MESSAGE("2", "邮箱"), + + /** + * 短信 + */ + SMS_MESSAGE("3", "短信"); + + private final String code; + + private final String desc; + + private static final Map MESSAGE_TYPE_ENUM_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(MessageTypeEnum::getCode, Function.identity())); + + /** + * 根据消息类型 code 获取 MessageTypeEnum + * + * @param code 消息类型code + * @return MessageTypeEnum + */ + public static MessageTypeEnum getByCode(String code) { + return MESSAGE_TYPE_ENUM_MAP.getOrDefault(code, null); + } + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java new file mode 100644 index 0000000..eed1b91 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java @@ -0,0 +1,49 @@ +package org.dromara.workflow.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 人员类型 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum TaskAssigneeType { + + /** + * 待办任务的审批人权限 + *

该权限表示用户是待办任务的审批人,负责审核任务的执行情况。

+ */ + APPROVER("1", "待办任务的审批人权限"), + + /** + * 待办任务的转办人权限 + *

该权限表示用户是待办任务的转办人,负责将任务分配给其他人员。

+ */ + TRANSFER("2", "待办任务的转办人权限"), + + /** + * 待办任务的委托人权限 + *

该权限表示用户是待办任务的委托人,能够委托其他人代为处理任务。

+ */ + DELEGATE("3", "待办任务的委托人权限"), + + /** + * 待办任务的抄送人权限 + *

该权限表示用户是待办任务的抄送人,仅接收任务信息的通知,不参与任务的审批或处理。

+ */ + COPY("4", "待办任务的抄送人权限"); + + /** + * 类型 + */ + private final String code; + + /** + * 描述 + */ + private final String description; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java new file mode 100644 index 0000000..d18ebb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java @@ -0,0 +1,104 @@ +package org.dromara.workflow.common.enums; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 任务状态枚举 + * + * @author may + */ +@Getter +@AllArgsConstructor +public enum TaskStatusEnum { + + /** + * 撤销 + */ + CANCEL("cancel", "撤销"), + + /** + * 通过 + */ + PASS("pass", "通过"), + + /** + * 待审核 + */ + WAITING("waiting", "待审核"), + + /** + * 作废 + */ + INVALID("invalid", "作废"), + + /** + * 退回 + */ + BACK("back", "退回"), + + /** + * 终止 + */ + TERMINATION("termination", "终止"), + + /** + * 转办 + */ + TRANSFER("transfer", "转办"), + + /** + * 委托 + */ + DEPUTE("depute", "委托"), + + /** + * 抄送 + */ + COPY("copy", "抄送"), + + /** + * 加签 + */ + SIGN("sign", "加签"), + + /** + * 减签 + */ + SIGN_OFF("sign_off", "减签"), + + /** + * 超时 + */ + TIMEOUT("timeout", "超时"); + + /** + * 状态 + */ + private final String status; + + /** + * 描述 + */ + private final String desc; + + private static final Map STATUS_DESC_MAP = Arrays.stream(values()) + .collect(Collectors.toConcurrentMap(TaskStatusEnum::getStatus, TaskStatusEnum::getDesc)); + + /** + * 任务业务状态 + * + * @param status 状态 + */ + public static String findByStatus(String status) { + // 从缓存中直接获取描述 + return STATUS_DESC_MAP.getOrDefault(status, StrUtil.EMPTY); + } + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java new file mode 100644 index 0000000..08f1808 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java @@ -0,0 +1,16 @@ +package org.dromara.workflow.config; + +import org.dromara.workflow.common.ConditionalOnEnable; +import org.springframework.context.annotation.Configuration; + +/** + * warmFlow配置 + * + * @author may + */ +@ConditionalOnEnable +@Configuration +public class WarmFlowConfig { + +} + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java new file mode 100644 index 0000000..37d414f --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java @@ -0,0 +1,132 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +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.web.core.BaseController; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 流程分类 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/category") +public class FlwCategoryController extends BaseController { + + private final IFlwCategoryService flwCategoryService; + + /** + * 查询流程分类列表 + */ + @SaCheckPermission("workflow:category:list") + @GetMapping("/list") + public R> list(FlowCategoryBo bo) { + List list = flwCategoryService.queryList(bo); + return R.ok(list); + } + + /** + * 导出流程分类列表 + */ + @SaCheckPermission("workflow:category:export") + @Log(title = "流程分类", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FlowCategoryBo bo, HttpServletResponse response) { + List list = flwCategoryService.queryList(bo); + ExcelUtil.exportExcel(list, "流程分类", FlowCategoryVo.class, response); + } + + /** + * 获取流程分类详细信息 + * + * @param categoryId 主键 + */ + @SaCheckPermission("workflow:category:query") + @GetMapping("/{categoryId}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long categoryId) { + flwCategoryService.checkCategoryDataScope(categoryId); + return R.ok(flwCategoryService.queryById(categoryId)); + } + + /** + * 新增流程分类 + */ + @SaCheckPermission("workflow:category:add") + @Log(title = "流程分类", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody FlowCategoryBo category) { + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("新增流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } + return toAjax(flwCategoryService.insertByBo(category)); + } + + /** + * 修改流程分类 + */ + @SaCheckPermission("workflow:category:edit") + @Log(title = "流程分类", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody FlowCategoryBo category) { + Long categoryId = category.getCategoryId(); + flwCategoryService.checkCategoryDataScope(categoryId); + if (!flwCategoryService.checkCategoryNameUnique(category)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,流程分类名称已存在"); + } else if (category.getParentId().equals(categoryId)) { + return R.fail("修改流程分类'" + category.getCategoryName() + "'失败,上级流程分类不能是自己"); + } + return toAjax(flwCategoryService.updateByBo(category)); + } + + /** + * 删除流程分类 + * + * @param categoryId 主键 + */ + @SaCheckPermission("workflow:category:remove") + @Log(title = "流程分类", businessType = BusinessType.DELETE) + @DeleteMapping("/{categoryId}") + public R remove(@PathVariable Long categoryId) { + if (flwCategoryService.hasChildByCategoryId(categoryId)) { + return R.warn("存在下级流程分类,不允许删除"); + } + if (flwCategoryService.checkCategoryExistDefinition(categoryId)) { + return R.warn("流程分类存在流程定义,不允许删除"); + } + return toAjax(flwCategoryService.deleteWithValidById(categoryId)); + } + + /** + * 获取流程分类树列表 + * + * @param categoryBo 流程分类 + */ + @GetMapping("/categoryTree") + public R>> categoryTree(FlowCategoryBo categoryBo) { + return R.ok(flwCategoryService.selectCategoryTreeList(categoryBo)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java new file mode 100644 index 0000000..10d9de8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java @@ -0,0 +1,194 @@ +package org.dromara.workflow.controller; + +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +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.warm.flow.core.entity.Definition; +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.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * 流程定义管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/definition") +public class FlwDefinitionController extends BaseController { + + private final DefService defService; + private final IFlwDefinitionService flwDefinitionService; + + /** + * 查询流程定义列表 + * + * @param flowDefinition 参数 + * @param pageQuery 分页 + */ + @GetMapping("/list") + public TableDataInfo list(FlowDefinition flowDefinition, PageQuery pageQuery) { + return flwDefinitionService.queryList(flowDefinition, pageQuery); + } + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinition 参数 + * @param pageQuery 分页 + */ + @GetMapping("/unPublishList") + public TableDataInfo unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) { + return flwDefinitionService.unPublishList(flowDefinition, pageQuery); + } + + /** + * 获取流程定义详细信息 + * + * @param id 流程定义id + */ + @GetMapping(value = "/{id}") + public R getInfo(@PathVariable Long id) { + return R.ok(defService.getById(id)); + } + + /** + * 新增流程定义 + * + * @param flowDefinition 参数 + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PostMapping + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R add(@RequestBody FlowDefinition flowDefinition) { + return R.ok(defService.checkAndSave(flowDefinition)); + } + + /** + * 修改流程定义 + * + * @param flowDefinition 参数 + */ + @Log(title = "流程定义", businessType = BusinessType.UPDATE) + @PutMapping + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R edit(@RequestBody FlowDefinition flowDefinition) { + return R.ok(defService.updateById(flowDefinition)); + } + + /** + * 发布流程定义 + * + * @param id 流程定义id + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PutMapping("/publish/{id}") + @RepeatSubmit() + public R publish(@PathVariable Long id) { + return R.ok(flwDefinitionService.publish(id)); + } + + /** + * 取消发布流程定义 + * + * @param id 流程定义id + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PutMapping("/unPublish/{id}") + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R unPublish(@PathVariable Long id) { + return R.ok(defService.unPublish(id)); + } + + /** + * 删除流程定义 + */ + @Log(title = "流程定义", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@PathVariable List ids) { + return toAjax(flwDefinitionService.removeDef(ids)); + } + + /** + * 复制流程定义 + * + * @param id 流程定义id + */ + @Log(title = "流程定义", businessType = BusinessType.INSERT) + @PostMapping("/copy/{id}") + @RepeatSubmit() + @Transactional(rollbackFor = Exception.class) + public R copy(@PathVariable Long id) { + return R.ok(defService.copyDef(id)); + } + + /** + * 导入流程定义 + * + * @param file 文件 + * @param category 分类 + */ + @Log(title = "流程定义", businessType = BusinessType.IMPORT) + @PostMapping("/importDef") + public R importDef(MultipartFile file, String category) { + return R.ok(flwDefinitionService.importJson(file, category)); + } + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + @Log(title = "流程定义", businessType = BusinessType.EXPORT) + @PostMapping("/exportDef/{id}") + public void exportDef(@PathVariable Long id, HttpServletResponse response) throws IOException { + flwDefinitionService.exportDef(id, response); + } + + /** + * 获取流程定义JSON字符串 + * + * @param id 流程定义id + */ + @GetMapping("/xmlString/{id}") + public R xmlString(@PathVariable Long id) { + return R.ok("操作成功", defService.exportJson(id)); + } + + /** + * 激活/挂起流程定义 + * + * @param id 流程定义id + * @param active 激活/挂起 + */ + @RepeatSubmit() + @PutMapping("/active/{id}") + @Transactional(rollbackFor = Exception.class) + public R active(@PathVariable Long id, @RequestParam boolean active) { + return R.ok(active ? defService.active(id) : defService.unActive(id)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java new file mode 100644 index 0000000..ae99c16 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java @@ -0,0 +1,157 @@ +package org.dromara.workflow.controller; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +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.warm.flow.core.service.InsService; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; +import org.dromara.workflow.service.IFlwInstanceService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/instance") +public class FlwInstanceController extends BaseController { + + private final InsService insService; + private final IFlwInstanceService flwInstanceService; + + /** + * 查询正在运行的流程实例列表 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @GetMapping("/pageByRunning") + public TableDataInfo selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return flwInstanceService.selectRunningInstanceList(flowInstanceBo, pageQuery); + } + + /** + * 查询已结束的流程实例列表 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @GetMapping("/pageByFinish") + public TableDataInfo selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return flwInstanceService.selectFinishInstanceList(flowInstanceBo, pageQuery); + } + + /** + * 根据业务id查询流程实例详细信息 + * + * @param businessId 业务id + */ + @GetMapping("/getInfo/{businessId}") + public R getInfo(@PathVariable Long businessId) { + return R.ok(flwInstanceService.queryByBusinessId(businessId)); + } + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + */ + @DeleteMapping("/deleteByBusinessIds/{businessIds}") + public R deleteByBusinessIds(@PathVariable List businessIds) { + return toAjax(flwInstanceService.deleteByBusinessIds(businessIds)); + } + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + */ + @DeleteMapping("/deleteByInstanceIds/{instanceIds}") + public R deleteByInstanceIds(@PathVariable List instanceIds) { + return toAjax(flwInstanceService.deleteByInstanceIds(instanceIds)); + } + + /** + * 撤销流程 + * + * @param bo 参数 + */ + @RepeatSubmit() + @PutMapping("/cancelProcessApply") + public R cancelProcessApply(@RequestBody FlowCancelBo bo) { + return toAjax(flwInstanceService.cancelProcessApply(bo)); + } + + /** + * 激活/挂起流程实例 + * + * @param id 流程实例id + * @param active 激活/挂起 + */ + @RepeatSubmit() + @PutMapping("/active/{id}") + public R active(@PathVariable Long id, @RequestParam boolean active) { + return R.ok(active ? insService.active(id) : insService.unActive(id)); + } + + /** + * 获取当前登陆人发起的流程实例 + * + * @param flowInstanceBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByCurrent") + public TableDataInfo selectCurrentInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + return flwInstanceService.selectCurrentInstanceList(flowInstanceBo, pageQuery); + } + + /** + * 获取流程图,流程记录 + * + * @param businessId 业务id + */ + @GetMapping("/flowImage/{businessId}") + public R> flowImage(@PathVariable String businessId) { + return R.ok(flwInstanceService.flowImage(businessId)); + } + + /** + * 获取流程变量 + * + * @param instanceId 流程实例id + */ + @GetMapping("/instanceVariable/{instanceId}") + public R> instanceVariable(@PathVariable Long instanceId) { + return R.ok(flwInstanceService.instanceVariable(instanceId)); + } + + /** + * 作废流程 + * + * @param bo 参数 + */ + @Log(title = "流程实例管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/invalid") + public R invalid(@Validated @RequestBody FlowInvalidBo bo) { + return R.ok(flwInstanceService.processInvalid(bo)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java new file mode 100644 index 0000000..463916b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java @@ -0,0 +1,201 @@ +package org.dromara.workflow.controller; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.dto.StartProcessReturnDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.validate.AddGroup; +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.warm.flow.core.entity.Node; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 任务管理 控制层 + * + * @author may + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/task") +public class FlwTaskController extends BaseController { + + private final IFlwTaskService flwTaskService; + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/startWorkFlow") + public R startWorkFlow(@Validated(AddGroup.class) @RequestBody StartProcessBo startProcessBo) { + StartProcessReturnDTO startProcessReturn = flwTaskService.startWorkFlow(startProcessBo); + return R.ok("提交成功", startProcessReturn); + } + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/completeTask") + public R completeTask(@Validated(AddGroup.class) @RequestBody CompleteTaskBo completeTaskBo) { + return toAjax(flwTaskService.completeTask(completeTaskBo)); + } + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByTaskWait") + public TableDataInfo pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByTaskWait(flowTaskBo, pageQuery); + } + + /** + * 查询当前用户的已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + + @GetMapping("/pageByTaskFinish") + public TableDataInfo pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByTaskFinish(flowTaskBo, pageQuery); + } + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByAllTaskWait") + public TableDataInfo pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByAllTaskWait(flowTaskBo, pageQuery); + } + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByAllTaskFinish") + public TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByAllTaskFinish(flowTaskBo, pageQuery); + } + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @GetMapping("/pageByTaskCopy") + public TableDataInfo pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + return flwTaskService.pageByTaskCopy(flowTaskBo, pageQuery); + } + + /** + * 根据taskId查询代表任务 + * + * @param taskId 任务id + */ + @GetMapping("/getTask/{taskId}") + public R getTask(@PathVariable Long taskId) { + return R.ok(flwTaskService.selectById(taskId)); + } + + /** + * 终止任务 + * + * @param bo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/terminationTask") + public R terminationTask(@RequestBody FlowTerminationBo bo) { + return R.ok(flwTaskService.terminationTask(bo)); + } + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + */ + @Log(title = "任务管理", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PostMapping("/taskOperation/{taskOperation}") + public R taskOperation(@Validated @RequestBody TaskOperationBo bo, @PathVariable String taskOperation) { + return toAjax(flwTaskService.taskOperation(bo, taskOperation)); + } + + /** + * 修改任务办理人 + * + * @param taskIdList 任务id + * @param userId 办理人id + */ + @Log(title = "任务管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/updateAssignee/{userId}") + public R updateAssignee(@RequestBody List taskIdList, @PathVariable String userId) { + return toAjax(flwTaskService.updateAssignee(taskIdList, userId)); + } + + /** + * 驳回审批 + * + * @param bo 参数 + */ + @Log(title = "任务管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/backProcess") + public R backProcess(@Validated({AddGroup.class}) @RequestBody BackProcessBo bo) { + return toAjax(flwTaskService.backProcess(bo)); + } + + /** + * 获取可驳回的前置节点 + * + * @param definitionId 流程定义id + * @param nowNodeCode 当前节点 + */ + @GetMapping("/getBackTaskNode/{definitionId}/{nowNodeCode}") + public R> getBackTaskNode(@PathVariable Long definitionId, @PathVariable String nowNodeCode) { + return R.ok(flwTaskService.getBackTaskNode(definitionId, nowNodeCode)); + } + + /** + * 获取当前任务的所有办理人 + * + * @param taskId 任务id + */ + @GetMapping("/currentTaskAllUser/{taskId}") + public R> currentTaskAllUser(@PathVariable Long taskId) { + return R.ok(flwTaskService.currentTaskAllUser(taskId)); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java new file mode 100644 index 0000000..98825d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java @@ -0,0 +1,108 @@ +package org.dromara.workflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +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.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; +import org.dromara.workflow.service.ITestLeaveService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 请假 + * + * @author may + * @date 2023-07-21 + */ +@ConditionalOnEnable +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/workflow/leave") +public class TestLeaveController extends BaseController { + + private final ITestLeaveService testLeaveService; + + /** + * 查询请假列表 + */ + @SaCheckPermission("workflow:leave:list") + @GetMapping("/list") + public TableDataInfo list(TestLeaveBo bo, PageQuery pageQuery) { + return testLeaveService.queryPageList(bo, pageQuery); + } + + /** + * 导出请假列表 + */ + @SaCheckPermission("workflow:leave:export") + @Log(title = "请假", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TestLeaveBo bo, HttpServletResponse response) { + List list = testLeaveService.queryList(bo); + ExcelUtil.exportExcel(list, "请假", TestLeaveVo.class, response); + } + + /** + * 获取请假详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("workflow:leave:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(testLeaveService.queryById(id)); + } + + /** + * 新增请假 + */ + @SaCheckPermission("workflow:leave:add") + @Log(title = "请假", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.insertByBo(bo)); + } + + /** + * 修改请假 + */ + @SaCheckPermission("workflow:leave:edit") + @Log(title = "请假", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestLeaveBo bo) { + return R.ok(testLeaveService.updateByBo(bo)); + } + + /** + * 删除请假 + * + * @param ids 主键串 + */ + @SaCheckPermission("workflow:leave:remove") + @Log(title = "请假", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids))); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java new file mode 100644 index 0000000..7d42a9b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java @@ -0,0 +1,63 @@ +package org.dromara.workflow.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; +import java.util.Date; + +/** + * 请假对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_leave") +public class TestLeave extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 请假类型 + */ + private String leaveType; + + /** + * 开始时间 + */ + private Date startDate; + + /** + * 结束时间 + */ + private Date endDate; + + /** + * 请假天数 + */ + private Integer leaveDays; + + /** + * 请假原因 + */ + private String remark; + + /** + * 状态 + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java new file mode 100644 index 0000000..3117a33 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java @@ -0,0 +1,71 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +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.List; +import java.util.Map; +import java.util.Objects; + + +/** + * 驳回参数请求 + * + * @author may + */ +@Data +public class BackProcessBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务ID + */ + @NotNull(message = "任务ID不能为空", groups = AddGroup.class) + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 驳回的节点id(目前未使用,直接驳回到申请人) + */ + @NotBlank(message = "驳回的节点不能为空", groups = AddGroup.class) + private String nodeCode; + + /** + * 办理意见 + */ + private String message; + + /** + * 通知 + */ + private String notice; + + /** + * 流程变量 + */ + 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/bo/CompleteTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java new file mode 100644 index 0000000..9fdf484 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java @@ -0,0 +1,75 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +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.List; +import java.util.Map; +import java.util.Objects; + +/** + * 办理任务请求对象 + * + * @author may + */ +@Data +public class CompleteTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotNull(message = "任务id不能为空", groups = {AddGroup.class}) + private Long taskId; + + /** + * 附件id + */ + private String fileId; + + /** + * 抄送人员 + */ + private List flowCopyList; + + /** + * 消息类型 + */ + private List messageType; + + /** + * 办理意见 + */ + private String message; + + /** + * 消息通知 + */ + private String notice; + + /** + * 流程变量 + */ + private Map variables; + + /** + * 扩展变量(此处为逗号分隔的ossId) + * @return + */ + private String ext; + + 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/bo/FlowCategoryBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java new file mode 100644 index 0000000..fd626eb --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java @@ -0,0 +1,47 @@ +package org.dromara.workflow.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 org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.workflow.domain.FlowCategory; + +/** + * 流程分类业务对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = FlowCategory.class, reverseConvertGenerate = false) +public class FlowCategoryBo extends BaseEntity { + + /** + * 流程分类ID + */ + @NotNull(message = "流程分类ID不能为空", groups = { EditGroup.class }) + private Long categoryId; + + /** + * 父流程分类id + */ + @NotNull(message = "父流程分类id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long parentId; + + /** + * 流程分类名称 + */ + @NotBlank(message = "流程分类名称不能为空", groups = {AddGroup.class, EditGroup.class}) + private String categoryName; + + /** + * 显示顺序 + */ + private Long orderNum; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java new file mode 100644 index 0000000..fb1fe61 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java @@ -0,0 +1,55 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 流程实例请求对象 + * + * @author may + */ +@Data +public class FlowInstanceBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 任务发起人 + */ + private String startUserId; + + /** + * 业务id + */ + private String businessId; + + /** + * 流程分类id + */ + private String category; + + /** + * 任务名称 + */ + private String nodeName; + + /** + * 申请人Ids + */ + private List createByIds; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java new file mode 100644 index 0000000..297bd00 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 作废请求对象 + * + * @author may + */ +@Data +public class FlowInvalidBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程实例id + */ + @NotNull(message = "流程实例id为空", groups = AddGroup.class) + private Long id; + + /** + * 审批意见 + */ + private String comment; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java new file mode 100644 index 0000000..64dd082 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java @@ -0,0 +1,55 @@ +package org.dromara.workflow.domain.bo; + +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 任务请求对象 + * + * @author may + */ +@Data +public class FlowTaskBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务名称 + */ + private String nodeName; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程实例id + */ + private Long instanceId; + + /** + * 权限列表 + */ + private List permissionList; + + /** + * 申请人Ids + */ + private List createByIds; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java new file mode 100644 index 0000000..897fc21 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java @@ -0,0 +1,31 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 终止任务请求对象 + * + * @author may + */ +@Data +public class FlowTerminationBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 任务id + */ + @NotNull(message = "任务id为空", groups = AddGroup.class) + private Long taskId; + + /** + * 审批意见 + */ + private String comment; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java new file mode 100644 index 0000000..4348e31 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java @@ -0,0 +1,48 @@ +package org.dromara.workflow.domain.bo; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + + +/** + * 任务操作业务对象,用于描述任务委派、转办、加签等操作的必要参数 + * 包含了用户ID、任务ID、任务相关的消息、以及加签/减签的用户ID + * + * @author AprilWind + */ +@Data +public class TaskOperationBo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 委派/转办人的用户ID(必填,准对委派/转办人操作) + */ + @NotNull(message = "委派/转办人id不能为空", groups = {AddGroup.class}) + private String userId; + + /** + * 加签/减签人的用户ID列表(必填,针对加签/减签操作) + */ + @NotNull(message = "加签/减签id不能为空", groups = {EditGroup.class}) + private List userIds; + + /** + * 任务ID(必填) + */ + @NotNull(message = "任务id不能为空") + private Long taskId; + + /** + * 意见或备注信息(可选) + */ + private String message; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java new file mode 100644 index 0000000..a1a4b59 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java @@ -0,0 +1,79 @@ +package org.dromara.workflow.domain.bo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.workflow.domain.TestLeave; + +import java.util.Date; + +/** + * 请假业务对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TestLeave.class, reverseConvertGenerate = false) +public class TestLeaveBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 请假类型 + */ + @NotBlank(message = "请假类型不能为空", groups = {AddGroup.class, EditGroup.class}) + private String leaveType; + + /** + * 开始时间 + */ + @NotNull(message = "开始时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @JsonFormat(pattern = "yyyy-MM-dd") + private Date startDate; + + /** + * 结束时间 + */ + @NotNull(message = "结束时间不能为空", groups = {AddGroup.class, EditGroup.class}) + @JsonFormat(pattern = "yyyy-MM-dd") + private Date endDate; + + /** + * 请假天数 + */ + private Integer leaveDays; + + /** + * 开始时间 + */ + private Integer startLeaveDays; + + /** + * 结束时间 + */ + private Integer endLeaveDays; + + /** + * 请假原因 + */ + private String remark; + + /** + * 状态 + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java new file mode 100644 index 0000000..c5d2785 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java @@ -0,0 +1,67 @@ +package org.dromara.workflow.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.workflow.domain.FlowCategory; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 流程分类视图对象 wf_category + * + * @author may + * @date 2023-06-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FlowCategory.class) +public class FlowCategoryVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 流程分类ID + */ + @ExcelProperty(value = "流程分类ID") + private Long categoryId; + + /** + * 父级id + */ + private Long parentId; + + /** + * 父类别名称 + */ + private String parentName; + + /** + * 祖级列表 + */ + private String ancestors; + + /** + * 流程分类名称 + */ + @ExcelProperty(value = "流程分类名称") + private String categoryName; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "显示顺序") + private Long orderNum; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java new file mode 100644 index 0000000..aef7573 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java @@ -0,0 +1,104 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + +/** + * 流程定义视图 + * + * @author may + */ +@Data +public class FlowDefinitionVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 流程版本 + */ + private String version; + + /** + * 是否发布(0未发布 1已发布 9失效) + */ + private Integer isPublish; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 流程激活状态(0挂起 1激活) + */ + private Integer activityStatus; + + /** + * 监听器类型 + */ + private String listenerType; + + /** + * 监听器路径 + */ + private String listenerPath; + + /** + * 扩展字段,预留给业务系统使用 + */ + private String ext; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java new file mode 100644 index 0000000..8776a76 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java @@ -0,0 +1,244 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.warm.flow.core.enums.CooperateType; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 历史任务视图 + * + * @author may + */ +@Data +public class FlowHisTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程实例表id + */ + private Long instanceId; + + /** + * 任务表id + */ + private Long taskId; + + /** + * 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + */ + private Integer cooperateType; + + /** + * 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + */ + private String cooperateTypeName; + + /** + * 业务id + */ + private String businessId; + + /** + * 开始节点编码 + */ + private String nodeCode; + + /** + * 开始节点名称 + */ + private String nodeName; + + /** + * 开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 目标节点编码 + */ + private String targetNodeCode; + + /** + * 结束节点名称 + */ + private String targetNodeName; + + /** + * 审批者 + */ + private String approver; + + /** + * 审批者 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "approver") + private String approveName; + + /** + * 协作人(只有转办、会签、票签、委派) + */ + private String collaborator; + + /** + * 权限标识 permissionFlag的list形式 + */ + private List permissionList; + + /** + * 跳转类型(PASS通过 REJECT退回 NONE无动作) + */ + private String skipType; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 任务状态 + */ + private String flowTaskStatus; + + /** + * 流程状态 + */ + private String flowStatusName; + + /** + * 审批意见 + */ + private String message; + + /** + * 业务详情 存业务类的json + */ + private String ext; + + /** + * 创建者 + */ + private String createBy; + + /** + * 申请人 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程版本号 + */ + private String version; + + /** + * 运行时长 + */ + private String runDuration; + + /** + * 设置创建时间并计算任务运行时长 + * + * @param createTime 创建时间 + */ + public void setCreateTime(Date createTime) { + this.createTime = createTime; + updateRunDuration(); + } + + /** + * 设置更新时间并计算任务运行时长 + * + * @param updateTime 更新时间 + */ + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + updateRunDuration(); + } + + /** + * 更新运行时长 + */ + private void updateRunDuration() { + // 如果创建时间和更新时间均不为空,计算它们之间的时长 + if (this.updateTime != null && this.createTime != null) { + this.runDuration = DateUtils.getTimeDifference(this.updateTime, this.createTime); + } + } + + /** + * 设置协作方式,并通过协作方式获取名称 + */ + public void setCooperateType(Integer cooperateType) { + this.cooperateType = cooperateType; + this.cooperateTypeName = CooperateType.getValueByKey(cooperateType); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java new file mode 100644 index 0000000..75543f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java @@ -0,0 +1,137 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.util.Date; + +/** + * 流程实例视图 + * + * @author may + */ +@Data +public class FlowInstanceVo { + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 业务id + */ + private String businessId; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 流程节点编码 每个流程的nodeCode是唯一的,即definitionId+nodeCode唯一,在数据库层面做了控制 + */ + private String nodeCode; + + /** + * 流程节点名称 + */ + private String nodeName; + + /** + * 流程变量 + */ + private String variable; + + /** + * 流程状态(0待提交 1审批中 2 审批通过 3自动通过 8已完成 9已退回 10失效) + */ + private String flowStatus; + + /** + * 流程状态 + */ + private String flowStatusName; + + /** + * 流程激活状态(0挂起 1激活) + */ + private Integer activityStatus; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单路径 + */ + private String formPath; + + /** + * 扩展字段,预留给业务系统使用 + */ + private String ext; + + /** + * 流程定义版本 + */ + private String version; + + /** + * 创建者 + */ + private String createBy; + + /** + * 申请人 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java new file mode 100644 index 0000000..3fb08d9 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java @@ -0,0 +1,176 @@ +package org.dromara.workflow.domain.vo; + +import lombok.Data; +import org.dromara.common.translation.annotation.Translation; +import org.dromara.common.translation.constant.TransConstant; +import org.dromara.warm.flow.core.entity.User; +import org.dromara.workflow.common.constant.FlowConstant; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * 任务视图 + * + * @author may + */ +@Data +public class FlowTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 租户ID + */ + private String tenantId; + + /** + * 删除标记 + */ + private String delFlag; + + /** + * 对应flow_definition表的id + */ + private Long definitionId; + + /** + * 流程实例表id + */ + private Long instanceId; + + /** + * 流程定义名称 + */ + private String flowName; + + /** + * 业务id + */ + private String businessId; + + /** + * 节点编码 + */ + private String nodeCode; + + /** + * 节点名称 + */ + private String nodeName; + + /** + * 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + */ + private Integer nodeType; + + /** + * 权限标识 permissionFlag的list形式 + */ + private List permissionList; + + /** + * 流程用户列表 + */ + private List userList; + + /** + * 审批表单是否自定义(Y是 N否) + */ + private String formCustom; + + /** + * 审批表单 + */ + private String formPath; + + /** + * 流程定义编码 + */ + private String flowCode; + + /** + * 流程版本号 + */ + private String version; + + /** + * 流程状态 + */ + private String flowStatus; + + /** + * 流程分类id + */ + private String category; + + /** + * 流程分类名称 + */ + @Translation(type = FlowConstant.CATEGORY_ID_TO_NAME, mapper = "category") + private String categoryName; + + /** + * 流程状态 + */ + @Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "flowStatus", other = "wf_business_status") + private String flowStatusName; + + /** + * 办理人类型 + */ + private String type; + + /** + * 办理人ids + */ + private String assigneeIds; + + /** + * 办理人名称 + */ + private String assigneeNames; + + /** + * 抄送人id + */ + private String processedBy; + + /** + * 抄送人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "processedBy") + private String processedByName; + + /** + * 流程签署比例值 大于0为票签,会签 + */ + private BigDecimal nodeRatio; + + /** + * 申请人id + */ + private String createBy; + + /** + * 申请人名称 + */ + @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "createBy") + private String createByName; +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java new file mode 100644 index 0000000..47886d7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java @@ -0,0 +1,70 @@ +package org.dromara.workflow.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.workflow.domain.TestLeave; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 请假视图对象 test_leave + * + * @author may + * @date 2023-07-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TestLeave.class) +public class TestLeaveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 请假类型 + */ + @ExcelProperty(value = "请假类型") + private String leaveType; + + /** + * 开始时间 + */ + @ExcelProperty(value = "开始时间") + private Date startDate; + + /** + * 结束时间 + */ + @ExcelProperty(value = "结束时间") + private Date endDate; + + /** + * 请假天数 + */ + @ExcelProperty(value = "请假天数") + private Integer leaveDays; + + /** + * 备注 + */ + @ExcelProperty(value = "请假原因") + private String remark; + + /** + * 状态 + */ + @ExcelProperty(value = "状态") + private String status; + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java new file mode 100644 index 0000000..4b215ef --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java @@ -0,0 +1,82 @@ +package org.dromara.workflow.handler; + +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.utils.SpringUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 流程监听服务 + * + * @author may + * @date 2024-06-02 + */ +@ConditionalOnEnable +@Slf4j +@Component +public class FlowProcessEventHandler { + + /** + * 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成等) + * + * @param flowCode 流程定义编码 + * @param businessId 业务id + * @param status 状态 + * @param submit 当为true时为申请人节点办理 + */ + public void processHandler(String flowCode, String businessId, String status, Map params, boolean submit) { + String tenantId = TenantHelper.getTenantId(); + log.info("发布流程事件,租户ID: {}, 流程状态: {}, 流程编码: {}, 业务ID: {}, 是否申请人节点办理: {}", tenantId, status, flowCode, businessId, submit); + ProcessEvent processEvent = new ProcessEvent(); + processEvent.setTenantId(tenantId); + processEvent.setFlowCode(flowCode); + processEvent.setBusinessId(businessId); + processEvent.setStatus(status); + processEvent.setParams(params); + processEvent.setSubmit(submit); + SpringUtils.context().publishEvent(processEvent); + } + + /** + * 执行办理任务监听 + * + * @param flowCode 流程定义编码 + * @param nodeCode 审批节点编码 + * @param taskId 任务id + * @param businessId 业务id + */ + public void processTaskHandler(String flowCode, String nodeCode, Long taskId, String businessId) { + String tenantId = TenantHelper.getTenantId(); + log.info("发布流程任务事件, 租户ID: {}, 流程编码: {}, 节点编码: {}, 任务ID: {}, 业务ID: {}", tenantId, flowCode, nodeCode, taskId, businessId); + ProcessTaskEvent processTaskEvent = new ProcessTaskEvent(); + processTaskEvent.setTenantId(tenantId); + processTaskEvent.setFlowCode(flowCode); + processTaskEvent.setNodeCode(nodeCode); + processTaskEvent.setTaskId(taskId); + processTaskEvent.setBusinessId(businessId); + SpringUtils.context().publishEvent(processTaskEvent); + } + + /** + * 删除流程监听 + * + * @param flowCode 流程定义编码 + * @param businessId 业务ID + */ + public void processDeleteHandler(String flowCode, String businessId) { + String tenantId = TenantHelper.getTenantId(); + log.info("发布删除流程事件, 租户ID: {}, 流程编码: {}, 业务ID: {}", tenantId, flowCode, businessId); + ProcessDeleteEvent processDeleteEvent = new ProcessDeleteEvent(); + processDeleteEvent.setTenantId(tenantId); + processDeleteEvent.setFlowCode(flowCode); + processDeleteEvent.setBusinessId(businessId); + SpringUtils.context().publishEvent(processDeleteEvent); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java new file mode 100644 index 0000000..c18e4ed --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java @@ -0,0 +1,73 @@ +package org.dromara.workflow.handler; + +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskAssigneeEnum; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.handler.PermissionHandler; +import org.dromara.warm.flow.core.service.impl.TaskServiceImpl; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 办理人权限处理器 + * + * @author AprilWind + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Component +@Slf4j +public class WorkflowPermissionHandler implements PermissionHandler { + + /** + * 审批前获取当前办理人,办理时会校验的该权限集合 + * 后续在{@link TaskServiceImpl#checkAuth(Task, FlowParams)} 中调用 + * 返回当前用户权限集合 + */ + @Override + public List permissions() { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + return new ArrayList<>(); + } + // 使用一个流来构建权限列表 + return Stream.of( + // 角色权限前缀 + loginUser.getRoles().stream() + .map(role -> TaskAssigneeEnum.ROLE.getCode() + role.getRoleId()), + + // 岗位权限前缀 + Stream.ofNullable(loginUser.getPosts()) + .flatMap(Collection::stream) + .map(post -> TaskAssigneeEnum.POST.getCode() + post.getPostId()), + + // 用户和部门权限 + Stream.of(String.valueOf(loginUser.getUserId()), + TaskAssigneeEnum.DEPT.getCode() + loginUser.getDeptId() + ) + ) + .flatMap(stream -> stream) + .collect(Collectors.toList()); + } + + /** + * 获取当前办理人 + * + * @return 当前办理人 + */ + @Override + public String getHandler() { + return LoginHelper.getUserIdStr(); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java new file mode 100644 index 0000000..d2c0b3a --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java @@ -0,0 +1,60 @@ +package org.dromara.workflow.mapper; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +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.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.vo.FlowCategoryVo; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * 流程分类Mapper接口 + * + * @author may + * @date 2023-06-27 + */ +public interface FlwCategoryMapper extends BaseMapperPlus { + + /** + * 统计指定流程分类ID的分类数量 + * + * @param categoryId 流程分类ID + * @return 该流程分类ID的分类数量 + */ + @DataPermission({ + @DataColumn(key = "deptName", value = "createDept") + }) + long countCategoryById(Long categoryId); + + /** + * 根据父流程分类ID查询其所有子流程分类的列表 + * + * @param parentId 父流程分类ID + * @return 包含子流程分类的列表 + */ + default List selectListByParentId(Long parentId) { + return this.selectList(new LambdaQueryWrapper() + .select(FlowCategory::getCategoryId) + .apply(DataBaseHelper.findInSet(parentId, "ancestors"))); + } + + /** + * 根据父流程分类ID查询包括父ID及其所有子流程分类ID的列表 + * + * @param parentId 父流程分类ID + * @return 包含父ID和子流程分类ID的列表 + */ + default List selectCategoryIdsByParentId(Long parentId) { + return Stream.concat( + this.selectListByParentId(parentId).stream() + .map(FlowCategory::getCategoryId), + Stream.of(parentId) + ).collect(Collectors.toList()); + } + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java new file mode 100644 index 0000000..cd1edba --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java @@ -0,0 +1,15 @@ +package org.dromara.workflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.workflow.domain.TestLeave; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +/** + * 请假Mapper接口 + * + * @author may + * @date 2023-07-21 + */ +public interface TestLeaveMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java new file mode 100644 index 0000000..91f173d --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java @@ -0,0 +1,102 @@ +package org.dromara.workflow.service; + +import cn.hutool.core.lang.tree.Tree; +import org.dromara.workflow.domain.bo.FlowCategoryBo; +import org.dromara.workflow.domain.vo.FlowCategoryVo; + +import java.util.List; + +/** + * 流程分类Service接口 + * + * @author may + */ +public interface IFlwCategoryService { + + /** + * 查询流程分类 + * + * @param categoryId 主键 + * @return 流程分类 + */ + FlowCategoryVo queryById(Long categoryId); + + /** + * 根据流程分类ID查询流程分类名称 + * + * @param categoryId 流程分类ID + * @return 流程分类名称 + */ + String selectCategoryNameById(Long categoryId); + + /** + * 查询符合条件的流程分类列表 + * + * @param bo 查询条件 + * @return 流程分类列表 + */ + List queryList(FlowCategoryBo bo); + + /** + * 查询流程分类树结构信息 + * + * @param category 流程分类信息 + * @return 流程分类树信息集合 + */ + List> selectCategoryTreeList(FlowCategoryBo category); + + /** + * 校验流程分类是否有数据权限 + * + * @param categoryId 流程分类ID + */ + void checkCategoryDataScope(Long categoryId); + + /** + * 校验流程分类名称是否唯一 + * + * @param category 流程分类信息 + * @return 结果 + */ + boolean checkCategoryNameUnique(FlowCategoryBo category); + + /** + * 查询流程分类是否存在流程定义 + * + * @param categoryId 流程分类ID + * @return 结果 true 存在 false 不存在 + */ + boolean checkCategoryExistDefinition(Long categoryId); + + /** + * 是否存在流程分类子节点 + * + * @param categoryId 流程分类ID + * @return 结果 + */ + boolean hasChildByCategoryId(Long categoryId); + + /** + * 新增流程分类 + * + * @param bo 流程分类 + * @return 是否新增成功 + */ + int insertByBo(FlowCategoryBo bo); + + /** + * 修改流程分类 + * + * @param bo 流程分类 + * @return 是否修改成功 + */ + int updateByBo(FlowCategoryBo bo); + + /** + * 删除流程分类信息 + * + * @param categoryId 主键 + * @return 是否删除成功 + */ + int deleteWithValidById(Long categoryId); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java new file mode 100644 index 0000000..99729c2 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java @@ -0,0 +1,159 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; + +import java.util.List; +import java.util.Map; + +/** + * 流程实例 服务层 + * + * @author may + */ +public interface IFlwInstanceService { + + /** + * 分页查询正在运行的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery); + + /** + * 分页查询已结束的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery); + + /** + * 根据业务id查询流程实例详细信息 + * + * @param businessId 业务id + * @return 结果 + */ + FlowInstanceVo queryByBusinessId(Long businessId); + + /** + * 按照业务id查询流程实例 + * + * @param businessId 业务id + * @return 结果 + */ + FlowInstance selectInstByBusinessId(String businessId); + + /** + * 按照实例id查询流程实例 + * + * @param instanceId 实例id + * @return 结果 + */ + FlowInstance selectInstById(Long instanceId); + + /** + * 按照实例id查询流程实例 + * + * @param instanceIds 实例id + * @return 结果 + */ + List selectInstListByIdList(List instanceIds); + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + * @return 结果 + */ + boolean deleteByBusinessIds(List businessIds); + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + * @return 结果 + */ + boolean deleteByInstanceIds(List instanceIds); + + /** + * 撤销流程 + * + * @param bo 参数 + * @return 结果 + */ + boolean cancelProcessApply(FlowCancelBo bo); + + /** + * 获取当前登陆人发起的流程实例 + * + * @param instanceBo 流程实例 + * @param pageQuery 分页 + * @return 结果 + */ + TableDataInfo selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery); + + /** + * 获取流程图,流程记录 + * + * @param businessId 业务id + * @return 结果 + */ + Map flowImage(String businessId); + + /** + * 按照实例id更新状态 + * + * @param instanceId 实例id + * @param status 状态 + */ + void updateStatus(Long instanceId, String status); + + /** + * 获取流程变量 + * + * @param instanceId 实例id + * @return 结果 + */ + Map instanceVariable(Long instanceId); + + /** + * 设置流程变量 + * + * @param instanceId 实例id + * @param variable 流程变量 + */ + void setVariable(Long instanceId, Map variable); + + /** + * 按任务id查询实例 + * + * @param taskId 任务id + * @return 结果 + */ + FlowInstance selectByTaskId(Long taskId); + + /** + * 按任务id查询实例 + * + * @param taskIdList 任务id + * @return 结果 + */ + List selectByTaskIdList(List taskIdList); + + /** + * 作废流程 + * + * @param bo 流程实例 + * @return 结果 + */ + boolean processInvalid(FlowInvalidBo bo); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java new file mode 100644 index 0000000..116cb74 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java @@ -0,0 +1,22 @@ +package org.dromara.workflow.service; + +import org.dromara.common.core.domain.dto.UserDTO; + +import java.util.List; + +/** + * 流程设计器-获取办理人 + * + * @author AprilWind + */ +public interface IFlwTaskAssigneeService { + + /** + * 根据存储标识符(storageId)解析分配类型和ID,并获取对应的用户列表 + * + * @param storageId 包含分配类型和ID的字符串(例如 "user:123" 或 "role:456") + * @return 与分配类型和ID匹配的用户列表,如果格式无效则返回空列表 + */ + List fetchUsersByStorageId(String storageId); + +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java new file mode 100644 index 0000000..67b50ba --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java @@ -0,0 +1,47 @@ +package org.dromara.workflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.workflow.domain.bo.TestLeaveBo; +import org.dromara.workflow.domain.vo.TestLeaveVo; + +import java.util.List; + +/** + * 请假Service接口 + * + * @author may + * @date 2023-07-21 + */ +public interface ITestLeaveService { + + /** + * 查询请假 + */ + TestLeaveVo queryById(Long id); + + /** + * 查询请假列表 + */ + TableDataInfo queryPageList(TestLeaveBo bo, PageQuery pageQuery); + + /** + * 查询请假列表 + */ + List queryList(TestLeaveBo bo); + + /** + * 新增请假 + */ + TestLeaveVo insertByBo(TestLeaveBo bo); + + /** + * 修改请假 + */ + TestLeaveVo updateByBo(TestLeaveBo bo); + + /** + * 校验并批量删除请假信息 + */ + Boolean deleteWithValidByIds(List ids); +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java new file mode 100644 index 0000000..8c73b59 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java @@ -0,0 +1,37 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.convert.Convert; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.translation.annotation.TranslationType; +import org.dromara.common.translation.core.TranslationInterface; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.service.IFlwCategoryService; +import org.springframework.stereotype.Service; + +/** + * 流程分类名称翻译实现 + * + * @author AprilWind + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +@TranslationType(type = FlowConstant.CATEGORY_ID_TO_NAME) +public class CategoryNameTranslationImpl implements TranslationInterface { + + private final IFlwCategoryService flwCategoryService; + + @Override + public String translation(Object key, String other) { + Long id = null; + if (key instanceof String categoryId) { + id = Convert.toLong(categoryId); + } else if (key instanceof Long categoryId) { + id = categoryId; + } + return flwCategoryService.selectCategoryNameById(id); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java new file mode 100644 index 0000000..591339b --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java @@ -0,0 +1,266 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.io.IoUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.warm.flow.core.dto.DefJson; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.PublishStatus; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.orm.entity.FlowDefinition; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowSkip; +import org.dromara.warm.flow.orm.mapper.FlowDefinitionMapper; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.warm.flow.orm.mapper.FlowSkipMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.constant.FlowConstant; +import org.dromara.workflow.domain.FlowCategory; +import org.dromara.workflow.domain.vo.FlowDefinitionVo; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.dromara.common.core.constant.TenantConstants.DEFAULT_TENANT_ID; + +/** + * 流程定义 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwDefinitionServiceImpl implements IFlwDefinitionService { + + private final DefService defService; + private final FlowDefinitionMapper flowDefinitionMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowNodeMapper flowNodeMapper; + private final FlowSkipMapper flowSkipMapper; + private final FlwCategoryMapper flwCategoryMapper; + + /** + * 查询流程定义列表 + * + * @param flowDefinition 流程定义信息 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + @Override + public TableDataInfo queryList(FlowDefinition flowDefinition, PageQuery pageQuery) { + LambdaQueryWrapper wrapper = buildQueryWrapper(flowDefinition); + wrapper.eq(FlowDefinition::getIsPublish, PublishStatus.PUBLISHED.getKey()); + Page page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + TableDataInfo build = TableDataInfo.build(); + build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class)); + build.setTotal(page.getTotal()); + return build; + } + + /** + * 查询未发布的流程定义列表 + * + * @param flowDefinition 流程定义信息 + * @param pageQuery 分页 + * @return 返回分页列表 + */ + @Override + public TableDataInfo unPublishList(FlowDefinition flowDefinition, PageQuery pageQuery) { + LambdaQueryWrapper wrapper = buildQueryWrapper(flowDefinition); + wrapper.in(FlowDefinition::getIsPublish, Arrays.asList(PublishStatus.UNPUBLISHED.getKey(), PublishStatus.EXPIRED.getKey())); + Page page = flowDefinitionMapper.selectPage(pageQuery.build(), wrapper); + TableDataInfo build = TableDataInfo.build(); + build.setRows(BeanUtil.copyToList(page.getRecords(), FlowDefinitionVo.class)); + build.setTotal(page.getTotal()); + return build; + } + + private LambdaQueryWrapper buildQueryWrapper(FlowDefinition flowDefinition) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowCode()), FlowDefinition::getFlowCode, flowDefinition.getFlowCode()); + wrapper.like(StringUtils.isNotBlank(flowDefinition.getFlowName()), FlowDefinition::getFlowName, flowDefinition.getFlowName()); + if (StringUtils.isNotBlank(flowDefinition.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowDefinition.getCategory())); + wrapper.in(FlowDefinition::getCategory, StreamUtils.toList(categoryIds, Convert::toStr)); + } + wrapper.orderByDesc(FlowDefinition::getCreateTime); + return wrapper; + } + + /** + * 发布流程定义 + * + * @param id 流程定义id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean publish(Long id) { + List flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper().eq(FlowNode::getDefinitionId, id)); + List errorMsg = new ArrayList<>(); + if (CollUtil.isNotEmpty(flowNodes)) { + for (FlowNode flowNode : flowNodes) { + String applyNodeCode = WorkflowUtils.applyNodeCode(id); + if (StringUtils.isBlank(flowNode.getPermissionFlag()) && !applyNodeCode.equals(flowNode.getNodeCode()) && NodeType.BETWEEN.getKey().equals(flowNode.getNodeType())) { + errorMsg.add(flowNode.getNodeName()); + } + } + if (CollUtil.isNotEmpty(errorMsg)) { + throw new ServiceException("节点【" + StringUtils.join(errorMsg, ",") + "】未配置办理人!"); + } + } + return defService.publish(id); + } + + /** + * 导入流程定义 + * + * @param file 文件 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean importJson(MultipartFile file, String category) { + try { + DefJson defJson = JsonUtils.parseObject(file.getBytes(), DefJson.class); + defJson.setCategory(category); + defService.importDef(defJson); + } catch (IOException e) { + log.error("读取文件流错误: {}", e.getMessage(), e); + throw new IllegalStateException("文件读取失败,请检查文件内容", e); + } + return true; + } + + /** + * 导出流程定义 + * + * @param id 流程定义id + * @param response 响应 + * @throws IOException 异常 + */ + @Override + public void exportDef(Long id, HttpServletResponse response) throws IOException { + byte[] data = defService.exportJson(id).getBytes(StandardCharsets.UTF_8); + // 设置响应头和内容类型 + response.reset(); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setContentType("application/text"); + response.setHeader("Content-Disposition", "attachment;"); + response.addHeader("Content-Length", "" + data.length); + IoUtil.write(response.getOutputStream(), false, data); + } + + /** + * 删除流程定义 + * + * @param ids 流程定义id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean removeDef(List ids) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.in(FlowHisTask::getDefinitionId, ids); + List flowHisTasks = flowHisTaskMapper.selectList(wrapper); + if (CollUtil.isNotEmpty(flowHisTasks)) { + List flowDefinitions = flowDefinitionMapper.selectByIds(StreamUtils.toList(flowHisTasks, FlowHisTask::getDefinitionId)); + if (CollUtil.isNotEmpty(flowDefinitions)) { + String join = StreamUtils.join(flowDefinitions, FlowDefinition::getFlowCode); + log.error("流程定义【{}】已被使用不可被删除!", join); + throw new ServiceException("流程定义【" + join + "】已被使用不可被删除!"); + } + } + try { + defService.removeDef(ids); + } catch (Exception e) { + log.error("Error removing flow definitions: {}", e.getMessage(), e); + throw new RuntimeException("Failed to remove flow definitions", e); + } + return true; + } + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void syncDef(String tenantId) { + List flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID)); + if (CollUtil.isEmpty(flowDefinitions)) { + return; + } + FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper() + .eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID).eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID)); + flowCategory.setCategoryId(null); + flowCategory.setTenantId(tenantId); + flwCategoryMapper.insert(flowCategory); + List defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId); + List flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper().in(FlowNode::getDefinitionId, defIds)); + List flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper().in(FlowSkip::getDefinitionId, defIds)); + for (FlowDefinition definition : flowDefinitions) { + FlowDefinition flowDefinition = BeanUtil.toBean(definition, FlowDefinition.class); + flowDefinition.setId(null); + flowDefinition.setTenantId(tenantId); + flowDefinition.setIsPublish(0); + flowDefinition.setCategory(String.valueOf(flowCategory.getCategoryId())); + int insert = flowDefinitionMapper.insert(flowDefinition); + if (insert <= 0) { + log.info("同步流程定义【{}】失败!", definition.getFlowCode()); + continue; + } + log.info("同步流程定义【{}】成功!", definition.getFlowCode()); + Long definitionId = flowDefinition.getId(); + if (CollUtil.isNotEmpty(flowNodes)) { + List nodes = StreamUtils.filter(flowNodes, node -> node.getDefinitionId().equals(definition.getId())); + if (CollUtil.isNotEmpty(nodes)) { + List flowNodeList = BeanUtil.copyToList(nodes, FlowNode.class); + flowNodeList.forEach(e -> { + e.setId(null); + e.setDefinitionId(definitionId); + e.setTenantId(tenantId); + e.setPermissionFlag(null); + }); + flowNodeMapper.insertOrUpdate(flowNodeList); + } + } + if (CollUtil.isNotEmpty(flowSkips)) { + List skips = StreamUtils.filter(flowSkips, skip -> skip.getDefinitionId().equals(definition.getId())); + if (CollUtil.isNotEmpty(skips)) { + List flowSkipList = BeanUtil.copyToList(skips, FlowSkip.class); + flowSkipList.forEach(e -> { + e.setId(null); + e.setDefinitionId(definitionId); + e.setTenantId(tenantId); + }); + flowSkipMapper.insertOrUpdate(flowSkipList); + } + } + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java new file mode 100644 index 0000000..db8ab71 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java @@ -0,0 +1,451 @@ +package org.dromara.workflow.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.ObjectUtil; +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 lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +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.warm.flow.core.FlowEngine; +import org.dromara.warm.flow.core.constant.ExceptionCons; +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.enums.NodeType; +import org.dromara.warm.flow.core.service.ChartService; +import org.dromara.warm.flow.core.service.DefService; +import org.dromara.warm.flow.core.service.InsService; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.orm.entity.FlowHisTask; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.FlowCancelBo; +import org.dromara.workflow.domain.bo.FlowInstanceBo; +import org.dromara.workflow.domain.bo.FlowInvalidBo; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowInstanceVo; +import org.dromara.workflow.domain.vo.FlowVariableVo; +import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.mapper.FlwInstanceMapper; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程实例 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwInstanceServiceImpl implements IFlwInstanceService { + + private final InsService insService; + private final DefService defService; + private final ChartService chartService; + private final TaskService taskService; + private final FlowHisTaskMapper flowHisTaskMapper; + private final FlowInstanceMapper flowInstanceMapper; + private final FlowProcessEventHandler flowProcessEventHandler; + private final IFlwTaskService flwTaskService; + private final FlwInstanceMapper flwInstanceMapper; + private final FlwCategoryMapper flwCategoryMapper; + + /** + * 分页查询正在运行的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo selectRunningInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowInstanceBo); + queryWrapper.in("fi.flow_status", BusinessStatusEnum.runningStatus()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 分页查询已结束的流程实例 + * + * @param flowInstanceBo 流程实例 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo selectFinishInstanceList(FlowInstanceBo flowInstanceBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowInstanceBo); + queryWrapper.in("fi.flow_status", BusinessStatusEnum.finishStatus()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 根据业务id查询流程实例详细信息 + * + * @param businessId 业务id + * @return 结果 + */ + @Override + public FlowInstanceVo queryByBusinessId(Long businessId) { + FlowInstance instance = this.selectInstByBusinessId(String.valueOf(businessId)); + FlowInstanceVo instanceVo = BeanUtil.toBean(instance, FlowInstanceVo.class); + Definition definition = defService.getById(instanceVo.getDefinitionId()); + instanceVo.setFlowName(definition.getFlowName()); + instanceVo.setFlowCode(definition.getFlowCode()); + instanceVo.setVersion(definition.getVersion()); + instanceVo.setFormCustom(definition.getFormCustom()); + instanceVo.setFormPath(definition.getFormPath()); + instanceVo.setCategory(definition.getCategory()); + return instanceVo; + } + + /** + * 通用查询条件 + * + * @param flowInstanceBo 查询条件 + * @return 查询条件构造方法 + */ + private QueryWrapper buildQueryWrapper(FlowInstanceBo flowInstanceBo) { + QueryWrapper queryWrapper = Wrappers.query(); + queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getNodeName()), "fi.node_name", flowInstanceBo.getNodeName()); + queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowName()), "fd.flow_name", flowInstanceBo.getFlowName()); + queryWrapper.like(StringUtils.isNotBlank(flowInstanceBo.getFlowCode()), "fd.flow_code", flowInstanceBo.getFlowCode()); + if (StringUtils.isNotBlank(flowInstanceBo.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowInstanceBo.getCategory())); + queryWrapper.in("fd.category", StreamUtils.toList(categoryIds, Convert::toStr)); + } + queryWrapper.eq(StringUtils.isNotBlank(flowInstanceBo.getBusinessId()), "fi.business_id", flowInstanceBo.getBusinessId()); + queryWrapper.in(CollUtil.isNotEmpty(flowInstanceBo.getCreateByIds()), "fi.create_by", flowInstanceBo.getCreateByIds()); + queryWrapper.eq("fi.del_flag", "0"); + queryWrapper.orderByDesc("fi.create_time"); + return queryWrapper; + } + + /** + * 根据业务id查询流程实例 + * + * @param businessId 业务id + */ + @Override + public FlowInstance selectInstByBusinessId(String businessId) { + return flowInstanceMapper.selectOne(new LambdaQueryWrapper().eq(FlowInstance::getBusinessId, businessId)); + } + + /** + * 按照实例id查询流程实例 + * + * @param instanceId 实例id + */ + @Override + public FlowInstance selectInstById(Long instanceId) { + return flowInstanceMapper.selectById(instanceId); + } + + /** + * 按照实例id查询流程实例 + * + * @param instanceIds 实例id + */ + @Override + public List selectInstListByIdList(List instanceIds) { + return flowInstanceMapper.selectByIds(instanceIds); + } + + /** + * 按照业务id删除流程实例 + * + * @param businessIds 业务id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByBusinessIds(List businessIds) { + List flowInstances = flowInstanceMapper.selectList(new LambdaQueryWrapper().in(FlowInstance::getBusinessId, businessIds)); + if (CollUtil.isEmpty(flowInstances)) { + log.warn("未找到对应的流程实例信息,无法执行删除操作。"); + return false; + } + return insService.remove(StreamUtils.toList(flowInstances, FlowInstance::getId)); + } + + /** + * 按照实例id删除流程实例 + * + * @param instanceIds 实例id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean deleteByInstanceIds(List instanceIds) { + // 获取实例信息 + List instances = insService.getByIds(instanceIds); + if (CollUtil.isEmpty(instances)) { + log.warn("未找到对应的流程实例信息,无法执行删除操作。"); + return false; + } + // 获取定义信息 + Map definitionMap = defService.getByIds( + StreamUtils.toList(instances, Instance::getDefinitionId) + ).stream().collect(Collectors.toMap(Definition::getId, definition -> definition)); + + // 逐一触发删除事件 + instances.forEach(instance -> { + Definition definition = definitionMap.get(instance.getDefinitionId()); + if (ObjectUtil.isNull(definition)) { + log.warn("实例 ID: {} 对应的流程定义信息未找到,跳过删除事件触发。", instance.getId()); + return; + } + flowProcessEventHandler.processDeleteHandler(definition.getFlowCode(), instance.getBusinessId()); + }); + + // 删除实例 + return insService.remove(instanceIds); + } + + /** + * 撤销流程 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean cancelProcessApply(FlowCancelBo bo) { + try { + Instance instance = selectInstByBusinessId(bo.getBusinessId()); + if (instance == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Definition definition = defService.getById(instance.getDefinitionId()); + if (definition == null) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_DEF); + } + String message = bo.getMessage(); + BusinessStatusEnum.checkCancelStatus(instance.getFlowStatus()); + String applyNodeCode = WorkflowUtils.applyNodeCode(definition.getId()); + //撤销 + WorkflowUtils.backTask(message, instance.getId(), applyNodeCode, BusinessStatusEnum.CANCEL.getStatus(), BusinessStatusEnum.CANCEL.getStatus()); + //判断或签节点是否有多个,只保留一个 + List currentTaskList = taskService.list(FlowEngine.newTask().setInstanceId(instance.getId())); + if (CollUtil.isNotEmpty(currentTaskList)) { + if (currentTaskList.size() > 1) { + currentTaskList.remove(0); + WorkflowUtils.deleteRunTask(StreamUtils.toList(currentTaskList, Task::getId)); + } + } + + } catch (Exception e) { + log.error("撤销失败: {}", e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + return true; + } + + /** + * 获取当前登陆人发起的流程实例 + * + * @param instanceBo 流程实例 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo selectCurrentInstanceList(FlowInstanceBo instanceBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(instanceBo); + queryWrapper.eq("fi.create_by", LoginHelper.getUserIdStr()); + Page page = flwInstanceMapper.selectInstanceList(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 获取流程图,流程记录 + * + * @param businessId 业务id + */ + @Override + public Map flowImage(String businessId) { + FlowInstance flowInstance = this.selectInstByBusinessId(businessId); + if (ObjectUtil.isNull(flowInstance)) { + throw new ServiceException(ExceptionCons.NOT_FOUNT_INSTANCE); + } + Long instanceId = flowInstance.getId(); + //运行中的任务 + List list = new ArrayList<>(); + List flowTaskList = flwTaskService.selectByInstId(instanceId); + if (CollUtil.isNotEmpty(flowTaskList)) { + List flowHisTaskVos = BeanUtil.copyToList(flowTaskList, FlowHisTaskVo.class); + for (FlowHisTaskVo flowHisTaskVo : flowHisTaskVos) { + flowHisTaskVo.setFlowStatus(TaskStatusEnum.WAITING.getStatus()); + flowHisTaskVo.setUpdateTime(null); + flowHisTaskVo.setRunDuration(null); + List allUser = flwTaskService.currentTaskAllUser(flowHisTaskVo.getId()); + if (CollUtil.isNotEmpty(allUser)) { + String join = StreamUtils.join(allUser, e -> String.valueOf(e.getUserId())); + flowHisTaskVo.setApprover(join); + } + if (BusinessStatusEnum.isDraftOrCancelOrBack(flowInstance.getFlowStatus())) { + flowHisTaskVo.setApprover(LoginHelper.getUserIdStr()); + flowHisTaskVo.setApproveName(LoginHelper.getLoginUser().getNickname()); + } + } + list.addAll(flowHisTaskVos); + } + //历史任务 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(FlowHisTask::getInstanceId, instanceId); + wrapper.eq(FlowHisTask::getNodeType, NodeType.BETWEEN.getKey()); + wrapper.orderByDesc(FlowHisTask::getCreateTime).orderByDesc(FlowHisTask::getUpdateTime); + List flowHisTasks = flowHisTaskMapper.selectList(wrapper); + if (CollUtil.isNotEmpty(flowHisTasks)) { + list.addAll(BeanUtil.copyToList(flowHisTasks, FlowHisTaskVo.class)); + } + String flowChart = chartService.chartIns(instanceId); + return Map.of("list", list, "image", flowChart); + } + + /** + * 按照实例id更新状态 + * + * @param instanceId 实例id + * @param status 状态 + */ + @Override + public void updateStatus(Long instanceId, String status) { + LambdaUpdateWrapper wrapper = new LambdaUpdateWrapper<>(); + wrapper.set(FlowInstance::getFlowStatus, status); + wrapper.eq(FlowInstance::getId, instanceId); + flowInstanceMapper.update(wrapper); + } + + /** + * 获取流程变量 + * + * @param instanceId 实例id + */ + @Override + public Map instanceVariable(Long instanceId) { + Map map = new HashMap<>(); + FlowInstance flowInstance = flowInstanceMapper.selectById(instanceId); + Map variableMap = flowInstance.getVariableMap(); + List list = new ArrayList<>(); + if (CollUtil.isNotEmpty(variableMap)) { + for (Map.Entry entry : variableMap.entrySet()) { + FlowVariableVo flowVariableVo = new FlowVariableVo(); + flowVariableVo.setKey(entry.getKey()); + flowVariableVo.setValue(entry.getValue().toString()); + list.add(flowVariableVo); + } + } + map.put("variableList", list); + map.put("variable", flowInstance.getVariable()); + return map; + } + + /** + * 设置流程变量 + * + * @param instanceId 实例id + * @param variable 流程变量 + */ + @Override + public void setVariable(Long instanceId, Map variable) { + Instance instance = insService.getById(instanceId); + if (instance != null) { + taskService.mergeVariable(instance, variable); + } + } + + /** + * 按任务id查询实例 + * + * @param taskId 任务id + */ + @Override + public FlowInstance selectByTaskId(Long taskId) { + Task task = taskService.getById(taskId); + if (task == null) { + FlowHisTask flowHisTask = flwTaskService.selectHisTaskById(taskId); + if (flowHisTask != null) { + return this.selectInstById(flowHisTask.getInstanceId()); + } + } else { + return this.selectInstById(task.getInstanceId()); + } + return null; + } + + /** + * 按任务id查询实例 + * + * @param taskIdList 任务id + */ + @Override + public List selectByTaskIdList(List taskIdList) { + if (CollUtil.isEmpty(taskIdList)) { + return Collections.emptyList(); + } + Set instanceIds = new HashSet<>(); + List flowTaskList = flwTaskService.selectByIdList(taskIdList); + for (FlowTask flowTask : flowTaskList) { + instanceIds.add(flowTask.getInstanceId()); + } + List flowHisTaskList = flwTaskService.selectHisTaskByIdList(taskIdList); + for (FlowHisTask flowHisTask : flowHisTaskList) { + instanceIds.add(flowHisTask.getInstanceId()); + } + if (!instanceIds.isEmpty()) { + return this.selectInstListByIdList(new ArrayList<>(instanceIds)); + } + return Collections.emptyList(); + } + + /** + * 作废流程 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean processInvalid(FlowInvalidBo bo) { + try { + Instance instance = insService.getById(bo.getId()); + if (instance != null) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + List flowTaskList = flwTaskService.selectByInstId(bo.getId()); + for (FlowTask flowTask : flowTaskList) { + FlowParams flowParams = new FlowParams(); + flowParams.message(bo.getComment()); + flowParams.flowStatus(BusinessStatusEnum.INVALID.getStatus()) + .hisStatus(TaskStatusEnum.INVALID.getStatus()); + flowParams.ignore(true); + taskService.termination(flowTask.getId(), flowParams); + } + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java new file mode 100644 index 0000000..21a54d7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java @@ -0,0 +1,687 @@ +package org.dromara.workflow.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.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator; +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.dto.StartProcessReturnDTO; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.enums.BusinessStatusEnum; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.service.UserService; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +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.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.*; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.service.*; +import org.dromara.warm.flow.orm.entity.*; +import org.dromara.warm.flow.orm.mapper.FlowHisTaskMapper; +import org.dromara.warm.flow.orm.mapper.FlowInstanceMapper; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.common.enums.TaskAssigneeType; +import org.dromara.workflow.common.enums.TaskStatusEnum; +import org.dromara.workflow.domain.bo.*; +import org.dromara.workflow.domain.vo.FlowHisTaskVo; +import org.dromara.workflow.domain.vo.FlowTaskVo; +import org.dromara.workflow.handler.FlowProcessEventHandler; +import org.dromara.workflow.handler.WorkflowPermissionHandler; +import org.dromara.workflow.mapper.FlwCategoryMapper; +import org.dromara.workflow.mapper.FlwTaskMapper; +import org.dromara.workflow.service.IFlwTaskService; +import org.dromara.workflow.utils.WorkflowUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +import static org.dromara.workflow.common.constant.FlowConstant.*; + +/** + * 任务 服务层实现 + * + * @author may + */ +@ConditionalOnEnable +@Slf4j +@RequiredArgsConstructor +@Service +public class FlwTaskServiceImpl implements IFlwTaskService { + + private final TaskService taskService; + private final InsService insService; + private final DefService defService; + private final HisTaskService hisTaskService; + private final NodeService nodeService; + private final FlowInstanceMapper flowInstanceMapper; + private final FlowTaskMapper flowTaskMapper; + private final FlowHisTaskMapper flowHisTaskMapper; + private final IdentifierGenerator identifierGenerator; + private final FlowProcessEventHandler flowProcessEventHandler; + private final UserService userService; + private final FlwTaskMapper flwTaskMapper; + private final FlwCategoryMapper flwCategoryMapper; + + /** + * 启动任务 + * + * @param startProcessBo 启动流程参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public StartProcessReturnDTO startWorkFlow(StartProcessBo startProcessBo) { + String businessId = startProcessBo.getBusinessId(); + if (StringUtils.isBlank(businessId)) { + throw new ServiceException("启动工作流时必须包含业务ID"); + } + // 启动流程实例(提交申请) + Map variables = startProcessBo.getVariables(); + // 流程发起人 + variables.put(INITIATOR, LoginHelper.getUserIdStr()); + // 业务id + variables.put(BUSINESS_ID, businessId); + FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class) + .eq(FlowInstance::getBusinessId, businessId)); + if (ObjectUtil.isNotNull(flowInstance)) { + BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus()); + List taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId())); + StartProcessReturnDTO dto = new StartProcessReturnDTO(); + dto.setProcessInstanceId(taskList.get(0).getInstanceId()); + dto.setTaskId(taskList.get(0).getId()); + return dto; + } + FlowParams flowParams = new FlowParams(); + flowParams.flowCode(startProcessBo.getFlowCode()); + flowParams.variable(startProcessBo.getVariables()); + flowParams.flowStatus(BusinessStatusEnum.DRAFT.getStatus()); + Instance instance; + try { + instance = insService.start(businessId, flowParams); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + // 申请人执行流程 + List taskList = taskService.list(new FlowTask().setInstanceId(instance.getId())); + if (taskList.size() > 1) { + throw new ServiceException("请检查流程第一个环节是否为申请人!"); + } + StartProcessReturnDTO dto = new StartProcessReturnDTO(); + dto.setProcessInstanceId(instance.getId()); + dto.setTaskId(taskList.get(0).getId()); + return dto; + } + + /** + * 办理任务 + * + * @param completeTaskBo 办理任务参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean completeTask(CompleteTaskBo completeTaskBo) { + try { + // 获取任务ID并查询对应的流程任务和实例信息 + Long taskId = completeTaskBo.getTaskId(); + List messageType = completeTaskBo.getMessageType(); + String notice = completeTaskBo.getNotice(); + // 获取抄送人 + List flowCopyList = completeTaskBo.getFlowCopyList(); + FlowTask flowTask = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(flowTask)) { + throw new ServiceException("流程任务不存在或任务已审批!"); + } + Instance ins = insService.getById(flowTask.getInstanceId()); + // 获取流程定义信息 + Definition definition = defService.getById(flowTask.getDefinitionId()); + // 检查流程状态是否为草稿、已撤销或已退回状态,若是则执行流程提交监听 + if (BusinessStatusEnum.isDraftOrCancelOrBack(ins.getFlowStatus())) { + flowProcessEventHandler.processHandler(definition.getFlowCode(), ins.getBusinessId(), ins.getFlowStatus(), null, true); + } + // 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息 + FlowParams flowParams = new FlowParams(); + flowParams.variable(completeTaskBo.getVariables()); + flowParams.skipType(SkipType.PASS.getKey()); + flowParams.message(completeTaskBo.getMessage()); + flowParams.flowStatus(BusinessStatusEnum.WAITING.getStatus()).hisStatus(TaskStatusEnum.PASS.getStatus()); + + flowParams.hisTaskExt(completeTaskBo.getFileId()); + // 执行任务跳转,并根据返回的处理人设置下一步处理人 + Instance instance = taskService.skip(taskId, flowParams); + this.setHandler(instance, flowTask, flowCopyList); + // 消息通知 + WorkflowUtils.sendMessage(definition.getFlowName(), ins.getId(), messageType, notice); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 设置办理人 + * + * @param instance 实例 + * @param task (当前任务)未办理的任务 + * @param flowCopyList 抄送人 + */ + private void setHandler(Instance instance, FlowTask task, List flowCopyList) { + if (ObjectUtil.isNull(instance)) { + return; + } + // 添加抄送人 + this.setCopy(task, flowCopyList); + // 根据流程实例ID查询所有关联的任务 + List flowTasks = this.selectByInstId(instance.getId()); + if (CollUtil.isEmpty(flowTasks)) { + return; + } + List taskIdList = StreamUtils.toList(flowTasks, FlowTask::getId); + // 获取与当前任务关联的用户列表 + List associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList); + if (CollUtil.isEmpty(associatedUsers)) { + return; + } + List userList = new ArrayList<>(); + // 遍历任务列表,处理每个任务的办理人 + for (FlowTask flowTask : flowTasks) { + List users = StreamUtils.filter(associatedUsers, user -> Objects.equals(user.getAssociated(), flowTask.getId())); + if (CollUtil.isNotEmpty(users)) { + userList.addAll(WorkflowUtils.buildUser(users, flowTask.getId())); + } + } + // 批量删除现有任务的办理人记录 + WorkflowUtils.getFlowUserService().deleteByTaskIds(taskIdList); + // 确保要保存的 userList 不为空 + if (CollUtil.isEmpty(userList)) { + return; + } + WorkflowUtils.getFlowUserService().saveBatch(userList); + } + + /** + * 添加抄送人 + * + * @param task 任务信息 + * @param flowCopyList 抄送人 + */ + public void setCopy(FlowTask task, List flowCopyList) { + if (CollUtil.isEmpty(flowCopyList)) { + return; + } + // 添加抄送人记录 + FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0); + FlowNode flowNode = new FlowNode(); + flowNode.setNodeCode(flowHisTask.getTargetNodeCode()); + flowNode.setNodeName(flowHisTask.getTargetNodeName()); + //生成新的任务id + long taskId = identifierGenerator.nextId(null).longValue(); + task.setId(taskId); + task.setNodeName("【抄送】" + task.getNodeName()); + Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000); + FlowParams flowParams = FlowParams.build(); + flowParams.skipType(SkipType.NONE.getKey()); + flowParams.hisStatus(TaskStatusEnum.COPY.getStatus()); + flowParams.message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName)); + HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams); + hisTask.setCreateTime(updateTime); + hisTask.setUpdateTime(updateTime); + hisTaskService.save(hisTask); + List userList = flowCopyList.stream() + .map(flowCopy -> { + FlowUser flowUser = new FlowUser(); + flowUser.setType(TaskAssigneeType.COPY.getCode()); + flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId())); + flowUser.setAssociated(taskId); + return flowUser; + }).collect(Collectors.toList()); + // 批量保存抄送人员 + WorkflowUtils.getFlowUserService().saveBatch(userList); + } + + /** + * 查询当前用户的待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + queryWrapper.in("t.processed_by", SpringUtils.getBean(WorkflowPermissionHandler.class).permissions()); + queryWrapper.in("t.flow_status", BusinessStatusEnum.WAITING.getStatus()); + Page page = this.getFlowTaskVoPage(pageQuery, queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 查询当前用户的已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + queryWrapper.in("t.approver", LoginHelper.getUserIdStr()); + queryWrapper.orderByDesc("t.create_time").orderByDesc("t.update_time"); + Page page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 查询待办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByAllTaskWait(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.eq("t.node_type", NodeType.BETWEEN.getKey()); + Page page = getFlowTaskVoPage(pageQuery, queryWrapper); + return TableDataInfo.build(page); + } + + private Page getFlowTaskVoPage(PageQuery pageQuery, QueryWrapper queryWrapper) { + Page page = flwTaskMapper.getListRunTask(pageQuery.build(), queryWrapper); + List records = page.getRecords(); + if (CollUtil.isNotEmpty(records)) { + List taskIds = StreamUtils.toList(records, FlowTaskVo::getId); + Map> listMap = currentTaskAllUser(taskIds); + records.forEach(t -> { + List userList = listMap.getOrDefault(t.getId(), Collections.emptyList()); + if (CollUtil.isNotEmpty(userList)) { + t.setAssigneeIds(StreamUtils.join(userList, e -> String.valueOf(e.getUserId()))); + t.setAssigneeNames(StreamUtils.join(userList, UserDTO::getNickName)); + } + }); + } + return page; + } + + /** + * 查询已办任务 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByAllTaskFinish(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + Page page = flwTaskMapper.getListFinishTask(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + /** + * 查询当前用户的抄送 + * + * @param flowTaskBo 参数 + * @param pageQuery 分页 + */ + @Override + public TableDataInfo pageByTaskCopy(FlowTaskBo flowTaskBo, PageQuery pageQuery) { + QueryWrapper queryWrapper = buildQueryWrapper(flowTaskBo); + queryWrapper.in("t.processed_by", LoginHelper.getUserIdStr()); + Page page = flwTaskMapper.getTaskCopyByPage(pageQuery.build(), queryWrapper); + return TableDataInfo.build(page); + } + + private QueryWrapper buildQueryWrapper(FlowTaskBo flowTaskBo) { + QueryWrapper wrapper = Wrappers.query(); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getNodeName()), "t.node_name", flowTaskBo.getNodeName()); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowName()), "t.flow_name", flowTaskBo.getFlowName()); + wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode()); + wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds()); + if (StringUtils.isNotBlank(flowTaskBo.getCategory())) { + List categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory())); + wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr)); + } + wrapper.orderByDesc("t.create_time"); + return wrapper; + } + + /** + * 驳回任务 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean backProcess(BackProcessBo bo) { + try { + Long taskId = bo.getTaskId(); + String notice = bo.getNotice(); + List messageType = bo.getMessageType(); + String message = bo.getMessage(); + FlowTask task = flowTaskMapper.selectById(taskId); + if (ObjectUtil.isNull(task)) { + throw new ServiceException("任务不存在!"); + } + Instance inst = insService.getById(task.getInstanceId()); + BusinessStatusEnum.checkBackStatus(inst.getFlowStatus()); + Long definitionId = task.getDefinitionId(); + Definition definition = defService.getById(definitionId); + String applyNodeCode = WorkflowUtils.applyNodeCode(definitionId); + FlowParams flowParams = FlowParams.build(); + flowParams.nodeCode(bo.getNodeCode()); + flowParams.message(message); + flowParams.skipType(SkipType.REJECT.getKey()); + flowParams.flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus()) + .hisStatus(TaskStatusEnum.BACK.getStatus()); + flowParams.hisTaskExt(bo.getFileId()); + taskService.skip(task.getId(), flowParams); + + Instance instance = insService.getById(inst.getId()); + this.setHandler(instance, task, null); + // 消息通知 + WorkflowUtils.sendMessage(definition.getFlowName(), instance.getId(), messageType, notice); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 获取可驳回的前置节点 + * + * @param definitionId 流程定义id + * @param nowNodeCode 当前节点 + */ + @Override + public List getBackTaskNode(Long definitionId, String nowNodeCode) { + List nodeCodes = nodeService.getByNodeCodes(Collections.singletonList(nowNodeCode), definitionId); + if (!CollUtil.isNotEmpty(nodeCodes)) { + return nodeCodes; + } + //判断是否配置了固定驳回节点 + Node node = nodeCodes.get(0); + if (StringUtils.isNotBlank(node.getAnyNodeSkip())) { + return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId); + } + //获取可驳回的前置节点 + List nodes = nodeService.previousNodeList(definitionId, nowNodeCode); + if (CollUtil.isNotEmpty(nodes)) { + return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType())); + } + return nodes; + } + + /** + * 终止任务 + * + * @param bo 参数 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean terminationTask(FlowTerminationBo bo) { + try { + Long taskId = bo.getTaskId(); + Task task = taskService.getById(taskId); + if (task == null) { + throw new ServiceException("任务不存在!"); + } + Instance instance = insService.getById(task.getInstanceId()); + if (ObjectUtil.isNotNull(instance)) { + BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus()); + } + FlowParams flowParams = new FlowParams(); + flowParams.message(bo.getComment()); + flowParams.flowStatus(BusinessStatusEnum.TERMINATION.getStatus()) + .hisStatus(TaskStatusEnum.TERMINATION.getStatus()); + taskService.termination(taskId, flowParams); + return true; + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + */ + @Override + public List selectByIdList(List taskIdList) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .in(FlowTask::getId, taskIdList)); + } + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + */ + @Override + public FlowTaskVo selectById(Long taskId) { + Task task = taskService.getById(taskId); + if (ObjectUtil.isNull(task)) { + return null; + } + FlowTaskVo flowTaskVo = BeanUtil.toBean(task, FlowTaskVo.class); + Instance instance = insService.getById(task.getInstanceId()); + Definition definition = defService.getById(task.getDefinitionId()); + flowTaskVo.setFlowStatus(instance.getFlowStatus()); + flowTaskVo.setVersion(definition.getVersion()); + flowTaskVo.setFlowCode(definition.getFlowCode()); + flowTaskVo.setFlowName(definition.getFlowName()); + flowTaskVo.setBusinessId(instance.getBusinessId()); + List nodeList = nodeService.getByNodeCodes(Collections.singletonList(flowTaskVo.getNodeCode()), instance.getDefinitionId()); + if (CollUtil.isNotEmpty(nodeList)) { + Node node = nodeList.get(0); + flowTaskVo.setNodeRatio(node.getNodeRatio()); + } + return flowTaskVo; + } + + /** + * 按照任务id查询任务 + * + * @param taskIdList 任务id + * @return 结果 + */ + @Override + public List selectHisTaskByIdList(List taskIdList) { + return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class) + .in(FlowHisTask::getId, taskIdList)); + } + + /** + * 按照任务id查询任务 + * + * @param taskId 任务id + * @return 结果 + */ + @Override + public FlowHisTask selectHisTaskById(Long taskId) { + return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class) + .eq(FlowHisTask::getId, taskId)); + } + + /** + * 按照实例id查询任务 + * + * @param instanceIdList 流程实例id + */ + @Override + public List selectByInstIdList(List instanceIdList) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .in(FlowTask::getInstanceId, instanceIdList)); + } + + /** + * 按照实例id查询任务 + * + * @param instanceId 流程实例id + */ + @Override + public List selectByInstId(Long instanceId) { + return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class) + .eq(FlowTask::getInstanceId, instanceId)); + } + + /** + * 任务操作 + * + * @param bo 参数 + * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean taskOperation(TaskOperationBo bo, String taskOperation) { + FlowParams flowParams = new FlowParams(); + flowParams.message(bo.getMessage()); + if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) { + flowParams.ignore(true); + } + + // 根据操作类型构建 FlowParams + switch (taskOperation) { + case DELEGATE_TASK, TRANSFER_TASK -> { + ValidatorUtils.validate(bo, AddGroup.class); + flowParams.addHandlers(Collections.singletonList(bo.getUserId())); + } + case ADD_SIGNATURE -> { + ValidatorUtils.validate(bo, EditGroup.class); + flowParams.addHandlers(bo.getUserIds()); + } + case REDUCTION_SIGNATURE -> { + ValidatorUtils.validate(bo, EditGroup.class); + flowParams.reductionHandlers(bo.getUserIds()); + } + default -> { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + } + + Long taskId = bo.getTaskId(); + FlowTaskVo flowTaskVo = selectById(taskId); + if ("addSignature".equals(taskOperation) || "reductionSignature".equals(taskOperation)) { + if (flowTaskVo.getNodeRatio().compareTo(BigDecimal.ZERO) == 0) { + throw new ServiceException(flowTaskVo.getNodeName() + "不是会签节点!"); + } + } + // 设置任务状态并执行对应的任务操作 + switch (taskOperation) { + //委派任务 + case DELEGATE_TASK -> { + flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus()); + return taskService.depute(taskId, flowParams); + } + //转办任务 + case TRANSFER_TASK -> { + flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus()); + return taskService.transfer(taskId, flowParams); + } + //加签,增加办理人 + case ADD_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus()); + return taskService.addSignature(taskId, flowParams); + } + //减签,减少办理人 + case REDUCTION_SIGNATURE -> { + flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus()); + return taskService.reductionSignature(taskId, flowParams); + } + default -> { + log.error("Invalid operation type:{} ", taskOperation); + throw new ServiceException("Invalid operation type " + taskOperation); + } + } + } + + /** + * 修改任务办理人(此方法将会批量修改所有任务的办理人) + * + * @param taskIdList 任务id + * @param userId 用户id + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean updateAssignee(List taskIdList, String userId) { + if (CollUtil.isEmpty(taskIdList)) { + return false; + } + try { + List flowTasks = this.selectByIdList(taskIdList); + // 批量删除现有任务的办理人记录 + if (CollUtil.isNotEmpty(flowTasks)) { + WorkflowUtils.getFlowUserService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId)); + List userList = flowTasks.stream() + .map(flowTask -> { + FlowUser flowUser = new FlowUser(); + flowUser.setType(TaskAssigneeType.APPROVER.getCode()); + flowUser.setProcessedBy(userId); + flowUser.setAssociated(flowTask.getId()); + return flowUser; + }) + .collect(Collectors.toList()); + if (CollUtil.isNotEmpty(userList)) { + WorkflowUtils.getFlowUserService().saveBatch(userList); + } + } + } catch (Exception e) { + log.error(e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } + return true; + } + + /** + * 获取任务所有办理人 + * + * @param taskIdList 任务id + */ + @Override + public Map> currentTaskAllUser(List taskIdList) { + Map> map = new HashMap<>(); + // 获取与当前任务关联的用户列表 + List associatedUsers = WorkflowUtils.getFlowUserService().getByAssociateds(taskIdList); + Map> listMap = StreamUtils.groupByKey(associatedUsers, User::getAssociated); + for (Map.Entry> entry : listMap.entrySet()) { + List value = entry.getValue(); + if (CollUtil.isNotEmpty(value)) { + List userDTOS = userService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy()))); + map.put(entry.getKey(), userDTOS); + } + } + return map; + } + + /** + * 获取当前任务的所有办理人 + * + * @param taskId 任务id + */ + @Override + public List currentTaskAllUser(Long taskId) { + // 获取与当前任务关联的用户列表 + List userList = WorkflowUtils.getFlowUserService().getByAssociateds(Collections.singletonList(taskId)); + if (CollUtil.isEmpty(userList)) { + return Collections.emptyList(); + } + return userService.selectListByIds(StreamUtils.toList(userList, e -> Long.valueOf(e.getProcessedBy()))); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java new file mode 100644 index 0000000..f8a20b5 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java @@ -0,0 +1,132 @@ +package org.dromara.workflow.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +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 org.dromara.common.core.service.WorkflowService; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.warm.flow.orm.entity.FlowInstance; +import org.dromara.workflow.common.ConditionalOnEnable; +import org.dromara.workflow.domain.bo.CompleteTaskBo; +import org.dromara.workflow.domain.bo.StartProcessBo; +import org.dromara.workflow.service.IFlwDefinitionService; +import org.dromara.workflow.service.IFlwInstanceService; +import org.dromara.workflow.service.IFlwTaskService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +/** + * 通用 工作流服务实现 + * + * @author may + */ +@ConditionalOnEnable +@RequiredArgsConstructor +@Service +public class WorkflowServiceImpl implements WorkflowService { + + private final IFlwInstanceService flwInstanceService; + private final IFlwDefinitionService flwDefinitionService; + private final IFlwTaskService flwTaskService; + + /** + * 删除流程实例 + * + * @param businessIds 业务id + * @return 结果 + */ + @Override + public boolean deleteInstance(List businessIds) { + return flwInstanceService.deleteByBusinessIds(businessIds); + } + + /** + * 获取当前流程状态 + * + * @param taskId 任务id + */ + @Override + public String getBusinessStatusByTaskId(Long taskId) { + FlowInstance flowInstance = flwInstanceService.selectByTaskId(taskId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY; + } + + /** + * 获取当前流程状态 + * + * @param businessId 业务id + */ + @Override + public String getBusinessStatus(String businessId) { + FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getFlowStatus() : StringUtils.EMPTY; + } + + /** + * 设置流程变量 + * + * @param instanceId 流程实例id + * @param variables 流程变量 + */ + @Override + public void setVariable(Long instanceId, Map variables) { + flwInstanceService.setVariable(instanceId, variables); + } + + /** + * 获取流程变量 + * + * @param instanceId 流程实例id + */ + @Override + public Map instanceVariable(Long instanceId) { + return flwInstanceService.instanceVariable(instanceId); + } + + /** + * 按照业务id查询流程实例id + * + * @param businessId 业务id + * @return 结果 + */ + @Override + public Long getInstanceIdByBusinessId(String businessId) { + FlowInstance flowInstance = flwInstanceService.selectInstByBusinessId(businessId); + return ObjectUtil.isNotNull(flowInstance) ? flowInstance.getId() : null; + } + + /** + * 新增租户流程定义 + * + * @param tenantId 租户id + */ + @Override + public void syncDef(String tenantId) { + flwDefinitionService.syncDef(tenantId); + } + + /** + * 启动流程 + * + * @param startProcess 参数 + */ + @Override + public StartProcessReturnDTO startWorkFlow(StartProcessDTO startProcess) { + return flwTaskService.startWorkFlow(BeanUtil.toBean(startProcess, StartProcessBo.class)); + } + + /** + * 办理任务 + * + * @param completeTask 参数 + */ + @Override + public boolean completeTask(CompleteTaskDTO completeTask) { + return flwTaskService.completeTask(BeanUtil.toBean(completeTask, CompleteTaskBo.class)); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java new file mode 100644 index 0000000..e48ffc8 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/utils/WorkflowUtils.java @@ -0,0 +1,206 @@ +package org.dromara.workflow.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.dromara.common.core.domain.dto.UserDTO; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mail.utils.MailUtils; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.warm.flow.core.constant.ExceptionCons; +import org.dromara.warm.flow.core.dto.FlowParams; +import org.dromara.warm.flow.core.entity.Node; +import org.dromara.warm.flow.core.entity.Task; +import org.dromara.warm.flow.core.entity.User; +import org.dromara.warm.flow.core.enums.NodeType; +import org.dromara.warm.flow.core.enums.SkipType; +import org.dromara.warm.flow.core.service.NodeService; +import org.dromara.warm.flow.core.service.TaskService; +import org.dromara.warm.flow.core.service.UserService; +import org.dromara.warm.flow.core.utils.AssertUtil; +import org.dromara.warm.flow.orm.entity.FlowNode; +import org.dromara.warm.flow.orm.entity.FlowTask; +import org.dromara.warm.flow.orm.entity.FlowUser; +import org.dromara.warm.flow.orm.mapper.FlowNodeMapper; +import org.dromara.warm.flow.orm.mapper.FlowTaskMapper; +import org.dromara.workflow.common.enums.MessageTypeEnum; +import org.dromara.workflow.service.IFlwTaskAssigneeService; +import org.dromara.workflow.service.IFlwTaskService; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + + +/** + * 工作流工具 + * + * @author may + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class WorkflowUtils { + + private static final IFlwTaskAssigneeService TASK_ASSIGNEE_SERVICE = SpringUtils.getBean(IFlwTaskAssigneeService.class); + private static final IFlwTaskService FLW_TASK_SERVICE = SpringUtils.getBean(IFlwTaskService.class); + private static final FlowNodeMapper FLOW_NODE_MAPPER = SpringUtils.getBean(FlowNodeMapper.class); + private static final FlowTaskMapper FLOW_TASK_MAPPER = SpringUtils.getBean(FlowTaskMapper.class); + private static final UserService USER_SERVICE = SpringUtils.getBean(UserService.class); + private static final TaskService TASK_SERVICE = SpringUtils.getBean(TaskService.class); + private static final NodeService NODE_SERVICE = SpringUtils.getBean(NodeService.class); + + /** + * 获取工作流用户service + */ + public static UserService getFlowUserService() { + return USER_SERVICE; + } + + /** + * 构建工作流用户 + * + * @param userList 办理用户 + * @param taskId 任务ID + * @return 用户 + */ + public static Set buildUser(List userList, Long taskId) { + if (CollUtil.isEmpty(userList)) { + return Set.of(); + } + Set list = new HashSet<>(); + Set processedBySet = new HashSet<>(); + for (User user : userList) { + // 根据 processedBy 前缀判断处理人类型,分别获取用户列表 + List users = TASK_ASSIGNEE_SERVICE.fetchUsersByStorageId(user.getProcessedBy()); + // 转换为 FlowUser 并添加到结果集合 + if (CollUtil.isNotEmpty(users)) { + users.forEach(dto -> { + String processedBy = String.valueOf(dto.getUserId()); + if (!processedBySet.contains(processedBy)) { + FlowUser flowUser = new FlowUser(); + flowUser.setType(user.getType()); + flowUser.setProcessedBy(processedBy); + flowUser.setAssociated(taskId); + list.add(flowUser); + processedBySet.add(processedBy); + } + }); + } + } + return list; + } + + /** + * 发送消息 + * + * @param flowName 流程定义名称 + * @param messageType 消息类型 + * @param message 消息内容,为空则发送默认配置的消息内容 + */ + public static void sendMessage(String flowName, Long instId, List messageType, String message) { + List userList = new ArrayList<>(); + List list = FLW_TASK_SERVICE.selectByInstId(instId); + if (StringUtils.isBlank(message)) { + message = "有新的【" + flowName + "】单据已经提交至您,请您及时处理。"; + } + for (Task task : list) { + List users = FLW_TASK_SERVICE.currentTaskAllUser(task.getId()); + if (CollUtil.isNotEmpty(users)) { + userList.addAll(users); + } + } + if (CollUtil.isNotEmpty(userList)) { + for (String code : messageType) { + MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code); + if (ObjectUtil.isNotEmpty(messageTypeEnum)) { + switch (messageTypeEnum) { + case SYSTEM_MESSAGE: + SseMessageDto dto = new SseMessageDto(); + dto.setUserIds(StreamUtils.toList(userList, UserDTO::getUserId).stream().distinct().collect(Collectors.toList())); + dto.setMessage(message); + SseMessageUtils.publishMessage(dto); + break; + case EMAIL_MESSAGE: + MailUtils.sendText(StreamUtils.join(userList, UserDTO::getEmail), "单据审批提醒", message); + break; + case SMS_MESSAGE: + //todo 短信发送 + break; + default: + throw new IllegalStateException("Unexpected value: " + messageTypeEnum); + } + } + } + } + } + + /** + * 驳回 + * + * @param message 审批意见 + * @param instanceId 流程实例id + * @param targetNodeCode 目标节点 + * @param flowStatus 流程状态 + * @param flowHisStatus 节点操作状态 + */ + public static void backTask(String message, Long instanceId, String targetNodeCode, String flowStatus, String flowHisStatus) { + List list = FLW_TASK_SERVICE.selectByInstId(instanceId); + if (CollUtil.isNotEmpty(list)) { + List tasks = StreamUtils.filter(list, e -> e.getNodeCode().equals(targetNodeCode)); + if (list.size() == tasks.size()) { + return; + } + } + for (FlowTask task : list) { + List userList = FLW_TASK_SERVICE.currentTaskAllUser(task.getId()); + FlowParams flowParams = FlowParams.build(); + flowParams.nodeCode(targetNodeCode); + flowParams.message(message); + flowParams.skipType(SkipType.PASS.getKey()); + flowParams.flowStatus(flowStatus).hisStatus(flowHisStatus); + flowParams.ignore(true); + //解决会签没权限问题 + if (CollUtil.isNotEmpty(userList)) { + flowParams.handler(userList.get(0).getUserId().toString()); + } + TASK_SERVICE.skip(task.getId(), flowParams); + } + //解决会签多人审批问题 + backTask(message, instanceId, targetNodeCode, flowStatus, flowHisStatus); + } + + /** + * 申请人节点编码 + * + * @param definitionId 流程定义id + * @return 申请人节点编码 + */ + public static String applyNodeCode(Long definitionId) { + //获取已发布的流程节点 + List flowNodes = FLOW_NODE_MAPPER.selectList(new LambdaQueryWrapper().eq(FlowNode::getDefinitionId, definitionId)); + AssertUtil.isTrue(CollUtil.isEmpty(flowNodes), ExceptionCons.NOT_PUBLISH_NODE); + Node startNode = flowNodes.stream().filter(t -> NodeType.isStart(t.getNodeType())).findFirst().orElse(null); + AssertUtil.isNull(startNode, ExceptionCons.LOST_START_NODE); + Node nextNode = NODE_SERVICE.getNextNode(definitionId, startNode.getNodeCode(), null, SkipType.PASS.getKey()); + return nextNode.getNodeCode(); + } + + /** + * 删除运行中的任务 + * + * @param taskIds 任务id + */ + public static void deleteRunTask(List taskIds) { + if (CollUtil.isEmpty(taskIds)) { + return; + } + USER_SERVICE.deleteByTaskIds(taskIds); + FLOW_TASK_MAPPER.deleteByIds(taskIds); + } +} diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/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-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml new file mode 100644 index 0000000..e9918f1 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml new file mode 100644 index 0000000..30e2267 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml new file mode 100644 index 0000000..73e4ec7 --- /dev/null +++ b/ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/pom.xml b/ruoyi-modules/ruoyi-zhishu/pom.xml new file mode 100644 index 0000000..3ed2745 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/pom.xml @@ -0,0 +1,407 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + + ruoyi-zhishu + + + 业务模块 + + + + + + + org.dromara + ruoyi-common-core + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-sms + + + + org.dromara + ruoyi-common-mail + + + + org.dromara + ruoyi-common-redis + + + + org.dromara + ruoyi-common-idempotent + + + + org.dromara + ruoyi-common-mybatis + + + + + org.dromara + ruoyi-common-excel + + + + org.dromara + ruoyi-common-security + + + + org.dromara + ruoyi-common-web + + + + org.dromara + ruoyi-common-ratelimiter + + + + org.dromara + ruoyi-common-translation + + + + org.dromara + ruoyi-common-sensitive + + + + org.dromara + ruoyi-common-encrypt + + + + org.dromara + ruoyi-common-tenant + + + org.dromara + ruoyi-common-websocket + + + commons-logging + commons-logging + 1.2 + + + + com.google.code.gson + gson + 2.8.5 + + + + + + + + + + + com.pdd + com.pdd + 1.92.52 + + + com.aizuda + snail-job-common-log + 1.3.0 + compile + + + com.aizuda + snail-job-common-log + 1.3.0 + compile + + + + org.dromara + ruoyi-common-sse + + + org.jsoup + jsoup + 1.17.2 + + + + + org.apache.httpcomponents + httpclient + 4.5.14 + + + com.squareup.okhttp3 + okhttp + 4.9.3 + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.projectlombok + lombok + true + + + + + com.fasterxml.jackson.core + jackson-databind + + + + + commons-codec + commons-codec + 1.15 + + + + + org.springframework.boot + spring-boot-starter-test + test + + + cn.com.kingbase + kingbase8 + 8.6.0 + compile + + + org.anyline + anyline-data + 8.7.2-20250101 + compile + + + org.springframework.data + spring-data-jpa + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.apache.poi + poi-ooxml + 5.2.3 + + + org.apache.poi + poi-ooxml-schemas + 4.1.2 + + + org.apache.xmlbeans + xmlbeans + 5.1.1 + + + org.apache.commons + commons-collections4 + 4.4 + + + com.alibaba + fastjson + + + cn.com.kingbase + kingbase8 + 8.6.0 + compile + + + org.anyline + anyline-data + 8.7.2-20250101 + compile + + + org.springframework.data + spring-data-jpa + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.dromara + ruoyi-common-oss + + + org.scala-lang + scala-library + 2.13.9 + compile + + + org.dromara + ruoyi-common-core + + + org.dromara + ruoyi-common-log + + + org.dromara + ruoyi-system + + + org.checkerframework + checker-qual + 3.48.3 + compile + + + + com.github.wechatpay-apiv3 + wechatpay-java + 0.2.17 + + + + com.google.zxing + core + 3.4.1 + + + com.google.zxing + javase + 3.4.1 + + + + + + + + com.dtflys.forest + forest-spring-boot3-starter + 1.6.4 + + + + javax.annotation + javax.annotation-api + 1.3.2 + + + + com.tencentcloudapi + tencentcloud-sdk-java-ocr + 3.1.1252 + + + + com.hankcs + hanlp + portable-1.8.6 + + + + org.apache.pdfbox + pdfbox + 2.0.27 + + + + com.aliyun.oss + aliyun-sdk-oss + 3.17.4 + + + javax.xml.bind + jaxb-api + 2.3.1 + + + javax.activation + activation + 1.1.1 + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.3 + + + + com.github.wechatpay-apiv3 + wechatpay-apache-httpclient + 0.4.7 + + + + + org.bouncycastle + bcprov-jdk15to18 + 1.71 + + + + + org.apache.poi + poi-scratchpad + 5.2.3 + + + + com.opencsv + opencsv + 5.7.1 + + + + + net.java.dev.jna + jna + 5.13.0 + + + net.java.dev.jna + jna-platform + 5.13.0 + + + + org.springframework.boot + spring-boot-starter-websocket + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/CenterAspect.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/CenterAspect.java new file mode 100644 index 0000000..8fa4419 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/CenterAspect.java @@ -0,0 +1,90 @@ +package org.dromara.zhishu.aspect; + +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.vo.ProductForm; +import org.dromara.zhishu.service.IRunningLogFileService; +import org.dromara.zhishu.util.MapUtils; +import org.dromara.zhishu.util.RunningLogUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 中心书库发布任务日志 + */ +@Aspect +@Component +public class CenterAspect { + + // 定义 ThreadLocal 用于存储日志上下文 ID 或操作标识 + private static final ThreadLocal LOG_CONTEXT = new InheritableThreadLocal<>(); + + @Autowired + private IRunningLogFileService runningLogFileService; + + //定义文件类型 xcx 小程序 + private final String fileType = "centerBooksAdd"; + + + /** + * 中心书库发布数据接口 + * @param jsonStr + */ + @Pointcut(value = "execution(* org.dromara.zhishu.controller.TaskController.centerBooks(String)) && args(jsonStr)", argNames = "jsonStr") + public void centerBooks(String jsonStr){} + + /** + * 子方法: 自动发布商品切点 + * @param map + */ + @Pointcut(value = "execution(* org.dromara.zhishu.service.impl.TaskServiceImpl.addGoods(java.util.Map,org.dromara.zhishu.domain.bo.TaskBo,Long)) && args(map,taskBo,userId)", argNames = "map,taskBo,userId") + public void addGoods(Map map, TaskBo taskBo, Long userId){} + + + @Around(value = "centerBooks(jsonStr)", argNames = "joinPoint,jsonStr") + public Object repeatBook(ProceedingJoinPoint joinPoint, String jsonStr) { + RunningLogUtils.init(runningLogFileService); + //接受数据 + Map dataMap = JsonUtil.transferToObj(jsonStr, HashMap.class); + //任务名称 + String fileName = dataMap.get("taskId").toString(); + /** + * 从任务名称中解析出用户id + */ + //删除文本 ”中心书库发布“ + fileName = fileName.replace("中心书库发布",""); + //根据分号分割 + String[] split = fileName.split(";"); + //遍历split在根据分割后的字符串根据下划线进行分割获取userId + for (String s : split) { + String[] split1 = s.split("_"); + if(split1[0].equals("userId")){ + //将userId的值放入dataMap里 + dataMap.put("userId", split1[1]); + break; + } + } + //写日志 + return RunningLogUtils.runningLog(joinPoint, dataMap,"中心书库发布商品",fileType); + } + + + @Around(value = "addGoods(map,taskBo,userId)", argNames = "joinPoint,map,taskBo,userId") + public Object addGoods(ProceedingJoinPoint joinPoint,Map map, TaskBo taskBo, Long userId){ + RunningLogUtils.init(runningLogFileService); + Map dataMap = new HashMap(); + dataMap.put("map", map); + dataMap.put("taskBo", taskBo); + dataMap.put("userId", userId); + //写日志 + return RunningLogUtils.runningLog(joinPoint, dataMap,"中心书库发布商品发布方法addGoods",fileType); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/GoodsAddAspect.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/GoodsAddAspect.java new file mode 100644 index 0000000..66ae5d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/GoodsAddAspect.java @@ -0,0 +1,50 @@ +package org.dromara.zhishu.aspect; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.dromara.zhishu.domain.vo.ProductForm; +import org.dromara.zhishu.service.IRunningLogFileService; +import org.dromara.zhishu.util.MapUtils; +import org.dromara.zhishu.util.RunningLogUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + + +/** + * 勾选/Excel表发布商品 + */ +@Aspect +@Component +public class GoodsAddAspect { + + // 定义 ThreadLocal 用于存储日志上下文 ID 或操作标识 + private static final ThreadLocal LOG_CONTEXT = new InheritableThreadLocal<>(); + + @Autowired + private IRunningLogFileService runningLogFileService; + + //定义文件类型 goodsAdd + private final String fileType = "goodsAdd"; + + + @Pointcut(value = "execution(* org.dromara.zhishu.service.impl.ZhishuShopGoodsServiceImpl.goodsAdd(java.util.Map)) && args(map)", argNames = "map") + public void goodsAdd(Map map){} + + + @Around(value = "goodsAdd(form)", argNames = "joinPoint,form") + public void goodsAddLog(ProceedingJoinPoint joinPoint, ProductForm form) { + String contextId = UUID.randomUUID().toString(); + LOG_CONTEXT.set(contextId); + RunningLogUtils.init(runningLogFileService); + //写日志 + RunningLogUtils.runningLog(joinPoint, MapUtils.convertToMap(form),"勾选/Excel表发布商品",fileType); + } + + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/LogRecordAspect.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/LogRecordAspect.java new file mode 100644 index 0000000..e5d0bbb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/LogRecordAspect.java @@ -0,0 +1,112 @@ +package org.dromara.zhishu.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.dromara.zhishu.annotation.LogRecord; +import org.dromara.zhishu.domain.vo.SaveGoodsVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.util.EasyExcelUtil; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +@Slf4j +@Aspect +@Component +public class LogRecordAspect { + + /** + * 环绕增强方法 + * + * @param joinPoint 连接点 + * @param logRecord 注解对象 + * @return 方法执行结果 + * @throws Throwable 异常 + */ + @Around("@annotation(logRecord)") + public Object doLogRecord(ProceedingJoinPoint joinPoint, LogRecord logRecord) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + Object[] args = joinPoint.getArgs(); + String[] paramNames = signature.getParameterNames(); + + // 提取关键参数 + Map paramMap = getMethodParams(paramNames, args); + + SaveGoodsVo saveGoodsVo = extractParam(paramMap, "saveGoodsVo", SaveGoodsVo.class); + AtomicInteger successMarkI = extractParam(paramMap, "successMarkI", AtomicInteger.class); + AtomicInteger failMarkI = extractParam(paramMap, "failMarkI", AtomicInteger.class); + ShopVo shopVo = extractParam(paramMap, "shopVo", ShopVo.class); + Integer totalNum = extractParam(paramMap, "totalNum", Integer.class); + Long time = extractParam(paramMap, "time", Long.class); + AtomicBoolean status = extractParam(paramMap, "status", AtomicBoolean.class); + + // 执行原方法 + Object result; + result = joinPoint.proceed(); + + // 记录方法调用后的信息 + if (status.get()) { + logAfter(successMarkI, saveGoodsVo, shopVo, totalNum, time); + } + + if (!status.get()) { + // 记录异常信息 + logException(failMarkI, saveGoodsVo, shopVo, totalNum); + } + + return result; + } + + /** + * 获取需要记录的方法参数 + */ + private Map getMethodParams(String[] parameterNames, Object[] args) { + Map params = new HashMap<>(); + + for (int i = 0; i < parameterNames.length; i++) { + params.put(parameterNames[i], args[i]); + } + + return params; + } + + /** + * 安全提取参数并做类型检查 + */ + @SuppressWarnings("unchecked") + private T extractParam(Map paramMap, String key, Class type) { + Object value = paramMap.get(key); + if (value != null && type.isAssignableFrom(value.getClass())) { + return (T) value; + } + throw new IllegalArgumentException("参数缺失或类型错误: " + key + ", 类型应为: " + type.getName()); + } + + /** + * 方法执行后的日志记录 + */ + private void logAfter(AtomicInteger successMarkI, SaveGoodsVo saveGoodsVo, ShopVo shopVo, Integer totalNum, long newTime) { + // 更新计数器条数 + Integer successExecutedNum = successMarkI.incrementAndGet(); + EasyExcelUtil.writeTxtMsgLog(saveGoodsVo.getTaskId(), totalNum, successExecutedNum); + EasyExcelUtil.writeTxtLog(saveGoodsVo.getTaskId(), shopVo.getId(), shopVo.getShopName(), totalNum, successExecutedNum); + EasyExcelUtil.writeDetailTxtLog(saveGoodsVo.getTaskId(), shopVo.getId(), shopVo.getShopName(), totalNum, successExecutedNum, "同步成功", "New_" + shopVo.getId() + "_" + newTime + "_0"); + } + + /** + * 异常时的日志记录 + */ + private void logException(AtomicInteger failMarkI, SaveGoodsVo saveGoodsVo, ShopVo shopVo, Integer totalNum) { + // 更新计数器条数 + Integer failExecutedNum = failMarkI.incrementAndGet(); + EasyExcelUtil.writeDetailTxtLog(saveGoodsVo.getTaskId(), shopVo.getId(), shopVo.getShopName(), totalNum, failExecutedNum, "修改货号失败", "New_" + shopVo.getId() + "_0"); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/XcxAspect.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/XcxAspect.java new file mode 100644 index 0000000..e43ddae --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/aspect/XcxAspect.java @@ -0,0 +1,103 @@ +package org.dromara.zhishu.aspect; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.vo.ProductForm; +import org.dromara.zhishu.service.IRunningLogFileService; +import org.dromara.zhishu.util.MapUtils; +import org.dromara.zhishu.util.RunningLogUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + + +/** + * 记录从小程序端入库和发布日志 + */ +@Aspect +@Component +public class XcxAspect { + + // 定义 ThreadLocal 用于存储日志上下文 ID 或操作标识 + private static final ThreadLocal LOG_CONTEXT = new InheritableThreadLocal<>(); + + @Autowired + private IRunningLogFileService runningLogFileService; + + //定义文件类型 xcx 小程序 + private final String fileType = "xcx"; + + +// /** +// * 小程序扫码提交切点 +// * @param form +// */ +// // 定义切入点:匹配AdminController中的register方法 +// @Pointcut(value = "execution(* org.dromara.zhishu.service.impl.ZhishuShopGoodsServiceImpl.submitProduct(org.dromara.zhishu.domain.vo.ProductForm)) && args(form)", argNames = "form") +// public void registerMethod(ProductForm form) {} +// /** +// * 小程序版权页提交切点 +// * @param form +// */ +// @Pointcut(value = "execution(* org.dromara.zhishu.service.impl.ZhishuShopGoodsServiceImpl.submitFromCopyrightPage(org.dromara.zhishu.domain.vo.ProductForm)) && args(form)", argNames = "form") +// public void submitFromCopyrightPage(ProductForm form) {} + /** + * 子方法: 自动发布商品切点 + * @param map + */ +// @Pointcut(value = "execution(* org.dromara.zhishu.service.impl.ZhishuShopGoodsServiceImpl.goodsAutoAdd(java.util.Map)) && args(map)", argNames = "map") +// public void registerDetailMethod(Map map){} + + +// @Around(value = "registerMethod(form)", argNames = "joinPoint,form") +// public Object validateAndLog(ProceedingJoinPoint joinPoint, ProductForm form) { +// String contextId = UUID.randomUUID().toString(); +// LOG_CONTEXT.set(contextId); +// +// RunningLogUtils.init(runningLogFileService); +// //写日志 +// RunningLogUtils.runningLog(joinPoint, MapUtils.convertToMap(form),"这里小程序扫码提交",fileType); +// +// // 继续执行原方法并返回结果 +//// try { +//// return joinPoint.proceed(); +//// } catch (Throwable throwable) { +//// throw new RuntimeException(throwable); +//// } +// } + +// @Around(value = "submitFromCopyrightPage(form)", argNames = "joinPoint,form") +// public Object submitFromCopyrightPage(ProceedingJoinPoint joinPoint, ProductForm form) { +// String contextId = UUID.randomUUID().toString(); +// LOG_CONTEXT.set(contextId); +// RunningLogUtils.init(runningLogFileService); +// //写日志 +// RunningLogUtils.runningLog(joinPoint,MapUtils.convertToMap(form),"这里小程序版权页提交",fileType); +// +// // 继续执行原方法并返回结果 +//// try { +//// return joinPoint.proceed(); +//// } catch (Throwable throwable) { +//// throw new RuntimeException(throwable); +//// } +// } + +// @Around(value = "registerDetailMethod(map)", argNames = "joinPoint,map") +// public void detailLog(ProceedingJoinPoint joinPoint,Map map){ +// String contextId = LOG_CONTEXT.get(); +// if (contextId == null) { +// contextId = "NO_PARENT"; // 表示没有外部触发源 +// } +// //写日志 +// RunningLogUtils.runningLog(joinPoint,map,"这里是商品发布main方法日志",fileType); +// } + + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/config/RestTemplateConfig.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/config/RestTemplateConfig.java new file mode 100644 index 0000000..c0306a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/config/RestTemplateConfig.java @@ -0,0 +1,17 @@ +package org.dromara.zhishu.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +/** + * RestTemplate配置类 + */ +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/config/SecondRedissonConfig.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/config/SecondRedissonConfig.java new file mode 100644 index 0000000..8290c54 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/config/SecondRedissonConfig.java @@ -0,0 +1,126 @@ +package org.dromara.zhishu.config; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.StringCodec; +import org.redisson.codec.JsonJacksonCodec; +import org.redisson.config.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +@Configuration +public class SecondRedissonConfig { + + @Bean + @Primary + public RedissonClient redissonClient() { + Config config = new Config(); + + // ✅ 优化:4核6G配置,提高线程数充分利用CPU + config.setThreads(8); // 从4改为8,充分利用4核CPU + config.setNettyThreads(16); // 从8改为16,提高网络IO处理能力 + + config.setCodec(new JsonJacksonCodec()); + + config.useSingleServer() + .setAddress("redis://146.56.227.42:6379") + .setDatabase(0) + .setPassword("Qq123123") + .setClientName("ruoyi_primary") + + // ✅ 优化:增大连接池,提高并发处理能力 + .setConnectionMinimumIdleSize(4) // 从2改为4 + .setConnectionPoolSize(16) // 从8改为16,支持更高并发 + .setIdleConnectionTimeout(30000) // 从10秒改为30秒,减少连接重建开销 + + // 保持合理的超时时间 + .setConnectTimeout(5000) // 连接超时5秒 + .setTimeout(3000) // 操作超时3秒 + .setRetryAttempts(3) // 从2改为3次重试,提高容错 + + // ✅ 优化:增大订阅连接池 + .setSubscriptionConnectionPoolSize(8) // 从5改为8 + + // ✅ 优化:保活设置 + .setPingConnectionInterval(60000) // 从30秒改为60秒,减少网络开销 + .setKeepAlive(true) // 启用keep-alive + + .setRetryInterval(1500) + .setDnsMonitoringInterval(10000); // 从5秒改为10秒 + + return Redisson.create(config); + } + + @Bean(name = "secondRedissonClient") + public RedissonClient secondRedissonClient() { + Config config = new Config(); + + // ✅ 优化:提高次要Redis的线程配置 + config.setThreads(4); // 从2改为4 + config.setNettyThreads(8); // 从4改为8 + + config.setCodec(new StringCodec()); + + config.useSingleServer() + .setAddress("redis://36.212.16.27:6379") + .setDatabase(0) + .setPassword("long6166") + .setClientName("ruoyi_second") + + // ✅ 优化:增大连接池 + .setConnectionMinimumIdleSize(2) // 从1改为2 + .setConnectionPoolSize(8) // 从4改为8 + .setIdleConnectionTimeout(30000) // 从10秒改为30秒 + + .setConnectTimeout(5000) + .setTimeout(3000) + .setRetryAttempts(2) // 从1改为2 + + .setSubscriptionConnectionPoolSize(4) // 从2改为4 + + .setPingConnectionInterval(60000) // 从30秒改为60秒 + .setKeepAlive(true) + + .setRetryInterval(1500) + .setDnsMonitoringInterval(10000); + + return Redisson.create(config); + } + + @Bean(name = "thirdRedissonClient") + public RedissonClient thirdRedissonClient() { + Config config = new Config(); + + // ✅ 优化:第三个Redis实例的线程配置 + config.setThreads(8); // 保持8 + config.setNettyThreads(16); // 保持16 + + config.setCodec(new StringCodec()); + + config.useSingleServer() + .setAddress("redis://36.212.20.113:7963") + .setDatabase(7) + .setPassword("j8nZ4jra2E") + .setClientName("ruoyi_third") + + // ✅ 优化:调整连接池大小,避免过度占用内存 + .setConnectionMinimumIdleSize(8) // 从16改为8 + .setConnectionPoolSize(24) // 从32改为24,避免内存浪费 + .setIdleConnectionTimeout(30000) // 从10秒改为30秒 + .setConnectTimeout(10000) + .setTimeout(3000) + + // ✅ 优化:订阅连接池 + .setSubscriptionConnectionPoolSize(16) // 从25改为16 + + // ✅ 新增:添加保活设置 + .setPingConnectionInterval(60000) // 60秒ping一次 + .setKeepAlive(true) // 启用keep-alive + .setRetryAttempts(3) // 3次重试 + .setRetryInterval(1500) // 重试间隔 + .setDnsMonitoringInterval(10000); // DNS监控间隔 + + return Redisson.create(config); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/AccountController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/AccountController.java new file mode 100644 index 0000000..4665f60 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/AccountController.java @@ -0,0 +1,39 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.Account; +import org.dromara.zhishu.domain.ProfitSharingLog; +import org.dromara.zhishu.service.IAccountService; +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; + +/** + * 分润日志表 + * + * @author yxy + * @date 2026-03-05 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/account") +public class AccountController { + + private final IAccountService accountService; + + /** + * 分页查询分润日志表 + */ +// @SaCheckPermission("zhishu:profitSharingLog:list") + @GetMapping("/list") + @SaIgnore + public TableDataInfo list(Account bo, PageQuery pageQuery) { + return accountService.queryPageList(bo, pageQuery); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ArtNoMoveController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ArtNoMoveController.java new file mode 100644 index 0000000..66c657a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ArtNoMoveController.java @@ -0,0 +1,13 @@ +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/ArtNoMove") +public class ArtNoMoveController { +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/BookBaseInfoController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/BookBaseInfoController.java new file mode 100644 index 0000000..470671f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/BookBaseInfoController.java @@ -0,0 +1,920 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSONObject; +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.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StringUtils; +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.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.bo.*; +import org.dromara.zhishu.domain.dto.BookBaseInfoDto; +import org.dromara.zhishu.domain.excel.BaseInfoExcel; +import org.dromara.zhishu.domain.vo.BaseInfoPricingVo; +import org.dromara.zhishu.domain.vo.BookBaseInfoVo; +import org.dromara.zhishu.domain.vo.ProductForm; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.mapper.BookBaseInfoMapper; +import org.dromara.zhishu.service.IBookBaseInfoService; +import org.dromara.zhishu.service.IRunningTaskByShopService; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlMultipartFile; +import org.dromara.zhishu.util.WxPayUtil; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.*; +import java.util.concurrent.TimeUnit; + +import static cn.dev33.satoken.SaManager.log; +import static org.dromara.zhishu.util.InterfaceUtils.getInterface; + +/** + * 基础信息 + * + * @author Lion Li + * @date 2025-03-08 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/baseInfo") +public class BookBaseInfoController extends BaseController { + + private final BookBaseInfoMapper baseMapper; + + + private final IBookBaseInfoService bookBaseInfoService; + private final ISysConfigService configService; + private final IShopService shopService; + private final IRunningTaskByShopService runningTaskByShopService; + + private final Set failedIsbns = Collections.synchronizedSet(new HashSet<>()); + + /** + * 查询基础信息列表 + */ + @SaCheckPermission("zhishu:baseInfo:list") + @GetMapping("/list") + @SaIgnore + public TableDataInfo list(BookBaseInfoDto bo, BookNumberRageBo number, PageQuery pageQuery) { + return bookBaseInfoService.queryPageList(bo, number, pageQuery); + } + + /** + * 导出基础信息列表 + */ + @SaCheckPermission("zhishu:baseInfo:export") + @Log(title = "基础信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(BookBaseInfoBo bo, HttpServletResponse response) { + List list = bookBaseInfoService.queryList(bo); + ExcelUtil.exportExcel(list, "基础信息", BookBaseInfoVo.class, response); + } + + /** + * 获取基础信息详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:baseInfo:query") + @SaIgnore + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(bookBaseInfoService.queryById(id)); + } + + + /** + * 获取基础信息详细信息 + * + * @param isbn isbn + */ + @SaCheckPermission("zhishu:baseInfo:query") + @GetMapping("/getBookByIsbn/{isbn}") + @SaIgnore + public R getIsbnList(@NotNull(message = "主键不能为空") + @PathVariable String isbn) { + return R.ok(bookBaseInfoService.getBookByIsbn(isbn)); + } + + /** + * 调取爬虫接口获取书籍数据 + */ + @SaCheckPermission("zhishu:baseInfo:getBookData") + @PostMapping("/getBookData/{isbn}") + public R getBookData(@NotNull(message = "主键不能为空") + @PathVariable String isbn) { + return R.ok(bookBaseInfoService.getBookData(isbn)); + } + + /** + * 新增基础信息 + */ + @SaCheckPermission("zhishu:baseInfo:add") + @Log(title = "基础信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody BookBaseInfoBo bo) { + return toAjax(bookBaseInfoService.insertByBo(bo)); + } + + /** + * 修改基础信息 + */ + @SaCheckPermission("zhishu:baseInfo:edit") + @Log(title = "基础信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody EditBookInfoBo bo) { + return toAjax(bookBaseInfoService.updateByBo(bo)); + } + + /** + * 删除基础信息 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:baseInfo:remove") + @Log(title = "基础信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids) { + + + return toAjax(bookBaseInfoService.deleteWithValidByIds(List.of(ids), true)); + } + /** + * 根据isbn查询书籍详情数据 + */ + @SaIgnore + @GetMapping("/getBookDataByIsbn/{isbn}") + public R> getBookDataByIsbn(@PathVariable String isbn){ + return R.ok(bookBaseInfoService.getBookDataByIsbn(isbn)); + } + + /** + * 更新选品中心单条数据 + */ + @SaIgnore + @PostMapping("/updateBookData") + public R updateBookData(@RequestBody BookUpdateInfoBo bo) { +// System.out.println("更新选品中心单条数据"+bo); + return R.ok(bookBaseInfoService.updateCentBookByIsbn(bo)); + } + + /** + * 文件信息 + * 导入 模板(预留字段) + */ +// @Log(title = "商品信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/importExcel") + public R importExcel(@RequestParam("file") MultipartFile file, @RequestParam("type") Integer type) { + + InputStream inputStream = null; + try { + inputStream = file.getInputStream(); + } catch (IOException e) { + + + } +// throw new RuntimeException("系统错误"); + + List list = ExcelUtil.importExcel(inputStream, BaseInfoExcel.class); + bookBaseInfoService.importExcel(list); + return R.ok(); + } + + + /** + * 获取图书列表 + */ +// @Log(title = "商品信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PostMapping("/getList") + public R getList() { + return R.ok(bookBaseInfoService.getList()); + } + + + + /** + * 书名获取列表 + */ + @RepeatSubmit + @PostMapping("/getBookByName") + @SaIgnore + public R> getBookName(@RequestBody Map request) { + String bookName = request.get("bookName"); + List list = bookBaseInfoService.getBookListByBookName(bookName); + return R.ok(list); + } + + @SaIgnore + @PostMapping("/addBookCatId") + public void addBookCatId(@RequestBody Map request) { + BookBaseInfoBo bo = new BookBaseInfoBo(); + bo.setIsbn(request.get("isbn")); + bo.setCatId(Long.parseLong(request.get("catId"))); + bookBaseInfoService.updateByIsbn(bo); + } + + /** + * 重新生成图书数据 + */ + @SaIgnore + @PostMapping("/regenerateBookData") + public R regenerateBookData() { + try { + System.out.println("=== 开始重新生成图书数据 ==="); + log.info("=== 开始重新生成图书数据 ==="); + long startTime = System.currentTimeMillis(); + + // 读取txt文件 + String fileName = "112233.txt"; + // 创建失败记录文件 + String failFileName = "failed_isbn_" + System.currentTimeMillis() + ".txt"; + + int totalProcessed = 0; + int totalSuccess = 0; + int totalFail = 0; + Set failedIsbns = new HashSet<>(); + + // 读取文件内容 + try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName))) { + String line; + while ((line = reader.readLine()) != null) { + String isbn = extractIsbn(line); + if (isbn != null) { + totalProcessed++; + try { + // 调用PHP爬虫接口 + String kongfzIp = configService.selectConfigByKey("kongfz.ip"); + String bookinfoStr = getInterface(kongfzIp, "/api/kfz/getBookInfoF/" + isbn); + + if (bookinfoStr != null && !bookinfoStr.isEmpty()) { + Map bookinfoMap = JsonUtil.transferToObj(bookinfoStr, Map.class); + if (bookinfoMap.get("code").toString().equals("200")) { + Map data = (Map) bookinfoMap.get("data"); + String bookInfoListStr = JsonUtil.transferToJson(data.get("product")); + List bookInfoList = JsonUtil.transferToObj(bookInfoListStr, List.class); + + if (!bookInfoList.isEmpty()) { + String bookInfo = JsonUtil.transferToJson(bookInfoList.get(0)); + BookBaseInfoVo newData = JsonUtil.transferToObj(bookInfo, BookBaseInfoVo.class); + if (newData != null) { + totalSuccess++; + System.out.println("成功处理ISBN: " + isbn); + log.info("成功处理ISBN: {}", isbn); + } else { + throw new Exception("数据转换失败"); + } + } else { + throw new Exception("商品列表为空"); + } + } else { + throw new Exception("接口返回错误码: " + bookinfoMap.get("code")); + } + } else { + throw new Exception("接口返回数据为空"); + } + } catch (Exception e) { + totalFail++; + failedIsbns.add(isbn); + System.out.println("处理失败ISBN: " + isbn + ", 错误: " + e.getMessage()); + log.error("处理失败ISBN: {}, 错误: {}", isbn, e.getMessage()); + } + + // 每处理一个ISBN后等待5秒 +// Thread.sleep(5000); + } + } + } + + // 将失败的ISBN写入文件 + if (!failedIsbns.isEmpty()) { + try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(failFileName), + StandardCharsets.UTF_8, StandardOpenOption.CREATE)) { + for (String isbn : failedIsbns) { + writer.write("isbn:" + isbn); + writer.newLine(); + } + } + } + + long endTime = System.currentTimeMillis(); + double duration = (endTime - startTime) / 1000.0; + + String message = String.format("处理完成 - 总数: %d, 成功: %d, 失败: %d, 耗时: %.2f秒, 失败记录已保存到: %s", + totalProcessed, totalSuccess, totalFail, duration, failFileName); + + System.out.println("=== 重新生成图书数据完成 ==="); + System.out.println(message); + log.info("=== 重新生成图书数据完成 ==="); + log.info(message); + + return R.ok(message); + + } catch (Exception e) { + String errorMsg = "重新生成图书数据时发生错误: " + e.getMessage(); + System.out.println(errorMsg); + log.error(errorMsg, e); + return R.fail(errorMsg); + } + } + + /** + * 从文本行中提取ISBN的辅助方法 + */ + private String extractIsbn(String line) { + try { + java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("ISBN: (\\d+)"); + java.util.regex.Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + return matcher.group(1); + } + } catch (Exception e) { + log.error("提取ISBN时发生错误: {}", e.getMessage()); + } + return null; + } + + /** + * 批量设置违规信息 + * + * @param bo + * @return + */ + @Log(title = "基础信息", businessType = BusinessType.DELETE) + @PutMapping("batchUpdateIll") + public R batchUpdateIll(@RequestBody IllBaseInfoBo bo) { + System.out.println(bo); + return toAjax(bookBaseInfoService.updateByIllge(bo)); +// return toAjax(bookBaseInfoService.deleteWithValidByIds(List.of(ids), true)); +// return null; + } + + + /** + * 查询基础信息列表 + */ + @GetMapping("/pricing/list") + @SaIgnore + public TableDataInfo listPricing(BookBaseInfoDto bo, BookNumberRageBo number, PageQuery pageQuery) { + return bookBaseInfoService.queryPagePricingList(bo, number, pageQuery); + } + + + /** + * 核价链接加密 + */ + @GetMapping("/pricingLink") + @SaIgnore + public String pricingLink(BookBaseInfoBo bo, BookNumberRageBo number, PageQuery pageQuery) { + String link = bookBaseInfoService.pricingLink(bo, pageQuery); + return link; + } + + + /** + * 核价链接解密 + */ + @GetMapping("/pricingLinkDec") + @SaIgnore + public Map pricingLinkDecrypt(String link) { + Map pricingLink = bookBaseInfoService.pricingLinkDec(link); + return pricingLink; + } + + /** + * 获取用户是否是会员 + * + * @return + */ + @GetMapping("/user/vipInfo/{type}") + @SaIgnore + public Boolean getUserIsVip(@PathVariable Integer type) { + Boolean isVip = bookBaseInfoService.getUserVip(type); + return isVip; + } + + /** + * 根据ISBN获取官图 + * @param isbn ISBN号 + * @return 官图信息 + */ + @GetMapping("/getBookPicByISBN") + @SaIgnore + public R> getBookPicByISBN(@RequestParam String isbn) { + try { + if (StringUtils.isEmpty(isbn)) { + return R.fail("ISBN不能为空"); + } + Map result = new HashMap<>(); + result.put("isbn", isbn); + log.info("开始获取官图,ISBN: {}", isbn); + String goUrl = configService.selectConfigByKey("centerBook.url"); +// String goUrl = "http://localhost:9009/api"; + + String apiUrl = "/es/searchByISBN?isbn=" + isbn; + String responseStr = getInterface(goUrl, apiUrl); + + JSONObject responseJson = JSONObject.parseObject(responseStr); + + if (StringUtils.isNotEmpty(responseJson.getString("data")) ){ + JSONObject dataJson = responseJson.getJSONObject("data"); + System.out.println(dataJson.getJSONObject("book_pic_s")); + ObjectMapper objectMapper = new ObjectMapper(); + Map picData = objectMapper.readValue(dataJson.getString("book_pic_s"), Map.class); + String localPathpdd = picData.get("localPath"); + String pddResponse = picData.get("pddResponse"); + System.out.println("localPath: " + localPathpdd); + System.out.println("pddResponse: " + pddResponse); + + if (pddResponse != null){ + result.put("localPath", pddResponse); + }else if(localPathpdd != null) { + result.put("localPath", localPathpdd); + }else { + result.put("localPath", ""); + log.warn("接口返回数据格式异常,ISBN: {}", isbn); + } + + + }else { + result.put("localPath", ""); + log.warn("接口返回数据为空,ISBN: {}", isbn); + } + + return R.ok(result); + + } catch (Exception e) { + log.error("获取官图失败,ISBN: {}, 错误: {}", isbn, e.getMessage(), e); + Map result = new HashMap<>(); + result.put("localPath", ""); + result.put("isbn", isbn); + return R.ok(result); + } + } + + + + /** + * 创建任务 + * + * @param bo + * @return + */ + @PostMapping("/task") + @SaIgnore + public Map getTask(@RequestBody TaskBo bo) { + return bookBaseInfoService.insertTask(bo); + } + + + @PostMapping("/addNewTask") + @SaIgnore + public Map addNewTask(String taskType,String shopId,String fileName){ + Map result = new HashMap(); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + if (shopVo == null){ + result.put("code",500); + result.put("msg","店铺不存在"); + return result; + } + // 根据shopId查询数据表是否存在 + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopId); + if (checkMark == 0) { + // 不存在则创建表 + runningTaskByShopService.createTable("t_running_task_" + shopId); + } + Task task = new Task(); + task.setTaskType(taskType); + task.setShopIds(shopId); + task.setShopNames(shopVo.getShopName()); + task.setFileName(fileName); + task.setDataNum(0L); + task.setTaskStatus("0"); + task.setStatus("0"); + task.setCreateBy(shopVo.getCreateBy()); + int mark = bookBaseInfoService.addNewTask(task); + if (mark > 0){ + result.put("code",200); + result.put("msg","任务创建成功"); + result.put("taskId",task.getId()); + }else{ + result.put("code",500); + result.put("msg","任务创建失败"); + } + return result; + } + + //扣除余额 + @GetMapping("/setBalance") + @SaIgnore + public Map setBalance(){ + return bookBaseInfoService.setBalance(); + } + + //页面支付 + @PostMapping("/userRecharge") + @SaIgnore + public R userRecharge(@RequestBody UserRechargeBo bo){ + //支付方式 1 微信 + String type = bo.getRechargType(); + //获取登录用户id + String userId = LoginHelper.getUserId().toString(); + if (userId.equals("1")){ + bo.setRechargPrice(BigDecimal.valueOf(1)); + } + if(type.equals("1")){ + //换算手续费为 分 + bo.setUserId(Long.parseLong(userId)); + bo.setStatus("0"); + // 插入erp订单 +// userRechargeService.insertByBo(bo); + String title = "页面展示会员"; + Integer payType=1; + // 插入新后台会员记录 +// bookBaseInfoService.insertUserInfo(bo,title,payType,198000); + // 新增新后台服务表插入 + Map params = new HashMap<>(); + params.put("service_name", title); + params.put("price", String.valueOf(bo.getRechargPrice())); + params.put("unit", "年"); + params.put("length", String.valueOf(1)); + params.put("type", "centerBookPage"); + params.put("sort", "1"); + String service = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/createService", params); + System.out.println("service:"+service); + if (service != null) { + JSONObject jsonObject = JSONObject.parseObject(service); + if (jsonObject != null && jsonObject.containsKey("data")) { + String serviceId = jsonObject.getString("data"); + params.put("serviceId", serviceId); + } + } + // 新增新后台订单表插入 + Map params1 = new HashMap<>(); + params1.put("orderType", "centerBookPage"); + params1.put("userId", userId); + params1.put("goodsId", params.get("serviceId")); + params1.put("count", "1"); + String orderId = null; + String order = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/orders/createOrder", params1); + System.out.println("order:"+order); + if (order != null) { + JSONObject jsonObject = JSONObject.parseObject(order); + if (jsonObject != null && jsonObject.containsKey("data")) { + JSONObject dataObject = jsonObject.getJSONObject("data"); + // 再从data对象中获取orderId + orderId = dataObject.getString("orderId"); + System.out.println("orderId:"+orderId); + params1.put("orderId", orderId); + } + } + String data = WxPayUtil.wxPay(bo.getId(), bo.getRechargPrice().setScale(0, RoundingMode.HALF_UP).intValue(), bo.getRechargPrice().toString(),orderId,userId); + String base64Str = WxPayUtil.generateQRCode(data); + Map map = new HashMap(); + map.put("img",base64Str); + map.put("id", bo.getId()); + return R.ok(map); + } + return R.fail("充值订单生成失败,请联系管理员"); + } + + + //高级按钮支付 + @PostMapping("/buttonUserRecharge") + @SaIgnore + public R buttonUserRecharge(@RequestBody UserRechargeBo bo){ + //支付方式 1 微信 + String type = bo.getRechargType(); + String userId = LoginHelper.getUserId().toString(); + if (userId.equals("1")){ + bo.setRechargPrice(BigDecimal.valueOf(1)); + } + //获取登录用户id + Integer intValue = bo.getRechargPrice().setScale(0, RoundingMode.HALF_UP).intValue(); // 124 + if(type.equals("1")){ + //换算手续费为 分 + bo.setUserId(Long.parseLong(userId)); + bo.setStatus("0"); + // 插入 erp 订单表 +// userRechargeService.insertByBo(bo); + String title = "高级搜索会员"; + Integer payType=0; + // 插入 newAErp 订单表 +// bookBaseInfoService.insertUserInfo(bo,title,payType,9800); + // 新增新后台服务表插入 + Map params = new HashMap<>(); + params.put("service_name", title); + params.put("price", String.valueOf(bo.getRechargPrice())); + params.put("unit", "月"); + params.put("length", String.valueOf(1)); + params.put("type", "centerBookSearch"); + params.put("sort", "1"); + String orderUrl = configService.selectConfigByKey("order.url"); + String service = InterfaceUtils.postForm(orderUrl, "/api/createService", params); +// String service = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/createService", params); + if (service != null) { + JSONObject jsonObject = JSONObject.parseObject(service); + if (jsonObject != null && jsonObject.containsKey("data")) { + String serviceId = jsonObject.getString("data"); + params.put("serviceId", serviceId); + } + } + // 新增新后台订单表插入 + Map params1 = new HashMap<>(); + params1.put("orderType", "centerBookSearch"); + params1.put("userId", userId); + params1.put("goodsId", params.get("serviceId")); + params1.put("count", "1"); + String orderId = null; + String order = InterfaceUtils.postForm(orderUrl, "/api/orders/createOrder", params1); +// String order = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/orders/createOrder", params1); + if (order != null) { + JSONObject jsonObject = JSONObject.parseObject(order); + if (jsonObject != null && jsonObject.containsKey("data")) { + JSONObject dataObject = jsonObject.getJSONObject("data"); + // 再从data对象中获取orderId + orderId = dataObject.getString("orderId"); + params1.put("orderId", orderId); + } + } + String data = WxPayUtil.wxPay(bo.getId(),intValue,bo.getRechargPrice().toString(),orderId,userId); + String base64Str = WxPayUtil.generateQRCode(data); + Map map = new HashMap(); + map.put("img",base64Str); + map.put("id", bo.getId()); + return R.ok(map); + } + return R.fail("充值订单生成失败,请联系管理员"); + } + + + /** + * 获取图片详情 从选品中心获取图片 + * @param isbn + * @return + */ + @GetMapping("/getImageDeit/{isbn}") + @SaIgnore + public R> getImageDeit(@PathVariable String isbn){ + try { + if (StringUtils.isEmpty(isbn)) { + return R.fail("ISBN不能为空"); + } + log.info("开始获取官图,ISBN: {}", isbn); + String goUrl = configService.selectConfigByKey("centerBook.url"); +// String goUrl = "http://localhost:9009"; + String apiUrl = "/es/searchByISBN?isbn=" + isbn; + String responseStr = getInterface(goUrl, apiUrl); + + Map result = new HashMap<>(); + result.put("isbn", isbn); + + if (StringUtils.isNotEmpty(responseStr)) { + try { + // 解析返回的JSON数据 + Map responseMap = JsonUtil.transferToObj(responseStr, Map.class); + if (responseMap != null && responseMap.containsKey("data")) { + String localPath=null ; + Object dataObj = responseMap.get("data"); + if (dataObj instanceof Map) { + Map dataMap = (Map) dataObj; + Object bookPicObj = dataMap.get("book_pic"); + if (bookPicObj instanceof String) { + localPath = (String) bookPicObj; + } else if (bookPicObj instanceof Map) { + + Map bookPicMap = (Map) bookPicObj; + localPath = (String) bookPicMap.get("pddPath"); + } else { + // 其他情况,比如为null或者不是我们预期的类型,可以设置一个默认值或者抛出异常 + localPath = null; // 或者默认值 + } + } + + result.put("localPath", localPath != null ? localPath : ""); + log.info("成功获取官图,ISBN: {}, book_pic_new: {}", isbn, localPath); + } else { + result.put("localPath", ""); + log.warn("接口返回数据格式异常,ISBN: {}", isbn); + } + } catch (Exception parseException) { + result.put("localPath", ""); + log.error("解析接口返回数据失败,ISBN: {}, 错误: {}", isbn, parseException.getMessage()); + } + } else { + result.put("localPath", ""); + log.warn("接口返回数据为空,ISBN: {}", isbn); + } + + return R.ok(result); + + } catch (Exception e) { + log.error("获取官图失败,ISBN: {}, 错误: {}", isbn, e.getMessage(), e); + Map result = new HashMap<>(); + result.put("localPath", ""); + result.put("isbn", isbn); + return R.ok(result); + } + + + + // Map map = bookBaseInfoService.getImageDite(isbn); + // return map; + } + + /** + * 检查订单状态 + * @return + */ + @GetMapping("/checkStatus") + @SaIgnore + public R checkStatus(String type) throws JsonProcessingException { + String userId = String.valueOf(LoginHelper.getUserId()); + Map map = new HashMap(); + map.put("type",type); + map.put("userId",userId); + String orderUrl = configService.selectConfigByKey("order.url"); + String status = InterfaceUtils.postForm(orderUrl, "/api/orders/checkStatus", map); +// String status = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/orders/checkStatus", map); + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode = objectMapper.readTree(status); + + // 构建返回结果 + Map resultMap = new HashMap<>(); + resultMap.put("code", rootNode.get("code")); + resultMap.put("isVip", rootNode.get("data").get("isVip")); + resultMap.put("expirationDate", rootNode.get("data").get("expirationDate")); + resultMap.put("msg", rootNode.get("message")); + + // 返回成功响应 + return R.ok(resultMap); + } + + /** + * xcx查询选品中心数据并同步 + */ + @PostMapping("/getXcxData") + @SaIgnore + public R getXcxData(@RequestBody ProductForm form) { + /** + * 添加选品中心查询 + */ + String centerBookUrl = configService.selectConfigByKey("centerBook.url"); +// String centerBookUrl = "http://192.168.101.213:9009/api"; + String path = "/es/addBookToES"; + Map params = new HashMap<>(); + params.put("isbn", form.getBarcode()); + + params.put("book_name",form.getName()); +// params.put("fix_price", form.getPrice()); + params.put("author", form.getAuthor()); + params.put("publication_time", form.getPublishTime()); + params.put("publisher", form.getPublisher()); + params.put("sell_counts", form.getSellCount()); + params.put("buy_counts", form.getBuyCount()); + + Map book_pic = new HashMap<>(); + Map book_pic_s = new HashMap<>(); + + String pddResponse = ""; + if (form.getFiles() != null && !form.getFiles().isEmpty() && form.getFiles().get(0).getUrl() != null && form.getFiles().get(0).getUrl().startsWith("http")) { + pddResponse = form.getFiles().get(0).getUrl(); + } + book_pic_s.put("localPath", ""); + book_pic_s.put("pddResponse", pddResponse); + + // 处理 kfzBookPic 图片上传获取 pddUrl + String pddUrl = ""; + if (form.getKfzBookPic() != null && !form.getKfzBookPic().isEmpty()) { + // 调用 processImage 处理图片URL + try { + log.info("开始处理图片URL: {}", form.getKfzBookPic()); + + // 从URL下载图片并转换为MultipartFile + String fileName = form.getBarcode() != null ? form.getBarcode() + ".jpg" : "image.jpg"; + UrlMultipartFile urlFile = new UrlMultipartFile(form.getKfzBookPic(), fileName); + + // 构建请求参数 - 使用文件而不是URL + Map imageRequest = new HashMap<>(); + imageRequest.put("goodsName", form.getName()); + imageRequest.put("isbn", form.getBarcode()); + imageRequest.put("isKW", "true"); // 标记为孔网图片 + imageRequest.put("autoUpload", "true"); // 自动上传到PDD + + // 将文件转换为base64 + byte[] bytes = urlFile.getBytes(); + String base64File = java.util.Base64.getEncoder().encodeToString(bytes); + imageRequest.put("imageData", base64File); + imageRequest.put("fileName", fileName); + + // 调用 processImageAndExtractPddUrl 方法获取 pddUrl + pddUrl = InterfaceUtils.processImageAndExtractPddUrl(imageRequest); + + log.info("图片处理成功,获取到 pddUrl: {}", pddUrl); + + } catch (Exception e) { + log.error("图片处理失败: {}, 错误: {}", form.getKfzBookPic(), e.getMessage(), e); + // 处理失败时 pddUrl 为空 + pddUrl = ""; + } + } + + // 将获取到的 pddUrl 放入 bookPic.pddPath + book_pic.put("pddPath", pddUrl); + + params.put("book_pic", book_pic); + params.put("book_pic_s", book_pic_s); + System.out.println("传递的参数"+params); + String interfacePost = InterfaceUtils.getInterfacePost(centerBookUrl, path, params); + return R.ok(interfacePost); + } + + @PostMapping("/processImage") + @SaIgnore + @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "图片处理中,请稍后再试") + public R processImage(@RequestParam(value = "filepath", required = false) MultipartFile file, + @RequestParam(value = "goodsName", required = false) String goodsName, + @RequestParam(value = "isbn", required = false) String isbn, + @RequestParam(value = "isKW", required = false, defaultValue = "false") String isKW, + @RequestParam(value = "autoUpload", required = false, defaultValue = "false") String autoUpload) { + try { + // 构建请求数据 + Map requestData = new HashMap<>(); + requestData.put("goodsName", goodsName); + requestData.put("isbn", isbn); + requestData.put("isKW", isKW); + requestData.put("autoUpload", autoUpload); + + // 如果有文件,优先使用文件 + if (file != null && !file.isEmpty()) { + // 将文件转换为base64用于传递给工具类 + byte[] bytes = file.getBytes(); + String base64File = java.util.Base64.getEncoder().encodeToString(bytes); + requestData.put("imageData", base64File); + requestData.put("fileName", file.getOriginalFilename()); + } else { + return R.fail("请提供图片文件或图片URL"); + } + + // 调用InterfaceUtils中的processImageAndExtractPddUrl方法获取PDD URL + // 现在直接传递Map对象,而不是JSON字符串 + String pddUrl = InterfaceUtils.processImageAndExtractPddUrl(requestData); + + // 返回提取的URL + return R.ok(pddUrl); + + } catch (Exception e) { + return R.fail("图片处理失败: " + e.getMessage()); + } + } + + @PostMapping("/detectById/{id}") + @SaIgnore + public R detectById(@PathVariable("id") Integer id) { + String centerBookUrl = configService.selectConfigByKey("centerBook.url"); +// String centerBookUrl = "http://localhost:9009/api"; + String path = "/es/DeleteBookByID?id=" + id; + String result = InterfaceUtils.getInterface(centerBookUrl, path); + System.out.println("删除结果:" + result); + return R.ok(result); + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/CountController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/CountController.java new file mode 100644 index 0000000..ee81962 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/CountController.java @@ -0,0 +1,48 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.web.core.BaseController; +import org.dromara.zhishu.domain.Statistic; + +import org.dromara.zhishu.service.CountService; +import org.dromara.zhishu.util.CnumberUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 统计 + * + * @author ruoyi + */ +@RestController +@RequiredArgsConstructor +@RequestMapping("/zhishu/statistic") +public class CountController extends BaseController { + + @Autowired + private CountService countService; + + + /** + * 获取库房总数,货架总数 + */ + @SaIgnore +// @SaCheckPermission("zhishu:statistic:statistic") + @GetMapping("/statistic") + public Statistic list() { + //获取当前用户id + Statistic message = countService.selectStatistic(); +// System.out.println(message); + return message; + } + + @GetMapping("/isbn") + @SaIgnore + public String getIsbn() { + return CnumberUtils.generateRandomIsbn(); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/CourierLogController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/CourierLogController.java new file mode 100644 index 0000000..1e87236 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/CourierLogController.java @@ -0,0 +1,81 @@ +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.CourierLog; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +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.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.vo.CourierLogVo; +import org.dromara.zhishu.domain.bo.CourierLogBo; +import org.dromara.zhishu.service.ICourierLogService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 快递日志 + * + * @author yxy + * @date 2026-03-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/courierLog") +public class CourierLogController extends BaseController { + + private final ICourierLogService courierLogService; + + /** + * 查询快递日志列表 + */ + @SaCheckPermission("zhishu:courierLog:list") + @GetMapping("/list") + public TableDataInfo list(CourierLogBo bo, PageQuery pageQuery) { + return courierLogService.queryPageList(bo, pageQuery); + } + + /** + * 导出快递日志列表 + */ + @SaCheckPermission("zhishu:courierLog:export") + @Log(title = "快递日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(CourierLogBo bo, HttpServletResponse response) { + List list = courierLogService.queryList(bo); + ExcelUtil.exportExcel(list, "快递日志", CourierLogVo.class, response); + } + + /** + * 获取快递日志详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:courierLog:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(courierLogService.queryById(id)); + } + + /** + * 删除快递日志 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:courierLog:remove") + @Log(title = "快递日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(courierLogService.deleteWithValidByIds(List.of(ids), true)); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/DepotOrderController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/DepotOrderController.java new file mode 100644 index 0000000..ed8b80c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/DepotOrderController.java @@ -0,0 +1,642 @@ +package org.dromara.zhishu.controller; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSONObject; +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.satoken.utils.LoginHelper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.bo.TShopOrderBo; +import org.dromara.zhishu.domain.dto.OrderGoodsDto; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.util.InterfaceUtils; +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.DepotOrderBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 仓库订单信息 + * + * @author yxy + * @date 2025-06-03 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/depotOrder") +public class DepotOrderController extends BaseController { + + private final IDepotOrderService depotOrderService; + private final ITDepotService depotService; + private final ITLogisticsService logisticsService; + private final ITShopOrderService shopOrderService; + private final IFastMailService fastMailService; + private final ISysConfigService configService;; + + /** + * 查询仓库订单信息列表 + */ + @SaCheckPermission("zhishu:depotOrder:list") + @GetMapping("/list") + public TableDataInfo list(DepotOrderBo bo, PageQuery pageQuery) { + return depotOrderService.queryPageList(bo, pageQuery); + } + + /** + * 导出仓库订单信息列表 + */ + @SaCheckPermission("zhishu:depotOrder:export") + @Log(title = "仓库订单信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(DepotOrderBo bo, HttpServletResponse response) { + List list = depotOrderService.queryList(bo); + ExcelUtil.exportExcel(list, "仓库订单信息", DepotOrderVo.class, response); + } + + /** + * 获取仓库订单信息详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:depotOrder:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(depotOrderService.queryById(id)); + } + + /** + * 新增仓库订单信息 + */ + @SaCheckPermission("zhishu:depotOrder:add") + @Log(title = "仓库订单信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DepotOrderBo bo) { + return toAjax(depotOrderService.insertByBo(bo)); + } + + /** + * 修改仓库订单信息 + */ + @SaCheckPermission("zhishu:depotOrder:edit") + @Log(title = "仓库订单信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DepotOrderBo bo) { + return toAjax(depotOrderService.updateByBo(bo)); + } + + /** + * 删除仓库订单信息 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:depotOrder:remove") + @Log(title = "仓库订单信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(depotOrderService.deleteWithValidByIds(List.of(ids), true)); + } + + + /** + * 电子面单下单 + * 获取运单号 + */ + @SaIgnore + @GetMapping("/getMailNo") + public R getMailNo(String id) throws Exception { + DepotOrderVo depotOrderVo = depotOrderService.selectDepotOrderById(id); + + if (depotOrderVo != null){ + TShopOrderVo shopOrderVo = shopOrderService.queryById(Long.parseLong(depotOrderVo.getShopOrderId())); + + + //查询韵达联调账号密码 + FastMailVo fastMailVo = fastMailService.selectByUserIdAndType(LoginHelper.getUserId().toString(),"1"); + if(fastMailVo == null){ + return R.fail("未配置韵达快递账号,请前往快递打单账号管理"); + } + //获取服务id + String fastMailIp = configService.selectConfigByKey("fastMail.ip"); + // String fastMailIp = "http://localhost:8100"; + + Map map=sendMailToYunda(depotOrderVo,fastMailVo); + + + String mailNo = InterfaceUtils.getInterfacePost(fastMailIp,"/api/yunda/createBmOrder", map); + + Map mailNoMap = JsonUtils.parseMap(mailNo); + + List list = (List) mailNoMap.get("data"); + + Map dataMap = (Map) list.get(0); + + mailNo = dataMap.get("mail_no").toString(); + //存储到订单中 + TShopOrderBo shopOrderBo = new TShopOrderBo(); + shopOrderBo.setId(Long.parseLong(depotOrderVo.getShopOrderId())); + shopOrderBo.setTrackingNumber(mailNo); + shopOrderBo.setOrderStatus(2); + shopOrderService.updateByBo(shopOrderBo); + + + //调用电子面单打印接口 + Map dayinMap = new HashMap(); + dayinMap.put("mailNo",mailNo); + dayinMap.put("partner_id",fastMailVo.getPartnerId()); + dayinMap.put("secret",fastMailVo.getSecret()); + + String pdfDataStr = InterfaceUtils.getInterfacePost(fastMailIp,"/api/yunda/createBmOrderDaYin", dayinMap); + Map pdfDataMap = JsonUtils.parseMap(pdfDataStr); + + List pdfDataList = (List) pdfDataMap.get("data"); + Map pdfData = (Map) pdfDataList.get(0); + String pdfInfo = pdfData.get("pdfInfo").toString(); + + + return R.ok(pdfInfo); + }else { + return R.fail("未找到该订单"); + } + + } + + + @GetMapping("/getPdf") + public R getPdf(String mailNo){ + + //查询韵达联调账号密码 + FastMailVo fastMailVo = fastMailService.selectByUserIdAndType(LoginHelper.getUserId().toString(),"1"); + if(fastMailVo == null){ + return R.fail("未配置韵达快递账号,请前往快递打单账号管理"); + } + //获取服务id + String fastMailIp = configService.selectConfigByKey("fastMail.ip"); + // String fastMailIp = "http://localhost:8100"; + //调用电子面单打印接口 + Map dayinMap = new HashMap(); + dayinMap.put("mailNo",mailNo); + dayinMap.put("partner_id",fastMailVo.getPartnerId()); + dayinMap.put("secret",fastMailVo.getSecret()); + + String pdfDataStr = InterfaceUtils.getInterfacePost(fastMailIp,"/api/yunda/createBmOrderDaYin", dayinMap); + Map pdfDataMap = JsonUtils.parseMap(pdfDataStr); + + List pdfDataList = (List) pdfDataMap.get("data"); + Map pdfData = (Map) pdfDataList.get(0); + String pdfInfo = pdfData.get("pdfInfo").toString(); + + return R.ok(pdfInfo); + } + + /** + * 圆通获取订单号接口 + */ + @SaIgnore + @GetMapping("/getMailNoByYuanTong") + public R getMailNoByYuanTong(String id){ + //获取服务id +// String fastMailIp = configService.selectConfigByKey("fastMail.ip"); + String fastMailIp = "http://localhost:8100"; + + DepotOrderVo depotOrderVo = depotOrderService.selectDepotOrderById(id); + //获取货号 + Map itemList = JsonUtils.parseMap(depotOrderVo.getItemList()); + String artNo = itemList.get("itemSn").toString(); + String itemName = itemList.get("itemName").toString(); + //货号前两位,仓库编码 +// String code = artNo.substring(0,2); + TDepotVo depotVo = depotService.selectDepotByCode(artNo); + //获取仓库绑定的运费模板 + TLogisticsVo tLogisticsVo = logisticsService.queryById(depotVo.getId()); + + Map map = new HashMap(); + map.put("logisticsNo",depotOrderVo.getOrderSn()); + map.put("senderName",tLogisticsVo.getContact()); + map.put("senderProvinceName",tLogisticsVo.getDeliveryProvince()); + map.put("senderCityName",tLogisticsVo.getDeliveryCity()); + map.put("senderCountyName",tLogisticsVo.getDeliveryArea()); + map.put("senderAddress",depotOrderVo.getReceiverName()); + map.put("receiverAddress",tLogisticsVo.getFullAddress()); + map.put("senderMobile",tLogisticsVo.getPhoneNumber()); + map.put("recipientName",depotOrderVo.getReceiverName()); + map.put("recipientProvinceName",depotOrderVo.getProvince()); + map.put("recipientCityName",depotOrderVo.getCity()); + map.put("recipientCountyName",depotOrderVo.getTown()); + map.put("recipientMobile",depotOrderVo.getReceiverPhoneMask()); + map.put("recipientAddress",depotOrderVo.getReceiverAddressMask()); + map.put("itemName",itemName); + //备注(货号) + map.put("remark",artNo); + + // 获取商品信息 + String isbn = itemList.containsKey("isbn") ? itemList.get("isbn").toString() : ""; + String itemId = itemList.containsKey("itemId") ? itemList.get("itemId").toString() : ""; + String quality = itemList.containsKey("quality") ? itemList.get("quality").toString() : ""; + String number = itemList.containsKey("number") ? itemList.get("number").toString() : "1"; + + // 创建OrderGoodsDto对象并设置相关属性 + OrderGoodsDto goodsDto = new OrderGoodsDto() + .setName(itemName) + .setItemSn(isbn) + .setGoodsId(itemId) + .setQuality(quality) + .setQuantity(Integer.parseInt(number)); + + // 创建物品列表集合 + Set goodsSet = new HashSet<>(); + goodsSet.add(goodsDto); + + // 添加物品列表到参数中 + map.put("goods", goodsSet); + + String mailNoResponse = InterfaceUtils.getInterfacePost(fastMailIp,"/api/yuanTong/createOrder", map); + + Map mailNoMap = JsonUtils.parseMap(mailNoResponse); + + // 直接从返回数据中获取mailNo,而不是从list中获取 + String mailNo = ""; + if (mailNoMap.containsKey("mailNo")) { + mailNo = mailNoMap.get("mailNo").toString(); + } else if (mailNoMap.containsKey("data") && mailNoMap.get("data") instanceof Map) { + Map dataMap = (Map) mailNoMap.get("data"); + if (dataMap.containsKey("mailNo")) { + mailNo = dataMap.get("mailNo").toString(); + } + } + + // 如果没有获取到mailNo,尝试解析完整的响应数据 + if (mailNo.isEmpty() && mailNoMap.containsKey("data")) { + Object dataObj = mailNoMap.get("data"); + if (dataObj instanceof String) { + // 尝试解析data字段中的JSON字符串 + Map dataMap = JsonUtils.parseMap(dataObj.toString()); + if (dataMap.containsKey("mailNo")) { + mailNo = dataMap.get("mailNo").toString(); + } + } + } + + // 如果仍然没有获取到mailNo,记录错误并返回 + if (mailNo.isEmpty()) { + return R.fail("获取运单号失败,接口返回数据:" + mailNoResponse); + } + + //存储到订单中 + TShopOrderBo shopOrderBo = new TShopOrderBo(); + shopOrderBo.setId(Long.parseLong(depotOrderVo.getShopOrderId())); + shopOrderBo.setTrackingNumber(mailNo); + shopOrderBo.setOrderStatus(2); + shopOrderService.updateByBo(shopOrderBo); + + //调用电子面单打印接口 + Map dayinMap = new HashMap(); + dayinMap.put("waybillNo", mailNo); + + String pdfDataStr = InterfaceUtils.getInterfacePost(fastMailIp,"/api/yuanTong/printWaybill", dayinMap); + Map pdfDataMap = JsonUtils.parseMap(pdfDataStr); + + // 直接从返回数据中获取PDF信息 + String pdfInfo = ""; + if (pdfDataMap.containsKey("data")) { + Object dataObj = pdfDataMap.get("data"); + if (dataObj instanceof Map) { + Map dataMap = (Map) dataObj; + if (dataMap.containsKey("pdfBase64")) { + pdfInfo = dataMap.get("pdfBase64").toString(); + } + } else if (dataObj instanceof String) { + try { + // 尝试解析data字段中的JSON字符串 + Map dataMap = JsonUtils.parseMap(dataObj.toString()); + if (dataMap != null && dataMap.containsKey("pdfBase64")) { + pdfInfo = dataMap.get("pdfBase64").toString(); + } else { + pdfInfo = dataObj.toString(); + } + } catch (Exception e) { + // 如果解析失败,直接使用字符串 + pdfInfo = dataObj.toString(); + } + } + } + + if (pdfInfo.isEmpty()) { + return R.fail("获取电子面单失败,接口返回数据:" + pdfDataStr); + } + + return R.ok(pdfInfo); + } + + @GetMapping("/getPdfByYuanTong") + public R getPdfByYuanTong(String waybillNo){ + //获取服务id +// String fastMailIp = configService.selectConfigByKey("fastMail.ip"); + + String fastMailIp = "http://localhost:8100"; + //调用电子面单打印接口 + Map dayinMap = new HashMap(); + dayinMap.put("waybillNo", waybillNo); + + String pdfDataStr = InterfaceUtils.getInterfacePost(fastMailIp,"/api/yuanTong/printWaybill", dayinMap); + Map pdfDataMap = JsonUtils.parseMap(pdfDataStr); + + // 直接从返回数据中获取PDF信息 + String pdfInfo = ""; + if (pdfDataMap.containsKey("data")) { + Object dataObj = pdfDataMap.get("data"); + if (dataObj instanceof Map) { + Map dataMap = (Map) dataObj; + if (dataMap.containsKey("pdfBase64")) { + pdfInfo = dataMap.get("pdfBase64").toString(); + } + } else if (dataObj instanceof String) { + try { + // 尝试解析data字段中的JSON字符串 + Map dataMap = JsonUtils.parseMap(dataObj.toString()); + if (dataMap != null && dataMap.containsKey("pdfBase64")) { + pdfInfo = dataMap.get("pdfBase64").toString(); + } else { + pdfInfo = dataObj.toString(); + } + } catch (Exception e) { + // 如果解析失败,直接使用字符串 + pdfInfo = dataObj.toString(); + } + } + } + + if (pdfInfo.isEmpty()) { + return R.fail("获取电子面单失败,接口返回数据:" + pdfDataStr); + } + + return R.ok(pdfInfo); + } + + /** + * 中通获取订单号接口 + */ + @SaIgnore + @GetMapping("/getMailNoByZhongTong") + public R getMailNoByZhongTong(String id){ + //获取服务id +// String fastMailIp = configService.selectConfigByKey("fastMail.ip"); + String fastMailIp = "http://localhost:8100"; + + DepotOrderVo depotOrderVo = depotOrderService.selectDepotOrderById(id); + + //获取货号 + Map itemList = JsonUtils.parseMap(depotOrderVo.getItemList()); + String artNo = itemList.get("itemSn").toString(); + String itemName = itemList.get("itemName").toString(); + //货号前两位,仓库编码 +// String code = artNo.substring(0,2); + TDepotVo depotVo = depotService.selectDepotByCode(artNo); + //获取仓库绑定的运费模板 + TLogisticsVo tLogisticsVo = logisticsService.queryById(depotVo.getId()); + + Map map = new HashMap(); + map.put("partnerType","2"); + map.put("orderType","1"); + map.put("partnerOrderCode",depotOrderVo.getOrderSn()); + Map accountInfo = new HashMap<>(); + accountInfo.put("accountId", "test"); + accountInfo.put("accountPassword", "ZTO123"); + accountInfo.put("type", "1"); + map.put("accountInfo", accountInfo); + + // 发件人信息 + Map senderInfo = new HashMap<>(); + senderInfo.put("senderName", tLogisticsVo.getContact()); + senderInfo.put("senderMobile", tLogisticsVo.getPhoneNumber()); + senderInfo.put("senderProvince", tLogisticsVo.getDeliveryProvince()); + senderInfo.put("senderCity", tLogisticsVo.getDeliveryCity()); + senderInfo.put("senderDistrict", tLogisticsVo.getDeliveryArea()); + senderInfo.put("senderAddress", tLogisticsVo.getFullAddress()); + map.put("senderInfo", senderInfo); + + // 收件人信息 + Map receiveInfo = new HashMap<>(); + receiveInfo.put("receiverName", depotOrderVo.getReceiverName()); + receiveInfo.put("receiverMobile", depotOrderVo.getReceiverPhoneMask()); + receiveInfo.put("receiverProvince", depotOrderVo.getProvince()); + receiveInfo.put("receiverCity", depotOrderVo.getCity()); + receiveInfo.put("receiverDistrict", depotOrderVo.getTown()); + receiveInfo.put("receiverAddress", depotOrderVo.getReceiverAddressMask()); + map.put("receiveInfo", receiveInfo); + // 获取商品信息 + String isbn = itemList.containsKey("isbn") ? itemList.get("isbn").toString() : ""; + String itemId = itemList.containsKey("itemId") ? itemList.get("itemId").toString() : ""; + String quality = itemList.containsKey("quality") ? itemList.get("quality").toString() : ""; + String number = itemList.containsKey("number") ? itemList.get("number").toString() : "1"; + + // 创建OrderGoodsDto对象并设置相关属性 + OrderGoodsDto goodsDto = new OrderGoodsDto() + .setName(itemName) + .setItemSn(isbn) + .setGoodsId(itemId) + .setQuality(quality) + .setQuantity(Integer.parseInt(number)); + + // 创建物品列表集合 + Set goodsSet = new HashSet<>(); + goodsSet.add(goodsDto); + Map orderItems = new HashMap<>(); + orderItems.put("name", goodsSet); + map.put("orderItems", orderItems); + + String mailNoResponse = InterfaceUtils.getInterfacePost(fastMailIp,"/api/zto/createOrder", map); + + Map mailNoMap = JsonUtils.parseMap(mailNoResponse); + + // 直接从返回数据中获取mailNo,而不是从list中获取 + String mailNo = ""; + if (mailNoMap.containsKey("mailNo")) { + mailNo = mailNoMap.get("mailNo").toString(); + } else if (mailNoMap.containsKey("data") && mailNoMap.get("data") instanceof Map) { + Map dataMap = (Map) mailNoMap.get("data"); + if (dataMap.containsKey("mailNo")) { + mailNo = dataMap.get("mailNo").toString(); + } + } + + // 如果没有获取到mailNo,尝试解析完整的响应数据 + if (mailNo.isEmpty() && mailNoMap.containsKey("data")) { + Object dataObj = mailNoMap.get("data"); + if (dataObj instanceof String) { + // 尝试解析data字段中的JSON字符串 + Map dataMap = JsonUtils.parseMap(dataObj.toString()); + if (dataMap.containsKey("mailNo")) { + mailNo = dataMap.get("mailNo").toString(); + } + } + } + + // 如果仍然没有获取到mailNo,记录错误并返回 + if (mailNo.isEmpty()) { + return R.fail("获取运单号失败,接口返回数据:" + mailNoResponse); + } + + //存储到订单中 + TShopOrderBo shopOrderBo = new TShopOrderBo(); + shopOrderBo.setId(Long.parseLong(depotOrderVo.getShopOrderId())); + shopOrderBo.setTrackingNumber(mailNo); + shopOrderBo.setOrderStatus(2); + shopOrderService.updateByBo(shopOrderBo); + + //调用电子面单打印接口 + Map dayinMap = new HashMap(); + dayinMap.put("waybillNo", mailNo); + + String pdfDataStr = InterfaceUtils.getInterfacePost(fastMailIp,"/api/zto/printWaybill", dayinMap); + Map pdfDataMap = JsonUtils.parseMap(pdfDataStr); + + // 直接从返回数据中获取PDF信息 + String pdfInfo = ""; + if (pdfDataMap.containsKey("data")) { + Object dataObj = pdfDataMap.get("data"); + if (dataObj instanceof Map) { + Map dataMap = (Map) dataObj; + if (dataMap.containsKey("pdfBase64")) { + pdfInfo = dataMap.get("pdfBase64").toString(); + } + } else if (dataObj instanceof String) { + try { + // 尝试解析data字段中的JSON字符串 + Map dataMap = JsonUtils.parseMap(dataObj.toString()); + if (dataMap != null && dataMap.containsKey("pdfBase64")) { + pdfInfo = dataMap.get("pdfBase64").toString(); + } else { + pdfInfo = dataObj.toString(); + } + } catch (Exception e) { + // 如果解析失败,直接使用字符串 + pdfInfo = dataObj.toString(); + } + } + } + + if (pdfInfo.isEmpty()) { + return R.fail("获取电子面单失败,接口返回数据:" + pdfDataStr); + } + + return R.ok(pdfInfo); + } + + + public Map sendMailToYunda(DepotOrderVo depotOrderVo,FastMailVo fastMailVo) { + + + Map map = new HashMap(); + // 判断订单来源 1 拼多多 2 孔网 + if(depotOrderVo.getOrderSourceType()==1){ + //获取货号 + Map itemList = JsonUtils.parseMap(depotOrderVo.getItemList()); + + String artNo = itemList.get("outerId").toString(); + String itemName = itemList.get("goodsName").toString(); + //货号前两位,仓库编码 + // String code = artNo.substring(0,2); + TDepotVo depotVo = depotService.selectDepotByCode(artNo); + //获取仓库绑定的运费模板 + TLogisticsVo tLogisticsVo = logisticsService.queryById(depotVo.getId()); + + + map.put("order_serial_no",depotOrderVo.getOrderSn()); + map.put("khddh",depotOrderVo.getOrderSn()); + map.put("senderName",tLogisticsVo.getContact()); + map.put("senderAddress",tLogisticsVo.getFullAddress()); + map.put("senderMobile",tLogisticsVo.getPhoneNumber()); + map.put("receiverName",depotOrderVo.getReceiverName()); + map.put("receiverAddress",depotOrderVo.getReceiverAddress()); + map.put("receiverMobile",depotOrderVo.getReceiverPhoneMask()); + map.put("partner_id",fastMailVo.getPartnerId()); + map.put("secret",fastMailVo.getSecret()); + map.put("itemName",itemName); + //备注(货号) + map.put("remark",artNo); + // 构建自定义区域的商品信息数据 + String isbn = itemList.containsKey("outerGoodsId") ? itemList.get("outerGoodsId").toString() : ""; + String itemId = itemList.containsKey("skuId") ? itemList.get("skuId").toString() : ""; + String quality = itemList.containsKey("quality") ? itemList.get("quality").toString() : ""; + String number = itemList.containsKey("goodsCount") ? itemList.get("goodsCount").toString() : ""; + + // 按照要求格式组装数据: isbn|itemId|itemName|quality*number + String customItemInfo = isbn + "|" + itemId + "|" + itemName + "|[" + quality + "]*" + number; + + // 添加自定义数据到打印参数 + map.put("customData", customItemInfo); + + + } + if(depotOrderVo.getOrderSourceType()==2){ + + Map itemList = JSONObject.parseObject(depotOrderVo.getItemList()); + String artNo = itemList.get("itemSn").toString(); + String itemName = itemList.get("itemName").toString(); + //货号前两位,仓库编码 +// String code = artNo.substring(0,2); + TDepotVo depotVo = depotService.selectDepotByCode(artNo); + + //获取仓库绑定的运费模板 + TLogisticsVo tLogisticsVo = logisticsService.queryById(depotVo.getId()); + //获取仓库绑定的运费模板 + // Logistics logistics = logisticsService.getInfo(depot.getId()); + + + map.put("order_serial_no",depotOrderVo.getOrderSn()); + map.put("khddh",depotOrderVo.getOrderSn()); + map.put("senderName",tLogisticsVo.getContact()); + map.put("senderAddress",tLogisticsVo.getFullAddress()); + map.put("senderMobile",tLogisticsVo.getPhoneNumber()); + map.put("receiverName",depotOrderVo.getReceiverName()); + map.put("receiverAddress",depotOrderVo.getReceiverAddress()); + map.put("receiverMobile",depotOrderVo.getReceiverPhoneMask()); + map.put("partner_id",fastMailVo.getPartnerId()); + map.put("secret",fastMailVo.getSecret()); + map.put("itemName",itemName); + //备注(货号) + map.put("remark",artNo); + // 构建自定义区域的商品信息数据 + String isbn = itemList.containsKey("isbn") ? itemList.get("isbn").toString() : ""; + String itemId = itemList.containsKey("itemId") ? itemList.get("itemId").toString() : ""; + String quality = itemList.containsKey("quality") ? itemList.get("quality").toString() : ""; + String number = itemList.containsKey("number") ? itemList.get("number").toString() : ""; + + // 按照要求格式组装数据: isbn|itemId|itemName|quality*number + String customItemInfo = isbn + "|" + itemId + "|" + itemName + "|[" + quality + "]*" + number; + + // 添加自定义数据到打印参数 + map.put("customData", customItemInfo); + + } + + + return map; + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ExcelTaskController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ExcelTaskController.java new file mode 100644 index 0000000..7536e1b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ExcelTaskController.java @@ -0,0 +1,294 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.core.ExcelResult; +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.oss.entity.UploadResult; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.BaseController; +import org.dromara.zhishu.domain.bo.ExcelTaskBo; +import org.dromara.zhishu.domain.vo.BookVo; +import org.dromara.zhishu.domain.vo.ExcelTaskVo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.service.IExcelTaskService; +import org.dromara.zhishu.service.ITDepotService; +import org.dromara.zhishu.threads.ExcelTaskRunnable; +import org.dromara.zhishu.util.EasyExcelUtil; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + + +/** + * execel任务列表 + * + * @author yxy + * @date 2025-03-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/excelTask") +public class ExcelTaskController extends BaseController { + + private final IExcelTaskService taskService; +// +// private final IShopDetailService shopDetailService; + +// private final PddServiceImpl pddService; + + private final ITDepotService tdepotService; + + + /** + * 查询任务列表列表 + */ + @SaCheckPermission("zhishu:excelTask:list") + @GetMapping("/list") + public TableDataInfo list(ExcelTaskBo bo, PageQuery pageQuery) { + return taskService.queryPageList(bo, pageQuery); + } + + + @GetMapping("/logsList") + public List> logsList(String id){ + String fileName = id+".txt"; + List> logsMapList = EasyExcelUtil.readFileContent(UrlUtil.getUrl() +fileName); + return logsMapList; + } + + @GetMapping("/logsMsg") + public String logsMsg(String id){ + String msg = EasyExcelUtil.readFileContentString(UrlUtil.getUrl()+id+"-msg.txt"); + return msg; + } + + @GetMapping("/logsDetailList/{taskId}/{shopId}") + public List> logsDetailList(@PathVariable("taskId") String taskId, + @PathVariable("shopId") String shopId){ + String fileName = taskId+shopId+".txt"; + List> logsDetailList = EasyExcelUtil.readFileContent(UrlUtil.getUrl()+fileName); + return logsDetailList; + } + + @SaIgnore + @GetMapping("/downloadLogs/{fileName}") + public ResponseEntity downloadLogs(HttpServletResponse response,@PathVariable String fileName) { + String filePath = UrlUtil.getUrl() + fileName; + File file = new File(filePath); + if (!file.exists()) { + return ResponseEntity.notFound().build(); + } + Resource resource = new FileSystemResource(file); + try { + // 编码文件名以处理 Unicode 字符 + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()); + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"") + .contentType(MediaType.APPLICATION_OCTET_STREAM) + .body(resource); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return ResponseEntity.badRequest().build(); + } + } + + /** + * 导出任务列表列表 + */ + @SaCheckPermission("zhishu:excelTask:export") + @Log(title = "任务列表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ExcelTaskBo bo, HttpServletResponse response) { +// List list = taskService.queryList(bo); +// ExcelUtil.exportExcel(list, "任务列表", ExcelTaskVo.class, response); + } + + /** + * 获取任务列表详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:excelTask:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(taskService.queryById(id)); +// return null; + } + + /** + * 新增任务列表 + */ +// @SaCheckPermission("zhishu:excelTask:add") + @Log(title = "任务列表", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody Map map) { + + //任务类型 + String taskType = map.get("taskType").toString(); +// + //仓库ids + String[] depotIdsArr = map.get("depotIds").toString().split(","); + //仓库名称 + String depotNames = ""; + for(String depotIds:depotIdsArr){ + String depotId=""; + if(depotIds.contains(String.valueOf("["))){ + depotId= depotIds.replace("[","").trim(); + }else if(depotIds.contains(String.valueOf("]"))){ + depotId= depotIds.replace("]","").trim(); + } + TDepotVo TDepotVo = tdepotService.queryById(Long.parseLong(depotId)); + + if(depotNames.equals("")){ + depotNames= TDepotVo.getName(); + }else{ + depotNames = depotNames + "," + TDepotVo.getName(); + } + } + + //图书列表 +// List list = RedisUtils.getCacheList("bookVoList"); +// RedisUtils.deleteObject("bookVoList"); + //文件名称 + String taskExcelName = RedisUtils.getCacheObject("taskExcelName"); + RedisUtils.deleteObject("taskExcelName"); + + //存储任务信息 + ExcelTaskBo taskBo = new ExcelTaskBo(); + taskBo.setTaskType(taskType); + taskBo.setFileName(taskExcelName); + taskBo.setDepotIds(depotNames); +// taskBo.setDataNum(Long.parseLong(list.size()+"")); + taskBo.setTaskStatus("1"); + taskService.insertByBo(taskBo); +// + // 创建并启动线程 + ExcelTaskRunnable taskRunnable = new ExcelTaskRunnable(map,taskBo); + Thread thread = new Thread(taskRunnable); + thread.start(); +// +// +// taskBo.setThreadId(thread.getId()); +// taskService.updateByBo(taskBo); + return toAjax(1); + } + + /** + * 暂停线程 + * @param threadId + */ + @GetMapping("/pauseThread/{threadId}/{taskId}") + public void pauseThread(@PathVariable("threadId") Long threadId,@PathVariable("taskId") Long taskId){ +// pddService.zanTing(String.valueOf(threadId)); +// ExcelTaskBo taskBo = new ExcelTaskBo(); +// taskBo.setId(taskId); +// taskBo.setTaskStatus("2"); +// taskService.updateByBo(taskBo); + } + + /** + * 继续执行线程 + * @param threadId + */ + @GetMapping("/continueThread/{threadId}/{taskId}") + public void continueThread(@PathVariable("threadId") Long threadId,@PathVariable("taskId") Long taskId){ +// pddService.huanXing(String.valueOf(threadId)); +// ExcelTaskBo taskBo = new ExcelTaskBo(); +// taskBo.setId(taskId); +// taskBo.setTaskStatus("1"); +// taskService.updateByBo(taskBo); + } + + + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "发布任务数据", BookVo.class, response); + } + + + /** + * 修改任务列表 + */ + @SaCheckPermission("zhishu:task:edit") + @Log(title = "任务列表", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ExcelTaskBo bo) { + return toAjax(taskService.updateByBo(bo)); +// return null; + } + + + /** + * 删除任务列表 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:excelTask:remove") + @Log(title = "任务列表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(taskService.deleteWithValidByIds(List.of(ids), true)); +// return null; + } + + @PostMapping(value = "/upload") + public R upload(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + /** + * 存储书号到radis + */ + RedisUtils.deleteObject("bookVoList"); + RedisUtils.deleteObject("taskExcelName"); + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), BookVo.class, true); + List list = MapstructUtils.convert(excelResult.getList(), BookVo.class); + RedisUtils.setCacheList("bookVoList", list); + RedisUtils.setCacheObject("taskExcelName",file.getOriginalFilename()); + } catch (IOException e) { + throw new RuntimeException(e); + } +// UploadResult uploadResult = shopDetailService.upload(file); +// return R.ok(uploadResult); + return null; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/FilterSetController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/FilterSetController.java new file mode 100644 index 0000000..63e100d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/FilterSetController.java @@ -0,0 +1,189 @@ +package org.dromara.zhishu.controller; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.util.ObjectUtil; +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.excel.core.ExcelResult; +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.vo.BookVo; +import org.dromara.zhishu.domain.vo.FilterSetTxtVo; +import org.dromara.zhishu.util.EasyExcelUtil; +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.FilterSetVo; +import org.dromara.zhishu.domain.bo.FilterSetBo; +import org.dromara.zhishu.service.IFilterSetService; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; + +/** + * 过滤设置 + * + * @author yxy + * @date 2025-04-14 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/filterSet") +public class FilterSetController extends BaseController { + + private final IFilterSetService filterSetService; + + /** + * 查询过滤设置列表 + */ + @SaCheckPermission("zhishu:filterSet:list") + @GetMapping("/list") + public TableDataInfo list(FilterSetBo bo, PageQuery pageQuery) { + return filterSetService.queryPageList(bo, pageQuery); + } + + /** + * 导出过滤设置列表 + */ + @SaCheckPermission("zhishu:filterSet:export") + @Log(title = "过滤设置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(FilterSetBo bo, HttpServletResponse response) { + List list = filterSetService.queryList(bo); + ExcelUtil.exportExcel(list, "过滤设置", FilterSetVo.class, response); + } + + /** + * 获取过滤设置详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:filterSet:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(filterSetService.queryById(id)); + } + + /** + * 新增过滤设置 + */ + @SaCheckPermission("zhishu:filterSet:add") + @Log(title = "过滤设置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + @SaIgnore + public R add(@Validated(AddGroup.class) @RequestBody FilterSetBo bo) { + String sort = bo.getSort(); + String[] addTxts = bo.getAddTxt().split("\n"); + Boolean bool = false; + for(String addTxt : addTxts){ + if (StringUtils.isEmpty(addTxt)){ + continue; + } + + bo.setId(null); + bo.setSort(sort); + //去掉前后空格 + addTxt = addTxt.trim(); + bo.setAddTxt(addTxt); + //查询是否有相同的违规词,如果有,则合并 + List list = filterSetService.selectVoListByBo(bo); + if(list.isEmpty()){ + //没有则直接新增 + bo.setAddTxt(addTxt); + bool = filterSetService.insertByBo(bo); + }else{ + //如果存在则合并平台字段,并将多余的数据删除 + //两个数组合并 + Set sortSet = new HashSet(); + FilterSetVo vo = list.get(0); + String[] newSortArr = bo.getSort().split( ","); + for (int j=0;j edit(@Validated(EditGroup.class) @RequestBody FilterSetBo bo) { + return toAjax(filterSetService.updateByBo(bo)); + } + + /** + * 删除过滤设置 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:filterSet:remove") + @Log(title = "过滤设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(filterSetService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "过滤设置数据", FilterSetTxtVo.class, response); + } + + @PostMapping(value = "/upload") + public R> upload(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + return R.fail("上传文件不能为空"); + } + try { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), FilterSetTxtVo.class, true); + List list = MapstructUtils.convert(excelResult.getList(), FilterSetTxtVo.class); + return R.ok(list); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/GoofishController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/GoofishController.java new file mode 100644 index 0000000..ebf18f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/GoofishController.java @@ -0,0 +1,34 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/huidiao/goofish") +public class GoofishController { + /** + * 导出店铺主表列表 + */ + + @PostMapping("/goofishGoods") + @SaIgnore + public void goofishgoods( ) { + return; + } + + @PostMapping("/goofishgOrder") + @SaIgnore + public void goofishgOrder( ) { + return; + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/KongfzController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/KongfzController.java new file mode 100644 index 0000000..40c5a96 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/KongfzController.java @@ -0,0 +1,209 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.lang.TypeReference; +import cn.hutool.json.ObjectMapper; +import com.alibaba.fastjson.JSONObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import com.pdd.pop.sdk.http.PopAccessTokenClient; +import com.pdd.pop.sdk.http.api.pop.response.PddMallInfoGetResponse; +import com.pdd.pop.sdk.http.token.AccessTokenResponse; +import io.swagger.v3.core.util.Json; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.dromara.common.core.config.RuoYiConfig; +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.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.TUserPlatform; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.zhishu.domain.bo.ShopGoodsPublishedBo; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.JsonObjUtil; +import org.dromara.zhishu.util.MapUtils; +import org.dromara.zhishu.util.UploadUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.AbstractView; +import org.springframework.web.servlet.view.RedirectView; + +import java.io.IOException; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static cn.dev33.satoken.SaManager.log; +import static org.dromara.zhishu.util.InterfaceUtils.getInterface; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/kongfz") +public class KongfzController { + + private final RuoYiConfig ruoYiConfig; + + private final IShopService shopService; + + private final IShopDetailService shopDetailService; + + private final ISysConfigService configService; + + private final IKongFzService kongFzService; + + private final IZhishuShopGoodsService zhishuShopGoodsService; + + private final IShopGoodsPublishedService shopGoodsPublishedService; + + + @GetMapping("/toKongfzGetCode") + @SaIgnore + public String toKongfzGetCode(@RequestParam String id) { + + String phpUrl = configService.selectConfigByKey("php.url"); + + String appId= "576"; + String state = id; + String redirectUri = phpUrl + "/auth/callback"; + + String authorizationUrl ="https://open.kongfz.com/v1/oauth2/authorize?" + + "appId="+appId + + "&responseType=code" + + "&state="+state + + "&redirectUri="+redirectUri; + + return authorizationUrl; + } + + @SaIgnore + @GetMapping("/phpCallBack") + public ModelAndView phpCallBack() { + return new ModelAndView(new RedirectView("http://" + ruoYiConfig.getIpurl() + "/shop/shop")); + } + +// /** +// * 孔夫子授权 +// */ +// @SaIgnore +// @GetMapping("/toKongfzGetCode") +// public R getAuthUrl(@RequestParam String id) { +// ShopVo shopVo = shopService.queryById(Long.parseLong(id)); +// +// String account = shopVo.getAccount(); +// String password = shopVo.getPassword(); +// //获取php服务地址 +// String phpUrl = configService.selectConfigByKey("php.url"); +// +// try { +// InterfaceUtils.getInterface(phpUrl, "/auth/getKongfuziAuthUrl/"+id+"/"+account+"/"+password); +// Thread.sleep(2000); // 停止2秒 +// } catch (InterruptedException e) { +// System.out.println("授权停止2秒异常"); +// } catch (Exception e) { +// System.out.println("授权接口返回500异常"); +// } +// +// return R.ok(); +// } + + + + /** + * 获取运费模板 + */ + @GetMapping("/getTemplateSimpleList/{shopId}") + public List getTemplateSimpleList(@PathVariable("shopId") String shopId){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + String kongfzIp = configService.selectConfigByKey("kongfz.ip"); + String templateSimpleListStr = getInterface(kongfzIp, "/api/kfz/getTemplateSimpleList/" + shopVo.getToken()); + List templateSimpleList = JsonUtil.transferToObj(templateSimpleListStr, ArrayList.class); + return templateSimpleList; + } + + @GetMapping("/getCategory") + @SaIgnore + public String getCategory(String token){ + String content = RedisUtils.getCacheObject("categoryListStr"); + if (content == null || StringUtils.isEmpty(content)) { + String kongfzIp = configService.selectConfigByKey("kongfz.ip"); + content = getInterface(kongfzIp, "/api/kfz/getCategory/" + token); + RedisUtils.setCacheObject("categoryListStr", content); + } + return content; + } +// +// /** +// * 商品发布 +// * @param shopId +// * @param goodId +// * @return +// */ +// @SaIgnore +// @GetMapping("/goodAdd/{shopId}/{goodId}") +// public String goodAdd(@PathVariable("shopId") String shopId,@PathVariable("goodId") String goodId){ +// +// ShopDetailVo shopDetailVo = shopDetailService.queryByShopId(Long.parseLong(shopId)); +// +// ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.queryById(goodId); +// +// ZhishuShopGoods zhishuShopGoods = new ZhishuShopGoods(); +// zhishuShopGoods.setId(zhishuShopGoodsVo.getId()); +// zhishuShopGoods.setIsbn(zhishuShopGoodsVo.getIsbn()); +// zhishuShopGoods.setGoodsName(zhishuShopGoodsVo.getGoodsName()); +// zhishuShopGoods.setPrice(zhishuShopGoodsVo.getPrice()); +// zhishuShopGoods.setInventory(Long.parseLong(zhishuShopGoodsVo.getInventory())); +// zhishuShopGoods.setArtNo(zhishuShopGoodsVo.getArtNo()); +// zhishuShopGoods.setConditionCode("L"); +// zhishuShopGoods.setUserId(1L); +// +// +// kongFzService.goodAdd(shopId,zhishuShopGoods,shopDetailVo); +// +// return "添加成功"; +// } + + /** + * 增加接口 + * @param map + * @return + */ + @SaIgnore + @PostMapping("/goodAddCallBack") + public void goodAddCallBack(@RequestBody Map map){ +// System.out.println("erp调用新增已发布商品数据:"+ JsonUtil.transferToJson(map)); + ShopGoodsPublishedBo bo = new ShopGoodsPublishedBo(); + bo.setShopGoodsId(map.get("goodId").toString()); + bo.setShopId(map.get("shopId").toString()); + bo.setPlatformId(map.get("itemId").toString()); + bo.setCreateBy(Long.parseLong(map.get("userId").toString())); + bo.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + bo.setUpdateTime(DateUtils.parseDate(DateUtils.getTime())); +// System.out.println("封装数据:"+bo); + shopGoodsPublishedService.insertByBo(bo); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/LogisticsController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/LogisticsController.java new file mode 100644 index 0000000..62f8fea --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/LogisticsController.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.controller; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.validation.constraints.NotNull; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.zhishu.domain.Logistics; +import org.dromara.zhishu.domain.bo.LogisticsBo; +import org.dromara.zhishu.domain.bo.TLogisticsBo; +import org.dromara.zhishu.service.LogisticsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/logistics") +public class LogisticsController { + + @Autowired + private LogisticsService logisticsService; + +// @SaCheckPermission("zhishu:shop:export") + @Log(title = "", businessType = BusinessType.EXPORT) + @PostMapping("/logistics") + @SaIgnore + public void export(@RequestBody LogisticsBo bo) { + Integer num= logisticsService.insert(bo); + if(num>0){ + System.out.println("插入成功"); + } + } + @GetMapping("/select") + @SaIgnore + public List getLogistics(@RequestParam String warehouseId) { + List logistics = logisticsService.selectLogistics(warehouseId); + return logistics; + } + @GetMapping("/logistics/{id}") + @SaIgnore + public Logistics getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id){ + return logisticsService.queryById(id); + } + /** + * 修改物流管理 + */ +// @SaCheckPermission("logistics:logistics:edit") + @Log(title = "修改物流模版", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/logistics") + public R edit(@Validated(EditGroup.class) @RequestBody LogisticsBo bo) { + Boolean num= logisticsService.setTemplate(bo); +// return toAjax(.updateByBo(bo)); + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/NewUserController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/NewUserController.java new file mode 100644 index 0000000..44206f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/NewUserController.java @@ -0,0 +1,125 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +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.common.core.validate.AddGroup; +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.web.core.BaseController; +import org.dromara.zhishu.domain.CardResult; +import org.dromara.zhishu.domain.LicenseResult; +import org.dromara.zhishu.domain.bo.NewUserBo; +import org.dromara.zhishu.service.ITDepotService; +import org.dromara.zhishu.service.NewUserService; +import org.dromara.zhishu.util.OcrUtil; +import org.dromara.zhishu.util.UploadUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + + +import com.tencentcloudapi.common.AbstractModel; + +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.ocr.v20181119.OcrClient; +import com.tencentcloudapi.ocr.v20181119.models.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.Base64; + + +@Validated +@RequiredArgsConstructor +@RestController + @RequestMapping("/system/newUser") +public class NewUserController extends BaseController { + + @Autowired + private final NewUserService newUserService; + + @Autowired + private OcrUtil ocrUtil; + + + + + @SaIgnore +//@SaCheckPermission("system:user:newuser") +@Log(title = "申请入驻", businessType = BusinessType.INSERT) +@RepeatSubmit() +@PostMapping +public R add(@Validated(AddGroup.class) @RequestBody NewUserBo newUserBo) { + return toAjax(newUserService.insertByBo(newUserBo)); +} + + +//身份证验证 +@PostMapping("/cardRedirect") +public R cardRedirect(@RequestParam("file") MultipartFile file) { + CardResult cardResult = new CardResult(); + try { + OcrClient client = ocrUtil.upload(file); + // 实例化一个请求对象,每个接口都会对应一个request对象 + IDCardOCRRequest req = new IDCardOCRRequest(); + // base64图片字节数组 + req.setEnableDateVerify(true); + req.setImageBase64(Base64.getEncoder().encodeToString(file.getBytes())); + // 返回的resp是一个IDCardOCRResponse的实例,与请求对象对应 + IDCardOCRResponse resp = client.IDCardOCR(req); + cardResult.setName(resp.getName()); + cardResult.setSex(resp.getSex()); + cardResult.setNation(resp.getNation()); + cardResult.setAddress(resp.getAddress()); + cardResult.setBirth(resp.getBirth()); + cardResult.setIdNum(resp.getIdNum()); + cardResult.setAuthority(resp.getAuthority()); + cardResult.setValidDate(resp.getValidDate()); + cardResult.setUrl(UploadUtil.upload(file,"user")); + } catch (TencentCloudSDKException e) { + cardResult.setMessage(e.getMessage()); + } catch (IOException e) { + throw new RuntimeException(e); + } + return R.ok(cardResult); +} + +//营业执照验证 +@PostMapping("/licenseRedirect") +public R licenseRedirect(@RequestParam("file") MultipartFile file) { + LicenseResult licenseResult = new LicenseResult(); + try { + OcrClient client = ocrUtil.upload(file); + // 实例化一个请求对象,每个接口都会对应一个request对象 + BizLicenseOCRRequest req = new BizLicenseOCRRequest(); + req.setImageBase64(Base64.getEncoder().encodeToString(file.getBytes())); + // 返回的resp是一个BizLicenseOCRResponse的实例,与请求对象对应 + BizLicenseOCRResponse resp = client.BizLicenseOCR(req); + licenseResult.setAddress(resp.getAddress()); + licenseResult.setBusiness(resp.getBusiness()); + licenseResult.setCapital(resp.getCapital()); + licenseResult.setName(resp.getName()); + String[] period = resp.getPeriod().split("至"); + if(period[1].contains("长期")||period[1].contains("永久")){ + period[1]=null; + } + licenseResult.setPeriod(period[1]); + licenseResult.setRegistrationAuthority(resp.getRegistrationAuthority()); + licenseResult.setRegNum(resp.getRegNum()); + licenseResult.setPerson(resp.getPerson()); + licenseResult.setUrl(UploadUtil.upload(file,"user")); + } catch (TencentCloudSDKException e) { + licenseResult.setMessage(e.getMessage()); + } catch (IOException e) { + throw new RuntimeException(e); + } + return R.ok(licenseResult); +} +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/NoticeController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/NoticeController.java new file mode 100644 index 0000000..6ab6474 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/NoticeController.java @@ -0,0 +1,129 @@ +package org.dromara.zhishu.controller; + +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.common.satoken.utils.LoginHelper; +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.NoticeVo; +import org.dromara.zhishu.domain.bo.NoticeBo; +import org.dromara.zhishu.service.INoticeService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 消息通知 + * + * @author yxy + * @date 2025-05-17 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/notice") +public class NoticeController extends BaseController { + + private final INoticeService noticeService; + + /** + * 查询消息通知列表 + */ + @SaCheckPermission("zhishu:notice:list") + @GetMapping("/list") + public TableDataInfo list(NoticeBo bo, PageQuery pageQuery) { + bo.setRecipient(LoginHelper.getUserId().toString()); + return noticeService.queryPageList(bo, pageQuery); + } + + /** + * 导出消息通知列表 + */ + @SaCheckPermission("zhishu:notice:export") + @Log(title = "消息通知", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(NoticeBo bo, HttpServletResponse response) { + List list = noticeService.queryList(bo); + ExcelUtil.exportExcel(list, "消息通知", NoticeVo.class, response); + } + + /** + * 获取消息通知详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:notice:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(noticeService.queryById(id)); + } + + /** + * 新增消息通知 + */ + @SaCheckPermission("zhishu:notice:add") + @Log(title = "消息通知", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody NoticeBo bo) { + return toAjax(noticeService.insertByBo(bo)); + } + + /** + * 修改消息通知 + */ + @SaCheckPermission("zhishu:notice:edit") + @Log(title = "消息通知", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody NoticeBo bo) { + return toAjax(noticeService.updateByBo(bo)); + } + + /** + * 删除消息通知 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:notice:remove") + @Log(title = "消息通知", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(noticeService.deleteWithValidByIds(List.of(ids), true)); + } + + + @SaIgnore + @PostMapping("/addNotice") + public void addNotice(@RequestBody Map map){ +// System.out.println("新增通知:"+map); + String msg = (String) map.get("msg"); + String userId = (String) map.get("userId"); + String isbn = (String) map.get("isbn"); + String bookName = (String) map.get("bookName"); + String sender = map.get("sender") == null ? "系统" : (String) map.get("sender"); + NoticeBo notice = new NoticeBo(); + notice.setSender(sender); + notice.setRecipient(userId); + notice.setContent("自动发布商品失败原因:"+msg+" ISBN:"+isbn+" 商品名称:"+bookName); + notice.setStatus("0"); + notice.setCreateBy(Long.parseLong(userId)); + notice.setTenantId("000000"); + noticeService.insertByBo(notice); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/OrderExternalGoodsController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/OrderExternalGoodsController.java new file mode 100644 index 0000000..634e12b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/OrderExternalGoodsController.java @@ -0,0 +1,433 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +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.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.bo.SysDictDataBo; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.service.ISysDictDataService; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; +import org.dromara.zhishu.domain.dto.OrderExternalGoodsDto; +import org.dromara.zhishu.domain.vo.FastMailVo; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; +import org.dromara.zhishu.service.IFastMailService; +import org.dromara.zhishu.service.IOrderExternalGoodsService; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.dromara.zhishu.util.*; +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; + +/** + * 仓库订单 + * + * @author yxy + * @date 2025-12-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/orderExternalGoods") +public class OrderExternalGoodsController { + + private final IOrderExternalGoodsService orderExternalGoodsService; + private final ISysDictDataService dictDataService; + private final IZhishuShopGoodsService zhishuShopGoodsService; + private final IFastMailService fastMailService; + + + @GetMapping("/getU") + public Long getUserId(){ + return LoginHelper.getUserId(); + } + + /** + * 查询仓库订单列表 + */ + @SaCheckPermission("zhishu:orderExternalGoods:list") + @GetMapping("/list") + public TableDataInfo list(OrderExternalGoodsDto dto, PageQuery pageQuery) { + Map params = new HashMap<>(); + params.put("pageNum",pageQuery.getPageNum()); + params.put("pageSize",pageQuery.getPageSize()); + params.put("deptUseId", LoginHelper.getUserId()); + params.put("erpAfterSalesStatus",dto.getErpAfterSalesStatus()); + if(dto.getErpAfterSalesStatus() != 0){ + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + params.put("createBy",userId); + } + } + + if (dto.getOrderStatus() != null){ + params.put("orderStatus",dto.getOrderStatus()); + } + + if (dto.getConfirmStatus() != null){ + params.put("confirmStatus",dto.getConfirmStatus()); + } + + if (dto.getAfterSalesStatus() != null){ + params.put("afterSalesStatus",dto.getAfterSalesStatus()); + } + + if (dto.getTrackingNumber() != null){ + params.put("trackingNumber",dto.getTrackingNumber()); + } + + if (StringUtils.isNotEmpty(dto.getOrderSn())){ + params.put("orderSn",dto.getOrderSn()); + } + if (dto.getShopType() != null){ + params.put("shopType",dto.getShopType()); + } + if (dto.getShopErpId() != null){ + params.put("shopErpId",dto.getShopErpId()); + } + if (StringUtils.isNotEmpty(dto.getItemList())){ + params.put("itemList",dto.getItemList()); + } + + if(!dto.getParams().isEmpty()){ + params.put("startTime",dto.getParams().get("startTime")); + params.put("endTime",dto.getParams().get("endTime")); + } + + String OrderExternalGoodsVoListStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/orderExternalGoods/getList",params); + Map dataMap = JsonUtil.transferToObj(OrderExternalGoodsVoListStr,Map.class); + List OrderExternalGoodsVoList = (List) dataMap.get("data"); + + for (Object object : OrderExternalGoodsVoList){ + Map orderExternalGoodsVo = (Map) object; + String goodsId = orderExternalGoodsVo.get("goodsId") == null ? "" : orderExternalGoodsVo.get("goodsId").toString(); + if (StringUtils.isNotEmpty(goodsId)){ + // 获取货号 + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.queryById(goodsId); + if (zhishuShopGoodsVo != null){ + orderExternalGoodsVo.put("shopGoodsVo",zhishuShopGoodsVo); + }else{ + orderExternalGoodsVo.put("shopGoodsVo",null); + } + } + + } + + int total = (int) dataMap.get("total"); + Page result = new Page<>(pageQuery.getPageNum(),pageQuery.getPageSize(),total); + result.setRecords(OrderExternalGoodsVoList); + return TableDataInfo.build(result); + } + + /** + * 查询仓库订单列表 + */ + @GetMapping("/appList") + @SaIgnore + public TableDataInfo appList(OrderExternalGoodsDto dto, PageQuery pageQuery) { + Map params = new HashMap<>(); + params.put("pageNum",pageQuery.getPageNum()); + params.put("pageSize",pageQuery.getPageSize()); + params.put("deptUseId", dto.getCreateBy()); + params.put("erpAfterSalesStatus",dto.getErpAfterSalesStatus()); + + if (StringUtils.isNotEmpty(dto.getOrderSn())){ + params.put("orderSn",dto.getOrderSn()); + } + if (dto.getShopType() != null){ + params.put("shopType",dto.getShopType()); + } + if (dto.getOrderStatus() != null){ + params.put("orderStatus",dto.getOrderStatus()); + } + if(dto.getStartTime() != null){ + params.put("startTime",dto.getStartTime()); + } + if(dto.getEndTime() != null){ + params.put("endTime",dto.getEndTime()); + } + if(dto.getWhetherOutbound() != null){ + params.put("whetherOutbound",dto.getWhetherOutbound()); + } + if (StringUtils.isNotEmpty(dto.getArtNo()) || StringUtils.isNotEmpty(dto.getOriginalArtNo()) || StringUtils.isNotEmpty(dto.getIsbn())){ + ZhishuShopGoodsBo bo = new ZhishuShopGoodsBo(); + bo.setUserId(Long.parseLong(params.get("deptUseId").toString())); + bo.setIsQueryAllGoods(dto.getIsQueryAllGoods()); + if(StringUtils.isNotEmpty(dto.getArtNo())){ + bo.setArtNo(dto.getArtNo()); + } + if (StringUtils.isNotEmpty(dto.getOriginalArtNo())){ + bo.setOriginalArtNo(dto.getOriginalArtNo()); + } + if (StringUtils.isNotEmpty(dto.getIsbn())){ + bo.setIsbn(dto.getIsbn()); + } + List zhishuShopGoodsVoList = zhishuShopGoodsService.queryList(bo); + if (zhishuShopGoodsVoList.isEmpty()){ + // 如果根据货号未查询到数据,则直接返回空 + Page result = new Page<>(pageQuery.getPageNum(),pageQuery.getPageSize(),0); + return TableDataInfo.build(result); + }else{ + params.put("goodsId",zhishuShopGoodsVoList.get(0).getId()); + } + } + + String OrderExternalGoodsVoListStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/orderExternalGoods/getList",params); + Map dataMap = JsonUtil.transferToObj(OrderExternalGoodsVoListStr,Map.class); + List OrderExternalGoodsVoList = (List) dataMap.get("data"); + + for (int i =0 ;i result = new Page<>(pageQuery.getPageNum(),pageQuery.getPageSize(),total); + result.setRecords(OrderExternalGoodsVoList); + return TableDataInfo.build(result); + } + + + @PostMapping("/editWhetherOutbound") + @SaIgnore + public Map editWhetherOutbound(String ids){ + Map map = new HashMap(); + map.put("ids",ids); + String result = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/orderExternalGoods/editWhetherOutbound",map); + return JsonUtil.transferToObj(result,Map.class); + } + + /** + * 快递单号匹配快递公司 + * @param trackingNumber + * @return + */ + @GetMapping("/getCompanyInfo") + public String getCompanyInfo(String trackingNumber){ + ExpressCompanyDetector.ExpressInfo expressInfo = ExpressCompanyDetector.detect(trackingNumber); + return expressInfo.getCode(); + } + + /** + * 发货按钮 + * @param map + * @return + */ + @PostMapping("/submitCompanyOrder") + @SaIgnore + public R submitCompanyOrder(@RequestBody Map map){ + // 快递公司名称 +// String dictLabel = dictDataService.selectDictLabel("t_fast_mail_type",map.get("code").toString()); +// map.put("companyName",dictLabel); + + SysDictDataBo bo = new SysDictDataBo(); + bo.setDictType("t_fast_mail_type"); + List sysDictDataVoList = dictDataService.selectDictDataList(bo); + map.put("sysDictDataVoListStr",JsonUtil.transferToJson(sysDictDataVoList)); +// String json = JsonUtil.transferToJson( map); +// String result = DllInitializer.executeInterfaceForward("POST",UrlUtil.getOrderServiceUrl() + "/api/erpGoodsOrder/orderCompanyOrder",json); + String result = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/orderCompanyOrder",map); + System.out.println(result); + return R.ok(); + } + + + @PostMapping("/process") + public Map process(@RequestBody Map map){ + System.out.println(map); + Map requestMap = new HashMap(); + requestMap.put("id",map.get("erpOrderId").toString()); + if(null != map.get("erpAssReason") && StringUtils.isNotEmpty(map.get("erpAssReason").toString())){ + requestMap.put("erpAfterSalesStatus","6"); + requestMap.put("erpAssReason",map.get("erpAssReason").toString()); + }else if(null != map.get("rollbackType") && map.get("rollbackType").toString().equals("5")){ + // 延迟处理 + requestMap.put("erpAfterSalesStatus",map.get("rollbackType")); + } else{ + // 1 同意 2 失败 + String handlingMethod = map.get("handlingMethod").toString(); + if(handlingMethod.equals("1")){ + // 同意售后 + // 回退类型 3 仅退款 2 退货退款 + String rollbackType = map.get("rollbackType").toString(); + requestMap.put("erpAfterSalesStatus",rollbackType); + if(rollbackType.equals("3")){ + // 同意仅退款:售后完成 + }else if(rollbackType.equals("2")){ + // 同意退货退款:待仓库确认收货 + requestMap.put("erpAssAddress",map.get("returnAddress")); + }else{ + // 其他 + R.fail("未知异常"); + } + }else if(handlingMethod.equals("2")){ + // 拒绝售后 + requestMap.put("erpAfterSalesStatus","4"); + requestMap.put("erpAssRemark",map.get("reasonForRejection")); + }else{ + // 其他 + R.fail("未知异常"); + } + } + + String result = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/orderExternalGoods/editAfterSales",requestMap); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + return resultMap; + } + + + @GetMapping("/getErpAfterSalesOrderLog") + @SaIgnore + public List getErpAfterSalesOrderLog(String orderNo){ + String erpOrderLogListStr = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/getErpOrderLog?orderNo="+orderNo+"_erpAfterSalesOrder"); + List erpOrderLogList = JsonUtil.transferToObj(erpOrderLogListStr,List.class); + return erpOrderLogList; + } + + + /** + * + * @param erpOrderId 订单id + * @param fastMailId 快递账号id + * @param printTemplateData 打印模板数据 + * @param type 快递类型 + * @param deliveryMode 发货模式 1 全部发货 2 单独发货 + * @return + */ + @GetMapping("/orderCreate") + public R orderCreate(String erpOrderId,String fastMailId,String printTemplateData,String type,String erpGoodsId,String deliveryMode,String orderSn){ + FastMailVo fastMailVo = fastMailService.queryById(Long.parseLong(fastMailId)); + if (fastMailVo.getFastMailType().equals("1")){ + if (type.equals("YUNDA")){ + return orderExternalGoodsService.getYundaPdf(fastMailVo,erpOrderId,printTemplateData,type,deliveryMode,orderSn); + }else if (type.equals("ZTO")){ + return orderExternalGoodsService.getZtoPdf(fastMailVo,erpOrderId,printTemplateData,type,deliveryMode,orderSn); + }else if (type.equals("YZXB") || type.equals("JTSD")){ + return orderExternalGoodsService.orderCreate(fastMailVo,erpOrderId,printTemplateData,type,deliveryMode,orderSn); + }else { + return R.fail("无快递:"+type); + } + }else{ + Map res = new HashMap(); + res.put("fastMailVo",JsonUtil.transferToJson(fastMailVo)); + res.put("erpOrderId",erpOrderId); + res.put("deliveryMode",deliveryMode); + res.put("orderSn",orderSn); + String result = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/print/pddCreateOrder",res); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + resultMap.put("fastMailType","2"); + resultMap.put("code",fastMailVo.getType()); + // 获取商品数据 + List> dataMapList = new ArrayList<>(); + List erpGoodsOrderList = (List) resultMap.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); + } + resultMap.put("dataList",dataMapList); + return R.ok(resultMap); + } + } + + /** + * 获取韵达预览pdf + * @param erpOrderId + * @param orderSn + * @param deliveryMode + * @param printTemplateData + * @return + */ + @GetMapping("/getYunDaPreviewPdf") + public R getYunDaPreviewPdf(String erpOrderId,String orderSn,String deliveryMode,String printTemplateData){ + Map res = new HashMap(); + + Map erpGoodsOrderMap = new HashMap(); + erpGoodsOrderMap.put("orderId",erpOrderId); + erpGoodsOrderMap.put("orderSn",orderSn); + erpGoodsOrderMap.put("deliveryMode",deliveryMode); + + String data = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/getOrderData",erpGoodsOrderMap); + Map dataMap = JsonUtil.transferToObj(data,Map.class); + List> dataMapList = new ArrayList<>(); + List erpGoodsOrderList = (List) dataMap.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 goodsMap = new HashMap(); + goodsMap.put("isbn",zhishuShopGoodsVo.getIsbn()); + goodsMap.put("goodsName",itemMap.get("goodsName")); + goodsMap.put("artNo",zhishuShopGoodsVo.getArtNo()); + goodsMap.put("originalArtNo",zhishuShopGoodsVo.getOriginalArtNo()); + goodsMap.put("goodsCount",itemMap.get("goodsCount")); + dataMapList.add(goodsMap); + } + // 收件人信息 + Map receiver = (Map) dataMap.get("receiver"); + // 发件人信息 + Map sender = (Map) dataMap.get("sender"); + String yundaPdf = DaDanUtil.getYunDaPreview(); + res.put("code","200"); + res.put("msg","快递单获取成功"); + res.put("pdfInfo",yundaPdf); + res.put("receiver",receiver); + res.put("sender",sender); + res.put("dataList",dataMapList); + res.put("printTemplateData",printTemplateData); + return R.ok(res); + } + + + /** + * 运单取消 + */ + @GetMapping("/cancelBmOrder") + public R cancelBmOrder(String erpOrderId){ + String res = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/print/cancelBmOrder?erpOrderId="+erpOrderId); + Map resMap = JsonUtil.transferToObj(res,Map.class); + if (resMap.get("code").equals("200")){ + return R.ok(resMap.get("msg").toString()); + }else{ + return R.fail(resMap.get("msg").toString()); + } + } + + @GetMapping("/printView") + public R printView(String erpOrderId){ + String res = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/print/printView?erpOrderId="+erpOrderId); + Map resMap = JsonUtil.transferToObj(res,Map.class); + if (resMap.get("code").equals("200")){ + return R.ok(resMap); + }else{ + return R.fail(resMap.get("msg").toString()); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PddController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PddController.java new file mode 100644 index 0000000..b6e1783 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PddController.java @@ -0,0 +1,1478 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSONObject; +import com.opencsv.CSVReader; +import com.opencsv.CSVReaderBuilder; +import com.opencsv.CSVWriter; +import com.opencsv.exceptions.CsvValidationException; +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.PddGoodsListGetRequest; +import com.pdd.pop.sdk.http.api.pop.request.PddPopAuthTokenRefreshRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddGoodsListGetResponse; +import com.pdd.pop.sdk.http.api.pop.response.PddGoodsSpecGetResponse; +import com.pdd.pop.sdk.http.api.pop.response.PddMallInfoGetResponse; +import com.pdd.pop.sdk.http.api.pop.response.PddPopAuthTokenRefreshResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.config.RuoYiConfig; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.PddUtil; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +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.PddShopInfo; + +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.TUserPlatform; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.dto.ErpGoodsDto; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.dto.SuccessDataKfz; +import org.dromara.zhishu.domain.dto.request.RenovateOnSaleRequest; +import org.dromara.zhishu.domain.dto.request.UpdateShopGoodsDataPriceCSVRequest; +import org.dromara.zhishu.domain.dto.response.PddTokenResponse; +import org.dromara.zhishu.domain.vo.AccessTokenVo; +import org.dromara.zhishu.domain.vo.MessageSubscribeVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.TaskVo; +import org.dromara.zhishu.mapper.TUserPlatformMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.client.FileClient; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.service.client.PddClient; +import org.dromara.zhishu.service.impl.RunningTaskByShopServiceImpl; +import org.dromara.zhishu.util.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.AbstractView; +import org.springframework.web.servlet.view.RedirectView; + +import java.io.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static cn.dev33.satoken.SaManager.log; +import static org.dromara.zhishu.util.InterfaceUtils.getInterface; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/huidiao/pdd") +public class PddController { + + private final IPddService pddService; + private final IShopService shopService; + private final RuoYiConfig ruoYiConfig; + private final ISysConfigService configService; + private final TShopMessageSubscribeService tShopMessageSubscribeService; + private final HttpServletRequest httpServletRequest; + private final ITUserPlatformService userPlatformService; + private final ITaskService taskService; + private final IZhishuShopGoodsService zhishuShopGoodsService; + private final IRunningTaskService runningTaskService; + private final IRunningTaskByShopService runningTaskByShopService; + private final PddClient pddClient; + @Autowired + private TUserPlatformMapper userPlatformMapper; + @Autowired + private KfzClient kfzClient; + + + private final FileClient fileClient; + + + // 授权页面url + String url = "https://fuwu.pinduoduo.com/service-market/auth"; + String clientId = PddUtil.getClientId(); + String clientSecret = PddUtil.getClientSecret(); + // 回调url + String redirectUri = "https://test.api.buzhiyushu.cn/huidiao/pdd"; + @Autowired + private RunningTaskByShopServiceImpl runningTaskByShopServiceImpl; + + + /** + * 拼多多回调调用方法,获取code + * + * @param code + * @param state 自定义参数,返回的是店铺id + */ + @SaIgnore + @GetMapping + public ModelAndView getCode(String code, String state, HttpServletResponse response) { + try { + if (state == null) { + state = "000000-2-null"; + } + System.out.println("\n\n==================== 拼多多授权回调开始 ===================="); + System.out.println("拼多多授权回调开始处理 - code: " + code + ", state: " + state); + + // 记录请求头信息 + System.out.println("请求头信息:"); + Enumeration headerNames = httpServletRequest.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + String headerValue = httpServletRequest.getHeader(headerName); + System.out.println(" " + headerName + ": " + headerValue); + } + + // 记录请求参数 + System.out.println("请求参数:"); + Enumeration parameterNames = httpServletRequest.getParameterNames(); + while (parameterNames.hasMoreElements()) { + String paramName = parameterNames.nextElement(); + String paramValue = httpServletRequest.getParameter(paramName); + System.out.println(" " + paramName + ": " + paramValue); + } + + String[] stateArr = state.split("-"); + state = stateArr[0]; + String type = stateArr[1]; + String userId = stateArr[2]; + System.out.println("解析state参数 - state: " + state + ", type: " + type); + + if (code == null || StringUtils.isEmpty(code)) { + System.out.println("授权参数无效 - code: " + code + ", state: " + state); + // 根据type参数决定跳转页面 + if ("2".equals(type)) { + return new ModelAndView(new RedirectView("https://erp.buzhiyushu.cn/login")); + } else { + return new ModelAndView(new RedirectView("https://" + ruoYiConfig.getIpurl() + "/shop/shop")); + } + } + + if ("2".equals(type)) { + System.out.println("开始处理用户注册流程"); + try { + String encodedCode = URLEncoder.encode(code, "UTF-8"); + String redirectUrl = "https://erp.newadmin.buzhiyushu.cn/redirectUrl?code=" + encodedCode; + return new ModelAndView(new RedirectView(redirectUrl)); + + } catch (Exception e) { + log.error("URL编码失败", e); + System.out.println("URL编码失败: " + e.getMessage()); + // 如果编码失败,使用默认店铺名称 + String encodedCode = URLEncoder.encode(code, "UTF-8"); + String redirectUrl = "https://erp.newadmin.buzhiyushu.cn/redirectUrl?code=" + encodedCode; + System.out.println("使用默认店铺名称跳转: " + redirectUrl); + + // 同样使用JavaScript跳转 + String htmlContent = "" + + "" + + "" + + "" + + "正在跳转..." + + "" + + "" + + "
正在跳转到注册页面...
" + + "
" + + "" + + ""; + + ModelAndView mav = new ModelAndView(); + mav.setView(new AbstractView() { + @Override + protected void renderMergedOutputModel(Map model, + HttpServletRequest request, HttpServletResponse response) throws Exception { + response.setContentType("text/html;charset=UTF-8"); + response.getWriter().write(htmlContent); + response.getWriter().flush(); + } + }); + return mav; + } + + } + + String pddIp = configService.selectConfigByKey("pdd.ip"); + System.out.println("获取拼多多IP配置: " + pddIp); + + String accessTokenVoString = getInterface(pddIp, "/api/pdd/auth/getAccessToken/" + code); + AccessTokenVo accessTokenVo = JSONObject.parseObject(accessTokenVoString, AccessTokenVo.class); + String accessToken = accessTokenVo.getAccessToken(); + System.out.println("获取accessToken成功: " + accessToken); + + // 获取店铺信息 + Long id = 0L; + if (StringUtils.isNotEmpty(state)) { + id = Long.parseLong(state); + } + String pddMallInfoGetResponseStr = getInterface(pddIp, "/api/pdd/auth/getMallInfo/" + accessToken); + + PddMallInfoGetResponse pddMallInfoGetResponse = JsonUtils.parseObject(pddMallInfoGetResponseStr, PddMallInfoGetResponse.class); + // 获取拼多多店铺ID和名称 + String pddMallId = String.valueOf(pddMallInfoGetResponse.getMallInfoGetResponse().getMallId()); + String pddMallName = pddMallInfoGetResponse.getMallInfoGetResponse().getMallName(); + System.out.println("获取店铺信息成功 - 店铺ID: " + pddMallId + ", 店铺名称: " + pddMallName); + // 根据三方店铺id查询修改 + ShopVo shopVo = shopService.selectByMallId(pddMallId); + if (shopVo != null) { + ShopBo bo = new ShopBo(); + bo.setId(shopVo.getId()); + bo.setToken(accessToken); + shopService.updateByBo(bo); + } + // 到期时间 + Date expirationTime; + // 服务版本 + String skuSpec; + // 获取店铺订阅服务 + String vasData = getInterface(pddIp, "/api/pdd/auth/getVasOrder?mallId=" + pddMallId); + Map vasMap = JsonUtil.transferToObj(vasData, Map.class); + if (vasMap.get("code").equals("200")) { + // 成功 调用新后台 + 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); + + skuSpec = vas.get("skuSpec").toString(); + try { + InterfaceUtils.getInterfacePost("https://newadmin.buzhiyushu.cn/", "/vas/addVas", vas); + } catch (Exception e) { + System.out.println("调用新后台存储订阅服务信息失败"); + } + + + } else if (vasMap.get("code").equals("401")) { + // 未订阅服务的情况,直接跳转购买页 + return new ModelAndView(new RedirectView("https://fuwu.pinduoduo.com/service-market/service-detail?detailId=90559")); + } else { + String alertMessage = vasMap.get("msg").toString(); + String htmlContent = "提示" + + "" + + ""; + + ModelAndView mav = new ModelAndView(); + mav.setView(new AbstractView() { + @Override + protected void renderMergedOutputModel(Map model, + HttpServletRequest request, HttpServletResponse response) throws Exception { + response.setContentType("text/html;charset=UTF-8"); + response.getWriter().write(htmlContent); + response.getWriter().flush(); + } + }); + return mav; + } + + if ("3".equals(type)) { + // 添加拼多多店铺 + if (shopVo != null && !shopVo.getId().equals(id)) { + // 存在店铺 + // 动态生成空白页并显示alert消息 + String alertMessage = "您的拼多多店铺已绑定!!!"; + String htmlContent = "提示" + + "" + + ""; + + ModelAndView mav = new ModelAndView(); + mav.setView(new AbstractView() { + @Override + protected void renderMergedOutputModel(Map model, + HttpServletRequest request, HttpServletResponse response) throws Exception { + response.setContentType("text/html;charset=UTF-8"); + response.getWriter().write(htmlContent); + response.getWriter().flush(); + } + }); + return mav; + } else { + ShopBo shopBo = new ShopBo(); + shopBo.setShopName(pddMallName); + shopBo.setToken(accessToken); + shopBo.setMallId(Long.valueOf(pddMallId)); + shopBo.setShopAliasName(pddMallName); + shopBo.setShopAuthorize("1"); + shopBo.setExpirationTime(expirationTime); + shopBo.setSkuSpec(skuSpec); + shopBo.setShopGroup("默认分组"); + shopBo.setShopType("1"); + shopBo.setAddTime(DateUtils.parseDate(DateUtils.getTime())); + shopBo.setCreateBy(Long.parseLong(userId)); + shopBo.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + shopBo.setTenant_id("000000"); + shopService.insertByBo(shopBo); + // 赋值id + id = shopBo.getId(); + // 生成用户与店铺绑定关系 + TUserPlatform userPlatform = new TUserPlatform(); + userPlatform.setType("1"); // 拼多多 + userPlatform.setUserId(Long.parseLong(userId)); + userPlatform.setPlatformId(pddMallId); + userPlatform.setPlatformName(pddMallName); + userPlatform.setStatus("0"); + userPlatform.setDelFlag("0"); + userPlatform.setTenantId("000000"); + userPlatform.setCreateBy(Long.parseLong(userId)); + userPlatform.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + userPlatformService.insertTUserPlatform(userPlatform); + } + } else if ("4".equals(type)) { + try { + System.out.println("调用新后台type" + type); + Map params = new HashMap<>(); + params.put("accessToken", accessToken); + params.put("pddMallId", pddMallId); + params.put("pddMallName", pddMallName); + InterfaceUtils.postForm("https://newadmin.buzhiyushu.cn/", "/shop/token", params); + ShopVo shopVo1 = shopService.selectByMallId(pddMallId); + if (shopVo1 != null) { + shopService.updateTokenByPddMallId(pddMallId, accessToken); + } else { + ShopBo shopBo = new ShopBo(); + shopBo.setId(id); + shopBo.setMallId(Long.valueOf(pddMallId)); + shopBo.setToken(accessToken); + shopBo.setShopAliasName(pddMallName); + shopBo.setShopAuthorize("1"); + shopBo.setExpirationTime(expirationTime); + shopBo.setSkuSpec(skuSpec); + shopService.selectShopAssociationMall(shopBo); + } + return new ModelAndView(new RedirectView("https://erp.newadmin.buzhiyushu.cn/shop/list")); + } catch (Exception e) { + System.out.println("调用新后台存储订阅服务信息失败"); + } + } else if ("5".equals(type)) { + + } else { + // 根据pddMallId查询是否存在相同数据 + if (shopVo != null && !shopVo.getId().equals(id)) { + // 动态生成空白页并显示alert消息 + String alertMessage = "扫码的拼多多店铺与erp绑定的店铺信息不匹配!!!"; + String htmlContent = "提示" + + "" + + ""; + + ModelAndView mav = new ModelAndView(); + mav.setView(new AbstractView() { + @Override + protected void renderMergedOutputModel(Map model, + HttpServletRequest request, HttpServletResponse response) throws Exception { + response.setContentType("text/html;charset=UTF-8"); + response.getWriter().write(htmlContent); + response.getWriter().flush(); + } + }); + return mav; + } else { + ShopBo shopBo = new ShopBo(); + shopBo.setId(id); + shopBo.setMallId(Long.valueOf(pddMallId)); + shopBo.setToken(accessToken); + shopBo.setShopAliasName(pddMallName); + shopBo.setShopAuthorize("1"); + shopBo.setExpirationTime(expirationTime); + shopBo.setSkuSpec(skuSpec); + shopService.selectShopAssociationMall(shopBo); + } + } + + // 处理订阅消息 + System.out.println("开始处理订阅消息"); + MessageSubscribeVo messageSubscribeVo = accessTokenVo.getMessageSubscribeVo(); + tShopMessageSubscribeService.insertOrUpdate(List.of(messageSubscribeVo), id); + System.out.println("订阅消息处理完成"); + + return new ModelAndView(new RedirectView("https://" + ruoYiConfig.getIpurl() + "/shop/shop")); + + } catch (Exception e) { + log.error("拼多多授权回调处理失败", e); + System.out.println("拼多多授权回调处理异常: " + e.getMessage()); + e.printStackTrace(); + throw new RuntimeException(e); + } finally { + System.out.println("==================== 拼多多授权回调结束 ====================\n\n"); + } + } + + + + /** + * 根据token授权店铺 + * + * @param code 授权码 有效期10分钟 + */ + @SaIgnore + @GetMapping("/tokenSq") + public R tokenSq(String code, HttpServletResponse response) { + try { + System.out.println("\n\n==================== 拼多多授权token码授权开始 ===================="); + Long userId = LoginHelper.getUserId(); + String pddIp = configService.selectConfigByKey("pdd.ip"); + System.out.println("获取拼多多IP配置: " + pddIp); + // 获取店铺信息 + String accessTokenVoString = getInterface(pddIp, "/api/pdd/auth/getAccessToken/" + code); + AccessTokenVo accessTokenVo = JSONObject.parseObject(accessTokenVoString, AccessTokenVo.class); + String accessToken = accessTokenVo.getAccessToken(); + String pddMallInfoGetResponseStr = getInterface(pddIp, "/api/pdd/auth/getMallInfo/" + accessToken); + PddMallInfoGetResponse pddMallInfoGetResponse = JsonUtils.parseObject(pddMallInfoGetResponseStr, PddMallInfoGetResponse.class); + if(pddMallInfoGetResponse.getErrorResponse() != null){ + String subMsg = pddMallInfoGetResponse.getErrorResponse().getSubMsg(); + if(subMsg.equals("access_token已过期")){ + return R.fail("授权码已过期"); + }else{ + return R.fail(subMsg); + } + } + // 获取拼多多店铺ID和名称 + String pddMallId = String.valueOf(pddMallInfoGetResponse.getMallInfoGetResponse().getMallId()); + String pddMallName = pddMallInfoGetResponse.getMallInfoGetResponse().getMallName(); + System.out.println("获取店铺信息成功 - 店铺ID: " + pddMallId + ", 店铺名称: " + pddMallName); + // 到期时间 + Date expirationTime; + // 服务版本 + String skuSpec; + // 获取店铺订阅服务 + String vasData = getInterface(pddIp, "/api/pdd/auth/getVasOrder?mallId=" + pddMallId); + Map vasMap = JsonUtil.transferToObj(vasData, Map.class); + if (vasMap.get("code").equals("200")) { + // 成功 调用新后台 + 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); + skuSpec = vas.get("skuSpec").toString(); + try { + InterfaceUtils.getInterfacePost("https://newadmin.buzhiyushu.cn/", "/vas/addVas", vas); + } catch (Exception e) { + System.out.println("调用新后台存储订阅服务信息失败"); + } + }else { + return R.fail(vasMap.get("msg").toString()); + } + // 根据三方店铺id查询修改 + ShopVo shopVo = shopService.selectByMallId(pddMallId); + if (shopVo != null) { + //判断是否绑定在自己账号下 + if(shopVo.getCreateBy().equals(userId)){ + ShopBo bo = new ShopBo(); + bo.setId(shopVo.getId()); + bo.setToken(accessToken); + bo.setExpirationTime(expirationTime); + bo.setSkuSpec(skuSpec); + bo.setShopAuthorize("1"); + bo.setUpdateTime(DateUtils.parseDate(DateUtils.getTime())); + shopService.updateByBo(bo); + }else{ + ShopBo bo = new ShopBo(); + bo.setId(shopVo.getId()); + bo.setToken(accessToken); + shopService.updateByBo(bo); + return R.fail("店铺已被其他账户绑定"); + } + }else{ + // 添加拼多多店铺 + ShopBo shopBo = new ShopBo(); + shopBo.setShopName(pddMallName); + shopBo.setToken(accessToken); + shopBo.setMallId(Long.valueOf(pddMallId)); + shopBo.setShopAliasName(pddMallName); + shopBo.setShopAuthorize("1"); + shopBo.setExpirationTime(expirationTime); + shopBo.setSkuSpec(skuSpec); + shopBo.setShopGroup("默认分组"); + shopBo.setShopType("1"); + shopBo.setAddTime(DateUtils.parseDate(DateUtils.getTime())); + shopBo.setCreateBy(userId); + shopBo.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + shopBo.setTenant_id("000000"); + shopService.insertByBo(shopBo); + // 赋值id + Long id = shopBo.getId(); + // 生成用户与店铺绑定关系 + TUserPlatform userPlatform = new TUserPlatform(); + userPlatform.setType("1"); // 拼多多 + userPlatform.setUserId(userId); + userPlatform.setPlatformId(pddMallId); + userPlatform.setPlatformName(pddMallName); + userPlatform.setStatus("0"); + userPlatform.setDelFlag("0"); + userPlatform.setTenantId("000000"); + userPlatform.setCreateBy(userId); + userPlatform.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + userPlatformService.insertTUserPlatform(userPlatform); + // 处理订阅消息 + System.out.println("开始处理订阅消息"); + tShopMessageSubscribeService.insertOrUpdate(List.of(accessTokenVo.getMessageSubscribeVo()), id); + System.out.println("订阅消息处理完成"); + } + return R.ok("授权成功"); + } catch (Exception e) { + return R.fail("授权码无效"); + } finally { + System.out.println("==================== 拼多多授权token码授权开始 ====================\n\n"); + } + } + + @SaIgnore + @GetMapping("/getPddToken") + public R getPddToken(@NotBlank(message = "code不能为空") String code) { + String pddIp = configService.selectConfigByKey("pdd.ip"); + System.out.println("获取拼多多IP配置: " + pddIp); + + String accessTokenVoString = getInterface(pddIp, "/api/pdd/auth/getAccessToken/" + code); + AccessTokenVo accessTokenVo = JSONObject.parseObject(accessTokenVoString, AccessTokenVo.class); + String accessToken = accessTokenVo.getAccessToken(); + System.out.println("获取accessToken成功: " + accessToken); + + String pddMallInfoGetResponseStr = getInterface(pddIp, "/api/pdd/auth/getMallInfo/" + accessToken); + + PddMallInfoGetResponse pddMallInfoGetResponse = JsonUtils.parseObject(pddMallInfoGetResponseStr, PddMallInfoGetResponse.class); + // 获取拼多多店铺ID和名称 + String pddMallId = String.valueOf(pddMallInfoGetResponse.getMallInfoGetResponse().getMallId()); + String pddMallName = pddMallInfoGetResponse.getMallInfoGetResponse().getMallName(); + System.out.println("获取店铺信息成功 - 店铺ID: " + pddMallId + ", 店铺名称: " + pddMallName); + // 根据三方店铺id查询修改 + ShopVo shopVo = shopService.selectByMallId(pddMallId); + if (shopVo != null) { + ShopBo bo = new ShopBo(); + bo.setId(shopVo.getId()); + bo.setToken(accessToken); + shopService.updateByBo(bo); + return R.fail("店铺已存在"); + } + + // 到期时间 + Date expirationTime; + // 服务版本 + String skuSpec = ""; + // 获取店铺订阅服务 + String vasData = getInterface(pddIp, "/api/pdd/auth/getVasOrder?mallId=" + pddMallId); + Map vasMap = JsonUtil.transferToObj(vasData, Map.class); + if (vasMap.get("code").equals("200")) { + // 成功 调用新后台 + 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); + + skuSpec = vas.get("skuSpec").toString(); + try { + InterfaceUtils.getInterfacePost("https://newadmin.buzhiyushu.cn/", "/vas/addVas", vas); + } catch (Exception e) { + System.out.println("调用新后台存储订阅服务信息失败"); + } + } + PddTokenResponse pddTokenResponse = new PddTokenResponse(); + pddTokenResponse.setAccessToken(accessToken); + pddTokenResponse.setPddMallId(pddMallId); + pddTokenResponse.setPddMallName(pddMallName); + pddTokenResponse.setSkuSpec(skuSpec); + return R.ok(pddTokenResponse); + } + + + /** + * 前往拼多多授权登录页面 + * + * @return + */ +// @SaCheckPermission("zhishu:authorize:getCode") + @GetMapping("/toPddGetCode") + @SaIgnore + public String toPddGetCode(String id, String type) { + + Long userId = LoginHelper.getUserId(); + + if (StringUtils.isEmpty(id)) { + type = "3"; + } + + String redirectUri = configService.selectConfigByKey("pdd.redirect.url"); + + String authorizationUrl = url + + "?response_type=code" + + "&client_id=" + clientId + + "&redirect_uri=" + redirectUri + + "&state=" + id + "-" + type + "-" + userId; + + return authorizationUrl; + } + + + /** + * 获取商品运费模版接口 + */ + @GetMapping("/getLogisticsTemplate/{shopId}") + public List getLogisticsTemplate(@PathVariable Long shopId, HttpServletRequest request) { + try { + Map headers = PddResultUtil.getPddHeaderMap(request); + + ShopVo shopVo = shopService.queryById(shopId); + String pddIp = configService.selectConfigByKey("pdd.ip"); + String logisticsTemplateListStr = getInterface(pddIp, "/api/pdd/auth/getLogisticsTemplate/" + shopVo.getToken(), headers); + List list = JsonUtils.parseObject(logisticsTemplateListStr, List.class); + return list; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @GetMapping("/getPageCode/{mallId}") + public String getPageCode(@PathVariable("mallId") String mallId) { + try { + String pddIp = configService.selectConfigByKey("pdd.ip"); + return getInterface(pddIp, "/api/pdd/auth/getPageCode/" + mallId); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 商品标准类目接口 + */ + @GetMapping("/getCats") + public ArrayList> getCats(HttpServletRequest request) { + Map headers = PddResultUtil.getPddHeaderMap(request); + // 从文件中获取数据字符串 + Map map; + ArrayList> mapList = new ArrayList<>(); + String content = RedisUtils.getCacheObject("catsMapStr"); + if (content == null || StringUtils.isEmpty(content)) { + String pddIp = configService.selectConfigByKey("pdd.ip"); + String catsMapStr = getInterface(pddIp, "/api/pdd/auth/getCats", headers); + RedisUtils.setCacheObject("catsMapStr", catsMapStr); + } + map = JsonUtils.parseObject(content, Map.class); + mapList.add(map); + return mapList; + } + + /** + * 商品属性类目接口 + */ + @GetMapping("/getSpec/{shopId}") + public List getSpec(@PathVariable String shopId, HttpServletRequest request) throws Exception { + Map headers = PddResultUtil.getPddHeaderMap(request); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + String pddIp = configService.selectConfigByKey("pdd.ip"); + String goodsSpecListStr = getInterface(pddIp, "/api/pdd/auth/getSpec/" + shopVo.getToken(), headers); + return JsonUtils.parseObject(goodsSpecListStr, List.class); + } + + + /** + * 从拼多多商铺获取商品信息 + */ + @PostMapping("/selPddShop") + public PddGoodsListGetResponse selPddShop(@RequestBody PddShopInfo search) throws Exception { + return this.pddGetGoods(search); + } + + + public PddGoodsListGetResponse pddGetGoods(PddShopInfo search) throws Exception { + + PopClient client = new PopHttpClient(clientId, clientSecret); + PddGoodsListGetRequest request = new PddGoodsListGetRequest(); +// request.setCostTemplateId(1L); // 模版Id +// request.setCreatedAtEnd(1654099200L); // 商品创建时间结束时间的时间戳 +// request.setCreatedAtFrom(1654012800L); // 商品创建时间开始时间的时间戳 + request.setGoodsName("中国"); // 商品名称模糊查询 + request.setIsOnsale(0); // 上下架状态,0-下架,1-上架 +// request.setOuterGoodsId("1"); //商家外部商品编码,支持多个,用逗号隔开,最多10个 +// request.setOuterId("str"); // 商品外部编码 + request.setPage(1); // 返回页码 默认 1 + request.setPageSize(10); // 返回数量,默认 100,最大100 + PddGoodsListGetResponse response = client.syncInvoke(request, PddUtil.getToken()); + System.out.println(JsonUtil.transferToJson(response)); + return response; + } + + + // 超时 + public void tokenCs() { + // 获取所有已授权店铺的token + List shopIds = shopService.getShopId(LoginHelper.getUserId()); + for (String shopId : shopIds) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + if (shopVo == null) { + continue; + } + // 获取店铺的token + String token = shopVo.getToken(); + // 获取店铺的授权过期时间 + Date expirationTime = shopVo.getExpirationTime(); + // 校验店铺过期时间是否超过当前时间 + if (expirationTime.getTime() < System.currentTimeMillis()) { + // 店铺已过期,进行注销操作 + System.out.println("店铺授权已过期,进行超时操作"); + // 2代表授权已过期 + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setStatus("2"); + shopService.updateByBo(shopBo); + } + } + } + + // 更新 + public void updateShop(Long shopId) throws Exception { + // 获取店铺信息 + ShopVo shopVo = shopService.queryById(shopId); + // 获取刷新token + String refreshToken = shopVo.getRefreshToken(); + String clientId = PddUtil.getClientId(); + String clientSecret = PddUtil.getClientSecret(); + + PopClient client = new PopHttpClient(clientId, clientSecret); + PddPopAuthTokenRefreshRequest request = new PddPopAuthTokenRefreshRequest(); + request.setRefreshToken(refreshToken); + PddPopAuthTokenRefreshResponse response = client.syncInvoke(request); + System.out.println(JsonUtil.transferToJson(response)); + + // 获取刷新后的token,重新赋值给店铺 + String token = response.getPopAuthTokenRefreshResponse().getAccessToken(); + + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + shopBo.setToken(token); + shopService.updateByBo(shopBo); + } + + + // 删除店铺处理 + public void deleteShop(Long shopId) { + // 将店铺注销,并清空token + ShopVo shopVo = shopService.queryById(shopId); + ShopBo shopBo = new ShopBo(); + shopBo.setId(shopVo.getId()); + // 店铺注销,进行注销操作 + shopBo.setStatus("3"); + // 清空token 操作 + shopBo.setToken("0"); + shopService.updateByBo(shopBo); + } + + @GetMapping("/getShopGoodsTotalNum") + @SaIgnore + public R getShopGoodsTotalNum(String shopId, Integer isOnsale) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + String pddIp = configService.selectConfigByKey("pdd.ip"); + String url = "/api/pdd/auth/getShopGoodsList?" + + "accessToken=" + shopVo.getToken(); + if (isOnsale != null) { + url += "&isOnsale=" + isOnsale; + } + String dataStr = getInterface(pddIp, url + "&page=1&pageSize=100"); + Map dataMap = JsonUtil.transferToObj(dataStr, Map.class); + Integer totalCount = dataMap.get("total_count") == null ? 0 : Integer.parseInt(dataMap.get("total_count").toString()); + return R.ok(totalCount); + } + + @GetMapping("/createShopGoodsList") + @SaIgnore + public R createShopGoodsList(String shopId, Long createdAtFrom, Long createdAtEnd, Integer isOnsale, Integer sycFlag,String account, String password) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 判断是2-孔网店铺还是1-拼多多店铺 + String shopType = shopVo.getShopType(); + TaskBo taskBo = new TaskBo(); + // 存储任务信息 + if (Objects.equals(shopType, "1") || Objects.equals(shopType, "5")) { + if (shopType.equals("5")){ + List shopVoList = shopService.selectListByMallId(shopVo.getMallId()); + for (ShopVo shop : shopVoList){ + // 根据shopId查询数据表是否存在 + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shop.getId()); + if (checkMark == 0) { + // 不存在则创建表 + runningTaskByShopService.createTable("t_running_task_" + shop.getId()); + } + runningTaskByShopService.deleteAll("t_running_task_"+shop.getId()); + } + } + taskBo.setTaskType("GET_SHOP_GOODS"); + taskBo.setFileName("拉取商品任务"); + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count","1"); + // 任务类型 + createMap.put("task_type","3"); + // img_type 必须传1 + createMap.put("img_type","1"); + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (!createResMap.get("code").equals("200")){ + return R.fail(createResMap.get("msg").toString()); + } + return R.ok("创建同步任务成功,请前往任务列表查看任务进度"); + } + return R.fail("店铺类型错误"); + } + + /** + * 继续执行拉取任务 + * @param shopId + * @return + */ + @GetMapping("/continueGetGoodsTask") + @SaIgnore + public R continueGetGoodsTask(String taskId,String shopId){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + String shopType = shopVo.getShopType(); + if (Objects.equals(shopType, "1")) { + TaskVo taskVo = taskService.queryById(Long.parseLong(taskId)); + String tableName = "t_running_task_" + shopId; + String lastFinishTimeStr = runningTaskByShopService.selectLastFinishTime(tableName); + + + for (int i = 0; i < 10; i++){ + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + System.out.println("休息异常"); + } + String lastFinishTimeStrMark = runningTaskByShopService.selectLastFinishTime(tableName); + if (StringUtils.isEmpty(lastFinishTimeStr) || StringUtils.isEmpty(lastFinishTimeStrMark)){ + return R.fail("任务已经执行完毕"); + } + if(!lastFinishTimeStr.equals(lastFinishTimeStrMark)){ + return R.fail("任务正在运行中"); + } + } + + // 时间格式转换 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + // 将字符串时间转换为Date对象 + Date lastFinishTime = sdf.parse(lastFinishTimeStr); + // 获取秒级时间戳 + long lastFinishTimestamp = lastFinishTime.getTime() / 1000; + + // 计算一个月后的时间 + Calendar calendar = Calendar.getInstance(); + calendar.setTime(lastFinishTime); + calendar.add(Calendar.DATE, 29); // 增加29天 + Date oneMonthLater = calendar.getTime(); + // 获取一个月后的秒级时间戳 + long oneMonthLaterTimestamp = oneMonthLater.getTime() / 1000; + // 获取当前时间的秒级时间戳 + long currentTimestamp = System.currentTimeMillis() / 1000; + + // 如果一个月后的时间大于当前时间,则使用当前时间作为结束时间 + long endTimestamp = oneMonthLaterTimestamp; + if (oneMonthLaterTimestamp > currentTimestamp) { + endTimestamp = currentTimestamp; + } + + String startTime = String.valueOf(lastFinishTimestamp); + String endTime = String.valueOf(endTimestamp); + + Map mapData = new HashMap(); + mapData.put("taskId", taskId); + mapData.put("shopId", shopId); + mapData.put("shopType", shopVo.getShopType()); + mapData.put("token", shopVo.getToken()); +// mapData.put("isOnsale", isOnsale == null ? "" : isOnsale.toString()); + if(taskVo.getFileName().contains("详细")){ + mapData.put("taskType", "2"); + }else{ + mapData.put("taskType", "1"); + } + mapData.put("startTime", startTime); + mapData.put("endTime", endTime); + mapData.put("serviceName","GET_SHOP_GOODS"); + // 调用接口 + InterfaceUtils.postForm(UrlUtil.getShopGoodsTaskUrl(), "/task/verifyPricePublishGoods", mapData); +// InterfaceUtils.postForm("http://localhost:18099", "/task/verifyPricePublishGoods", mapData); + } catch (ParseException e) { + // 时间解析异常处理 + e.printStackTrace(); + return R.fail("时间格式解析错误"); + } + return R.ok("任务继续"); + }else{ + return R.ok("目前只支持拼多多店铺"); + } + } + + @GetMapping("/createTask") + @SaIgnore + public R createTask (String shopId){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 判断是2-孔网店铺还是1-拼多多店铺 + String shopType = shopVo.getShopType(); + TaskBo taskBo = new TaskBo(); + taskBo.setTaskType("GET_KW_SHOP_GOODS"); + taskBo.setFileName("拉取孔网商品任务"); + taskBo.setShopIds(shopId); + taskBo.setShopNames(shopVo.getShopName()); + taskBo.setDataNum(0L); + taskBo.setTaskStatus("0"); + taskBo.setCreateBy(shopVo.getCreateBy()); + taskService.insertByBo(taskBo); + return R.ok("true", taskBo.getId().toString()); + } + + + @SaCheckPermission("zhishu:pddGoods:tongbu") + @GetMapping("/createShopGoodsDetailList") + @SaIgnore + public R createShopGoodsDetailList(String shopId, Long createdAtFrom, Long createdAtEnd, Integer isOnsale) { + 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","1"); + // 任务类型 + createMap.put("task_type","4"); + // img_type 必须传1 + createMap.put("img_type","1"); + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (!createResMap.get("code").equals("200")){ + return R.fail(createResMap.get("msg").toString()); + } + return R.ok("创建同步任务成功,请前往任务列表查看任务进度"); + } + + + @GetMapping("/createShopGoodsmovie") + @SaIgnore + public R createShopGoodsmovie(String shopId, Long createdAtFrom, Long createdAtEnd, Integer isOnsale,String targetShopIds) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + TaskBo taskBo = new TaskBo(); + // 存储任务信息 + taskBo.setTaskType("GET_MOVE_GOODS"); + taskBo.setFileName("拼多多店铺搬家"); + taskBo.setShopIds(shopId); + taskBo.setShopNames(shopVo.getShopName()); + taskBo.setDataNum(0L); + taskBo.setTaskStatus("0"); + taskService.insertByBo(taskBo); + + // 异步执行任务 + ThreadPoolUtils.execute(() -> { + pddService.sendPddGoodsToTargetShop(shopId, targetShopIds,taskBo,shopVo); + }); + + + return R.ok("创建同步任务成功,请前往任务列表查看任务进度"); + } + + + + + @GetMapping("/getShopGoodsList") + @SaIgnore + public TableDataInfo> getShopGoodsList(String shopId, String isOnsale,String isbn, + String priceDown,String priceUp,String startDate, + String endDate, Integer page, Integer pageSize, + String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode) { + return pddService.getShopGoodsList(shopId, isOnsale,isbn,priceDown,priceUp,startDate,endDate, page, pageSize,goodsName,stockDown,stockUp, trilateralId, goodsCode, skuCode); + } + + @GetMapping("/delShopGoods") + public R delShopGoods(String shopId, String isOnsale,String isbn,String priceDown,String priceUp,String startDate,String endDate){ + String shopName = ""; + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + shopName = shopVo.getShopName(); + + //任务列表中添加删除操作记录 + + TaskBo taskBo = new TaskBo(); + //存储任务信息 + taskBo.setTaskType("DEL"); + taskBo.setFileName("删除店铺商品列表"); + taskBo.setShopIds(shopId); + taskBo.setShopNames(shopName); + taskBo.setDataNum(runningTaskByShopServiceImpl.countAll("t_running_task_" + shopId).longValue()); + taskBo.setTaskStatus("3"); + taskService.insertByBo(taskBo); + + pddService.clearRedisBuffer(shopId); + + runningTaskByShopServiceImpl.delShopGoods("t_running_task_" + shopId, isOnsale,isbn,priceDown,priceUp,startDate,endDate); + return R.ok(); + } + + + /** + * 导出商品列表 + * + * @param + * @param + * @param response + */ + @PostMapping("/emportShopGoods") + @SaIgnore + public void emportShopGoods(ErpGoodsDto erpGoodsDto, HttpServletResponse response) { + erpGoodsDto.setTableName("t_running_task_" + erpGoodsDto.getShopId()); + List list = runningTaskByShopServiceImpl.selectShopGoodsList(erpGoodsDto); + ExcelUtil.exportExcel(list, "sheet", SuccessDataItemDto.class, response); + } + + /** + * 孔夫子专用导出商品列表 + * @param erpGoodsDto + * @param response + */ + @PostMapping("/emportKfzShopGoods") + @SaIgnore + public void emportKfzShopGoods(ErpGoodsDto erpGoodsDto, HttpServletResponse response) { + erpGoodsDto.setTableName("t_running_task_" + erpGoodsDto.getShopId()); + List list = runningTaskByShopServiceImpl.selectKfzShopGoodsList(erpGoodsDto); + ExcelUtil.exportExcel(list, "sheet", SuccessDataKfz.class, response); + } + + + @GetMapping("/checkFile") + public Boolean checkFile(String shopId) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + + int numMark = 0; + + String filePath = "ShopGoodsDataCSV/" + shopVo.getMallId() + "/" + numMark + ".csv"; + // 通过FileClient获取文件内容(Base64格式) + R dataResult = fileClient.get(UrlUtil.getFileServiceUrl(), filePath, "base64"); + + return R.isSuccess(dataResult); + } + + /** + * 一键上下架功能 + */ + @PostMapping("/editShopGoodsAllByIsOnSale") + public R editShopGoodsAllByIsOnSale(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) { + String[] shopIds = shopId.split(","); + List errorMessages = new ArrayList<>(); + List successMessages = new ArrayList<>(); + for (String shopIdStr : shopIds) { + try { + // 获取店铺信息 + ShopVo shopVo = shopService.queryById(Long.parseLong(shopIdStr)); + if (shopVo == null) { + errorMessages.add("店铺" + shopIdStr + "不存在"); + continue; + } + + int num = runningTaskByShopService.checkTableExists("t_running_task_" + shopIdStr); + String isOnsaleStr = isOnSale.equals("0") ? "下架" : "上架"; + // 检查表是否存在 + if (num == 0) { + errorMessages.add("店铺" + shopIdStr + "请先同步店铺商品"); + continue; + } + + if (!shopVo.equals("1")){ + // 检查是否存在正在进行的任务 + Long markNum = runningTaskService.selectTaskStatusByTaskTypeAndIsbn(Long.parseLong(shopIdStr), "EDIT_ISONSALE_GOODS", isbn); + if (markNum > 0) { + errorMessages.add("店铺" + shopIdStr + "正在执行商品上下架操作,请稍后再试"); + continue; + } + } + + // 检查符合条件的商品数量 + int count = runningTaskByShopService.selectGetShopGoodsListCount("t_running_task_" + shopIdStr, isOnSale.equals("0") ? "1" : "0", isbn, priceDown, priceUp, startDate, endDate,goodsName,stockDown,stockUp,trilateralId,goodsCode,skuCode); + if (count == 0) { + errorMessages.add("店铺" + shopIdStr + "没有符合条件的商品"); + continue; + } + // 创建任务 + TaskBo taskBo = new TaskBo(); + // 拼多多执行新任务 + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count",count+""); + createMap.put("task_type","5"); + createMap.put("img_type","1"); + String createResStr = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/task/create",createMap); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + if (createResMap.get("code").equals("500")){ + errorMessages.add("店铺" + shopIdStr + "创建任务异常:"+createResMap.get("msg").toString()); + continue; + }else{ + taskBo.setId(Long.parseLong(createResMap.get("data").toString())); + } + + // 异步执行任务 + new Thread(() -> { + pddService.editShopGoodsAllByIsOnSale(shopVo, taskBo, isOnSale, isbn, priceDown, priceUp, startDate, endDate, goodsName, stockDown, stockUp, trilateralId, goodsCode, skuCode); + }).start(); + successMessages.add("店铺" + shopIdStr + "(" + shopVo.getShopName() + ")创建" + isOnsaleStr + "任务成功"); + } catch (Exception e) { + errorMessages.add("店铺" + shopIdStr + "处理异常: " + e.getMessage()); + log.error("处理店铺{}时发生异常", shopIdStr, e); + } + } + // if (!skipMessages.isEmpty()) { + // if (resultMessage.length() > 0) resultMessage.append("\n"); + // resultMessage.append("跳过处理:").append(String.join(";", skipMessages)).append("。"); + // } + // if (!errorMessages.isEmpty()) { + // if (resultMessage.length() > 0) resultMessage.append("\n"); + // resultMessage.append("处理失败:").append(String.join(";", errorMessages)).append("。"); + // } + + // if (successMessages.isEmpty() && skipMessages.isEmpty()) { + // return R.fail(resultMessage.toString()); + // } + + if(!errorMessages.isEmpty()){ + errorMessages.addAll(successMessages); + return R.fail(errorMessages.toString()); + } + + return R.ok(successMessages.toString()); + } + + /** + * 获取商品核价文件下载链接 + */ + @SaIgnore + @GetMapping("/getVerifyPriceUrl") + public R getVerifyPriceUrl(String shopId) { + StringBuilder allContent = new StringBuilder(); + + String[] shopIds = shopId.split(","); + for (String shopIdStr : shopIds){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopIdStr)); + + if (shopVo == null) { + return R.fail("店铺不存在"); + } + + String filePath = "task_log/goods-list-csv/" + shopIdStr + "/online_goods.csv"; + // 通过FileClient获取文件内容(url格式) + R dataResult= dataResult= fileClient.get(UrlUtil.getFileServiceUrl(), filePath, "url"); + if (dataResult.isSuccess(dataResult) && dataResult.getData() != null) { + allContent.append(dataResult.getData()).append("\n"); + } + } + + return R.ok(allContent.toString()); + + // 通过FileClient获取文件内容(url格式) + + // + // if (R.isSuccess(dataResult)) { + // return R.ok("true", dataResult.getData()); + // } else { + // return R.fail("未查询到店铺商品,请重新同步后再试"); + // } + } + + /** + * 修改店铺商品CSV表格价格 + * + * @param request 修改商品价格请求参数 + * @return 修改成功状态 + */ + @SaIgnore + @PostMapping("/updateShopGoodsDataPriceCSV") + public R updateShopGoodsDataPriceCSV(@Validated @RequestBody UpdateShopGoodsDataPriceCSVRequest request) { + // 1. 构建文件路径 + String filePath = "ShopGoodsDataCSV/" + request.getMallId() + ".csv"; + + // 2. 获取CSV文件内容 + R dataResult = fileClient.get(UrlUtil.getFileServiceUrl(), filePath, "base64"); + if (!R.isSuccess(dataResult)) { + throw new ServiceException("获取文件失败"); + } + + // 3. 解码Base64并读取CSV内容 + byte[] decodedBytes = Base64.getDecoder().decode(dataResult.getData()); + String csvContent = new String(decodedBytes, StandardCharsets.UTF_8); + + // 4. 将请求中的商品列表转换为Map以便快速查找(key: platformId, value: SkuItem) + Map skuItemMap = request.getSkuItemList().stream() + .collect(Collectors.toMap( + UpdateShopGoodsDataPriceCSVRequest.SkuItem::getPlatformId, + Function.identity() + )); + + try (StringReader stringReader = new StringReader(csvContent); + CSVReader reader = new CSVReader(stringReader); + StringWriter writer = new StringWriter(); + CSVWriter csvWriter = new CSVWriter(writer)) { + + // 5. 读取CSV表头 + String[] header = reader.readNext(); + if (header == null) { + throw new ServiceException("CSV文件格式错误,缺少表头"); + } + + // 6. 查找关键列索引 + int goodsIdIndex = -1; + int isOnsaleIndex = -1; + int priceIndex = -1; + for (int i = 0; i < header.length; i++) { + switch (header[i]) { + case "goods_id": + goodsIdIndex = i; + break; + case "is_onsale": + isOnsaleIndex = i; + break; + case "price": + priceIndex = i; + break; + } + } + + if (goodsIdIndex == -1) { + throw new ServiceException("CSV文件缺少goods_id列"); + } + + // 7. 写入表头 + csvWriter.writeNext(header); + + // 8. 处理每一行数据 + String[] row; + while ((row = reader.readNext()) != null) { + try { + Long goodsId = Long.parseLong(row[goodsIdIndex]); + + // 检查当前商品是否需要修改 + if (skuItemMap.containsKey(goodsId)) { + UpdateShopGoodsDataPriceCSVRequest.SkuItem skuItem = skuItemMap.get(goodsId); + + // 修改is_onsale字段 + if (request.getIsOnSale() != null && isOnsaleIndex != -1) { + row[isOnsaleIndex] = request.getIsOnSale().toString(); + } + + // 修改price字段 + if (skuItem.getGroupPrice() != null && priceIndex != -1) { + row[priceIndex] = skuItem.getGroupPrice().toString(); + } + } + + // 写入处理后的行 + csvWriter.writeNext(row); + } catch (NumberFormatException e) { + log.error("解析goods_id失败,行内容: {}", Arrays.toString(row), e); + csvWriter.writeNext(row); // 解析失败时保留原行 + } + } + + // 9. 生成新的CSV内容并编码为Base64 + String newCsvContent = writer.toString(); + String newBase64Content = Base64.getEncoder().encodeToString(newCsvContent.getBytes(StandardCharsets.UTF_8)); + + // 10. 上传修改后的文件 + R uploadResult = fileClient.upload(UrlUtil.getFileServiceUrl(), newBase64Content, "ShopGoodsDataCSV", request.getMallId() + ".csv"); + if (!R.isSuccess(uploadResult)) { + throw new ServiceException("更新文件失败"); + } + + return R.ok(true); + } catch (Exception e) { + log.error("处理CSV文件失败", e); + throw new ServiceException("处理CSV文件失败:" + e.getMessage()); + } + } + + /** + * 批量设置商品下架 + * + * @return 批量设置成功状态 + */ + @SaIgnore + @PostMapping("/batchSetSoldOut/{shopId}") + public R batchSetSoldOut(@PathVariable("shopId") Long shopId) { + pddService.batchSetSoldOut(shopId); + return R.ok(true); + } + + // 批次大小 + private static final int BATCH_SIZE = 1000; + // 每个批次最大线程数 + private static final int MAX_THREADS_PER_BATCH = 10; + + /** + * 通过csv批量翻新商品上架拼多多 + * + * @param file 文件 + * @param shopId 店铺ID + * @return 响应 + */ + @SaIgnore + @PostMapping("/batchRenovateOnSaleByCsv") + public R batchRenovateOnSaleByCsv(@RequestParam("file") MultipartFile file, @NotBlank(message = "店铺Id不能为空") String shopId) { + // 判断是否上传了file文件 + if (file == null || file.isEmpty()) { + return R.fail("请上传文件"); + } + // 判断是否是csv文件 + String originalFilename = file.getOriginalFilename(); + if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".csv")) { + return R.fail("请上传CSV格式的文件"); + } + // 根据店铺查询店铺名称及token + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + if (shopVo == null) { + return R.fail("店铺不存在"); + } + + // 获取总条数 + Long totalCount = getCsvFileTotalCount(file); + + // 创建任务 + TaskBo taskBo = new TaskBo(); + // 存储任务信息 + taskBo.setTaskType("1"); + taskBo.setFileName("excel表格上传:批量翻新商品上架"); + taskBo.setShopIds(shopId); + taskBo.setShopNames(shopVo.getShopName()); + taskBo.setDataNum(totalCount); + taskBo.setTaskStatus("0"); + taskService.insertByBo(taskBo); + + // 调用方法异步处理文件数据 + pddService.batchRenovateOnSaleByCsv(file, taskBo, shopVo); + + return R.ok("已受理", true); + } + + // 使用 OpenCsv 获取文件总条数 + private Long getCsvFileTotalCount(MultipartFile file) { + long totalCount = 0; + try (Reader reader = new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8)) { + // OpenCSV 方式读取 CSV + CSVReader csvReader = new CSVReaderBuilder(reader) + .withSkipLines(0) // 不跳过任何行(默认) + .build(); + + // 遍历所有行并计数(不加载到内存) + while (csvReader.readNext() != null) { + totalCount++; + } + + // 如果文件有 header,需要减 1 + if (totalCount > 0) { + totalCount--; // 去掉 header 行 + } + } catch (IOException e) { + throw new ServiceException("读取CSV文件失败:" + e.getMessage()); + } catch (CsvValidationException e) { + throw new ServiceException("CSV格式验证失败:" + e.getMessage()); + } + return totalCount; + } + + /** + * 翻新单个商品上架拼多多 + * + * @return 响应 + */ + @SaIgnore + @PostMapping("/renovateOnSale") + public R renovateOnSale(@RequestBody RenovateOnSaleRequest request) { + pddService.renovateOnSale(request.getData(), request.getShopId(), request.getTaskId()); + return R.ok(Boolean.TRUE); + } + + + /** + * 检查店铺价格模板 + * @param shopId 店铺ID + * @return 价格模板信息 + */ + @GetMapping("/checkPriceTemplate") + public ResponseEntity> checkPriceTemplate(@RequestParam List shopId) { + Map result = new HashMap<>(); + + for (Long shopIdstr : shopId) { + String saleTemplateId = pddService.getSaleTemplateIdByShopId(shopIdstr); + result.put(shopIdstr, saleTemplateId); + } + + return ResponseEntity.ok(result); + } + + /** + * 获取商品核价文件下载链接 + */ + @SaIgnore + @GetMapping("/getPddChildrenBooksToken") + public JSONObject getPddChildrenBooksToken() { + JSONObject jsonObject = new JSONObject(); + String mailId = configService.selectConfigByKey("pdd_children_books_shopId"); + String pddIp = configService.selectConfigByKey("pdd.ip"); + ShopVo shopVo = shopService.queryByMailIdbyUseing(Long.parseLong(mailId),1); + if (shopVo==null){ + jsonObject.put("code", 500); + jsonObject.put("msg", "token已过期"); + return jsonObject; + } + //验证token是否过期 + String pddMallInfoGetResponseStr = getInterface(pddIp, "/api/pdd/auth/getMallInfo/" + shopVo.getToken()); + PddMallInfoGetResponse pddMallInfoGetResponse = JsonUtils.parseObject(pddMallInfoGetResponseStr, PddMallInfoGetResponse.class); + // 先检查主对象是否为null + if (pddMallInfoGetResponse == null) { + jsonObject.put("code", 500); + jsonObject.put("msg", "解析响应数据失败"); + return jsonObject; + } + if(pddMallInfoGetResponse.getErrorResponse()!=null){ + jsonObject.put("code", 500); + jsonObject.put("msg", pddMallInfoGetResponse.getErrorResponse().getErrorMsg()); + return jsonObject; + } + jsonObject.put("code", 200); + jsonObject.put("data", shopVo.getToken()); + jsonObject.put("msg", "获取成功"); + // 获取拼多多店铺ID和名称 + return jsonObject; + } + + + + @GetMapping("/getToken") + @SaIgnore + public String getToken(){ + return configService.selectConfigByKey("image.token"); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PddOrderContorller.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PddOrderContorller.java new file mode 100644 index 0000000..c6c42a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PddOrderContorller.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.controller; + +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 java.util.Date; + +public class PddOrderContorller { + + + +// //授权页面url +// String clientId = "203c5a7ba8bd4b8488d5e26f93052642"; +// String clientSecret = "892ffaa86e12b7a3d8d2942b669d9aa520ad8179"; + + + public static void main(String[] args) throws Exception { + + + //授权页面url + String clientId = "203c5a7ba8bd4b8488d5e26f93052642"; + String clientSecret = "892ffaa86e12b7a3d8d2942b669d9aa520ad8179"; +// String clientId = clientId; +// String clientSecret = "your clientSecret"; + String accessToken = "83b0b0e8aca14fba89e03ab42476dc7f403ffb39"; + +// String clientId = "your clientId"; +// String clientSecret = "your clientSecret"; +// String accessToken = "your accessToken"; + PopClient client = new PopHttpClient(clientId, clientSecret); + + PddOrderListGetRequest request = new PddOrderListGetRequest(); + request.setEndConfirmAt(1L); + request.setOrderStatus(5); + request.setPage(1); + request.setPageSize(100); + request.setRefundStatus(5); + request.setStartConfirmAt(1L); + request.setTradeType(1); + request.setUseHasNext(true); + PddOrderListGetResponse response = client.syncInvoke(request, accessToken); + System.out.println(JsonUtil.transferToJson(response)); + + + + + + Date date = new Date(); + + System.out.println(date.getTime()); + System.out.println("1742019835298".length()); + + + + + + + + + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PrintTemplateController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PrintTemplateController.java new file mode 100644 index 0000000..efa5478 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PrintTemplateController.java @@ -0,0 +1,116 @@ +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.PrintTemplateVo; +import org.dromara.zhishu.domain.bo.PrintTemplateBo; +import org.dromara.zhishu.service.IPrintTemplateService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 打印模板 + * + * @author yxy + * @date 2026-03-07 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/printTemplate") +public class PrintTemplateController extends BaseController { + + private final IPrintTemplateService printTemplateService; + + /** + * 查询打印模板列表 + */ + @SaCheckPermission("zhishu:printTemplate:list") + @GetMapping("/list") + public TableDataInfo list(PrintTemplateBo bo, PageQuery pageQuery) { + return printTemplateService.queryPageList(bo, pageQuery); + } + + /** + * 查询打印模板列表 + * @param bo + * @return + */ + @SaCheckPermission("zhishu:printTemplate:list") + @GetMapping("/listNoPage") + public List listNoPage(PrintTemplateBo bo){ + return printTemplateService.queryList(bo); + } + + /** + * 导出打印模板列表 + */ + @SaCheckPermission("zhishu:printTemplate:export") + @Log(title = "打印模板", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PrintTemplateBo bo, HttpServletResponse response) { + List list = printTemplateService.queryList(bo); + ExcelUtil.exportExcel(list, "打印模板", PrintTemplateVo.class, response); + } + + /** + * 获取打印模板详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:printTemplate:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(printTemplateService.queryById(id)); + } + + /** + * 新增打印模板 + */ + @SaCheckPermission("zhishu:printTemplate:add") + @Log(title = "打印模板", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody PrintTemplateBo bo) { + return toAjax(printTemplateService.insertByBo(bo)); + } + + /** + * 修改打印模板 + */ + @SaCheckPermission("zhishu:printTemplate:edit") + @Log(title = "打印模板", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody PrintTemplateBo bo) { + return toAjax(printTemplateService.updateByBo(bo)); + } + + /** + * 删除打印模板 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:printTemplate:remove") + @Log(title = "打印模板", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(printTemplateService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PrinterController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PrinterController.java new file mode 100644 index 0000000..2c5dbcd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/PrinterController.java @@ -0,0 +1,171 @@ +package org.dromara.zhishu.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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.zhishu.domain.bo.PrintTemplateBo; +import org.dromara.zhishu.domain.vo.PrintTemplateVo; +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.PrinterVo; +import org.dromara.zhishu.domain.bo.PrinterBo; +import org.dromara.zhishu.service.IPrinterService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 打印机设置 + * + * @author yxy + * @date 2026-03-06 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/printer") +public class PrinterController extends BaseController { + + private final IPrinterService printerService; + + /** + * 查询打印机设置列表 + */ + @SaCheckPermission("zhishu:printer:list") + @GetMapping("/list") + public TableDataInfo list(PrinterBo bo, PageQuery pageQuery) { + return printerService.queryPageList(bo, pageQuery); + } + + /** + * 查询全部打印机设置 + * @param bo + * @return + */ + @SaCheckPermission("zhishu:printer:list") + @GetMapping("/listNoPage") + public List listNoPage(PrinterBo bo){ + return printerService.queryList(bo); + } + + + /** + * 导出打印机设置列表 + */ + @SaCheckPermission("zhishu:printer:export") + @Log(title = "打印机设置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(PrinterBo bo, HttpServletResponse response) { + List list = printerService.queryList(bo); + ExcelUtil.exportExcel(list, "打印机设置", PrinterVo.class, response); + } + + /** + * 获取打印机设置详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:printer:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(printerService.queryById(id)); + } + + /** + * 新增打印机设置 + */ + @SaCheckPermission("zhishu:printer:add") + @Log(title = "打印机设置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody PrinterBo bo) { + if (bo.getPrintType().equals("2")){ + // 拼多多云打印机 + Map map = new HashMap(); + map.put("printerId",bo.getPrinter()); + map.put("verifyCode",bo.getCaptcha()); + map.put("accessToken",bo.getAccessToken()); + String res = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/pddCloudPrint/pddCloudPrinterBind",map); + try{ + Map resMap = JsonUtil.transferToObj(res,Map.class); + Map cloudPrinterBindresponse = (Map) resMap.get("cloud_printer_bind_response"); + Boolean success = (Boolean) cloudPrinterBindresponse.get("success"); + if (success){ + Map result = (Map) cloudPrinterBindresponse.get("result"); + bo.setShareCode(result.get("shareCode").toString()); + }else{ + return R.fail(cloudPrinterBindresponse.get("errorMsg").toString()); + } + }catch (Exception e){ + return R.fail(res); + } + } + + return toAjax(printerService.insertByBo(bo)); + } + + /** + * 修改打印机设置 + */ + @SaCheckPermission("zhishu:printer:edit") + @Log(title = "打印机设置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody PrinterBo bo) { + return toAjax(printerService.updateByBo(bo)); + } + + /** + * 删除打印机设置 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:printer:remove") + @Log(title = "打印机设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(printerService.deleteWithValidByIds(List.of(ids), true)); + } + + + /** + * 新增打印机设置 + */ + @GetMapping("/getCaptcha") + public R getCaptcha(PrinterBo bo) { + + + List voList = printerService.queryList(bo); + if (voList.size() > 0){ + return R.fail("该 "+bo.getPrinter()+" 打印机已被绑定"); + } + + Map map = new HashMap(); + map.put("printerId",bo.getPrinter()); + map.put("accessToken",bo.getAccessToken()); + String res = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/pddCloudPrint/pddCloudPrintVerifyCode",map); + try{ + Map resMap = JsonUtil.transferToObj(res,Map.class); + return R.ok(resMap); + }catch (Exception e){ + return R.fail(res); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ProductController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ProductController.java new file mode 100644 index 0000000..c30a25c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ProductController.java @@ -0,0 +1,72 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +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.zhishu.domain.SinglePrint; +import org.dromara.zhishu.domain.bo.SinglePrintBo; +import org.dromara.zhishu.service.IProductService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/product") +public class ProductController extends BaseController { + + private final IProductService productService; + + + @GetMapping("/getMappingList") + @SaIgnore + public Map getMappingList(){ + return productService.getMappingList(); + } + + /** + * 查询单票打印列表 + */ + @GetMapping("/list") + @SaIgnore + public TableDataInfo list(@RequestParam Map bo) { + return productService.queryPageList(bo); + } + + @PostMapping("/releaseGoods") + public R releaseGoods(@RequestBody Map map){ + // 异步执行 + CompletableFuture.runAsync(() -> { + productService.releaseGoods(map); + }); + return R.ok(); + } + + @PostMapping("/releaseGoodsAuto") + @SaIgnore + public R releaseGoodsAuto(@RequestParam Map map){ + try{ + // 用户id + String userId = map.get("userId").toString(); + // 仓库id + String warehouseId = map.get("warehouseId").toString(); + String productId = map.get("productId").toString(); + System.out.println("用户id:"+userId+";仓库id:"+warehouseId+";商品id:"+productId); + // 异步执行 + CompletableFuture.runAsync(() -> { + productService.releaseGoodsAuto(map); + }); + return R.ok(); + }catch (Exception e){ + return R.fail(e.getMessage()); + } + + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ProfitSharingLogController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ProfitSharingLogController.java new file mode 100644 index 0000000..f8a23da --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ProfitSharingLogController.java @@ -0,0 +1,40 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.ProfitSharingLog; +import org.dromara.zhishu.domain.bo.PriceTemplateBo; +import org.dromara.zhishu.domain.vo.PriceTemplateVo; +import org.dromara.zhishu.service.IProfitSharingLogService; +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; + +/** + * 分润日志表 + * + * @author yxy + * @date 2026-02-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/profitSharingLog") +public class ProfitSharingLogController { + + private final IProfitSharingLogService profitSharingLogService; + + /** + * 分页查询分润日志表 + */ +// @SaCheckPermission("zhishu:profitSharingLog:list") + @GetMapping("/list") + @SaIgnore + public TableDataInfo list(ProfitSharingLog bo, PageQuery pageQuery) { + return profitSharingLogService.queryPageList(bo, pageQuery); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/RunningLogFileController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/RunningLogFileController.java new file mode 100644 index 0000000..1483ad2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/RunningLogFileController.java @@ -0,0 +1,122 @@ +package org.dromara.zhishu.controller; + +import java.util.List; +import java.util.Map; + +import cn.dev33.satoken.annotation.SaIgnore; +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.zhishu.domain.bo.ViolationBo; +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.RunningLogFileVo; +import org.dromara.zhishu.domain.bo.RunningLogFileBo; +import org.dromara.zhishu.service.IRunningLogFileService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 程序运行日志表 + * + * @author yxy + * @date 2025-06-12 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/runningLogFile") +public class RunningLogFileController extends BaseController { + + private final IRunningLogFileService runningLogFileService; + + /** + * 查询程序运行日志表列表 + */ + @SaCheckPermission("zhishu:runningLogFile:list") + @GetMapping("/list") + public TableDataInfo list(RunningLogFileBo bo, PageQuery pageQuery) { + return runningLogFileService.queryPageList(bo, pageQuery); + } + + @SaIgnore + @PostMapping("/newList") + public String newList(@RequestBody Map map){ + Integer pageSize = Integer.parseInt(map.get("pageSize").toString()); + Integer pageNum = Integer.parseInt(map.get("pageNum").toString()); + + PageQuery pageQuery = new PageQuery(pageSize,pageNum); + + RunningLogFileBo bo = new RunningLogFileBo(); + + return JsonUtil.transferToJson(runningLogFileService.queryPageList(bo, pageQuery)); + } + + /** + * 导出程序运行日志表列表 + */ + @SaCheckPermission("zhishu:runningLogFile:export") + @Log(title = "程序运行日志表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(RunningLogFileBo bo, HttpServletResponse response) { + List list = runningLogFileService.queryList(bo); + ExcelUtil.exportExcel(list, "程序运行日志表", RunningLogFileVo.class, response); + } + + /** + * 获取程序运行日志表详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:runningLogFile:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(runningLogFileService.queryById(id)); + } + + /** + * 新增程序运行日志表 + */ + @SaCheckPermission("zhishu:runningLogFile:add") + @Log(title = "程序运行日志表", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody RunningLogFileBo bo) { + return toAjax(runningLogFileService.insertByBo(bo)); + } + + /** + * 修改程序运行日志表 + */ + @SaCheckPermission("zhishu:runningLogFile:edit") + @Log(title = "程序运行日志表", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody RunningLogFileBo bo) { + return toAjax(runningLogFileService.updateByBo(bo)); + } + + /** + * 删除程序运行日志表 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:runningLogFile:remove") + @Log(title = "程序运行日志表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(runningLogFileService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopController.java new file mode 100644 index 0000000..fd101f8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopController.java @@ -0,0 +1,691 @@ +package org.dromara.zhishu.controller; + +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +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 lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.extern.slf4j.Slf4j; +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.zhishu.domain.bo.EncryptionDataBo; +import org.dromara.zhishu.domain.bo.UserRechargeBo; +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.XyCategoryVo; +import org.dromara.zhishu.manager.TaskExecutorManager; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.impl.RunningTaskByShopServiceImpl; +import org.dromara.zhishu.service.impl.RunningTaskServiceImpl; +import org.dromara.zhishu.util.DateUtilsUtils; +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.ShopVo; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +import org.dromara.zhishu.mapper.ShopDepotMapper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.util.InterfaceUtils; + +/** + * 店铺主表 + * + * @author yxy + * @date 2025-03-10 + */ +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shop") +public class ShopController extends BaseController { + + private final IShopService shopService; + private final ISysConfigService configService; + private final IXyCategoryService xyCategoryService; + private final RunningTaskServiceImpl runningTaskServiceImpl; + private final TaskExecutorManager taskExecutorManager; + private final SysUserMapper sysUserMapper; + private final RunningTaskByShopServiceImpl runningTaskByShopServiceImpl; + private final ShopMapper shopMapper; + private final IUserRechargeService userRechargeService; + + + private static final String TODAY_GOODS_CACHE_KEY = "todayGoods:"; + private static final long CACHE_EXPIRE_MINUTES = 5; // 缓存5分钟 + + /** + * 查询店铺主表列表 + */ + @GetMapping("/list") + @SaIgnore + public TableDataInfo list(ShopBo bo, PageQuery pageQuery) { + return shopService.queryPageList(bo, pageQuery); + } + + @SaCheckPermission("zhishu:shop:list") + @GetMapping("/inviteList") + public TableDataInfo inviteList(ShopBo bo, PageQuery pageQuery) { + return shopService.queryPageListInvite(bo, pageQuery); + } + + @GetMapping("/getList") + public List getList() { + return shopService.queryList(new ShopBo()); + } + + @GetMapping("/getRunningShopList") + @SaIgnore + public List getRunningShopList(String taskType){ + List mapList = runningTaskServiceImpl.selectTaskGroupShop(taskType); + Iterator iterator = mapList.iterator(); + while (iterator.hasNext()) { + Map map = iterator.next(); + ShopVo shopVo = shopService.queryById(Long.parseLong(map.get("shop_id").toString())); + + if (shopVo == null) { + iterator.remove(); // 安全删除 + } else { + map.put("shopName", shopVo.getShopName()); + } + } + + return mapList; + } + + @GetMapping("/getJavaTaskPoolStatus") + @SaIgnore + public Map getJavaTaskPoolStatus() { + String bIp = "119.45.237.193"; + String es1Ip = "36.212.12.247"; + String url = "/task/metrics"; + + List> futures = Arrays.asList( + CompletableFuture.supplyAsync( + () -> runningTaskServiceImpl.getJavaTaskPool(bIp, "10046", url), + taskExecutorManager.getExecutor() + ).orTimeout(500, TimeUnit.SECONDS), // 设置5秒超时 + + CompletableFuture.supplyAsync( + () -> runningTaskServiceImpl.getJavaTaskPool(bIp, "10045", url), + taskExecutorManager.getExecutor() + ).orTimeout(500, TimeUnit.SECONDS), + + //新增节点 + CompletableFuture.supplyAsync( + () -> runningTaskServiceImpl.getJavaTaskPool(es1Ip, "10047", url), + taskExecutorManager.getExecutor() + ).orTimeout(500, TimeUnit.SECONDS), // 设置5秒超时 + + CompletableFuture.supplyAsync( + () -> runningTaskServiceImpl.getJavaTaskPool(es1Ip, "10048", url), + taskExecutorManager.getExecutor() + ).orTimeout(500, TimeUnit.SECONDS), // 设置5秒超时 + + CompletableFuture.supplyAsync( + () -> runningTaskServiceImpl.getJavaTaskPool(es1Ip, "10049", url), + taskExecutorManager.getExecutor() + ).orTimeout(500, TimeUnit.SECONDS), // 设置5秒超时 + + CompletableFuture.supplyAsync( + () -> runningTaskServiceImpl.getJavaTaskPool(es1Ip, "10050", url), + taskExecutorManager.getExecutor() + ).orTimeout(500, TimeUnit.SECONDS) + + ); + + // 处理结果,添加超时和异常处理 + List javaTaskPoolStatusList = new ArrayList<>(); + + for (CompletableFuture future : futures) { + try { + Map result = future.get(6, TimeUnit.SECONDS); // 总体超时6秒 + javaTaskPoolStatusList.add(result); + } catch (TimeoutException e) { + // 记录超时日志 + javaTaskPoolStatusList.add(createTimeoutResponse()); + } catch (Exception e) { + // 记录异常日志 + javaTaskPoolStatusList.add(createErrorResponse()); + } + } + + // 获取任务池各通道数据 + List shopMd5MapList = runningTaskServiceImpl.selectTaskByGroupShopMd5(); + + Map dataMap = new HashMap(); + dataMap.put("javaTaskPoolStatusList", javaTaskPoolStatusList); + dataMap.put("shopMd5MapList", shopMd5MapList); + return dataMap; + } + + private Map createTimeoutResponse() { + Map timeoutResponse = new HashMap<>(); + timeoutResponse.put("error", "请求超时"); + timeoutResponse.put("active", -2); + timeoutResponse.put("submitted", -2); + timeoutResponse.put("completed", -2); + timeoutResponse.put("shopMd5", "请求超时"); + return timeoutResponse; + } + + private Map createErrorResponse() { + Map errorResponse = new HashMap<>(); + errorResponse.put("error", "请求异常"); + errorResponse.put("active", -3); + errorResponse.put("submitted", -3); + errorResponse.put("completed", -3); + errorResponse.put("shopMd5", "请求异常"); + return errorResponse; + } + + + + /** + * 导出店铺主表列表 + */ + @SaCheckPermission("zhishu:shop:export") + @Log(title = "店铺主表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ShopBo bo, HttpServletResponse response) { + List list = shopService.queryList(bo); + ExcelUtil.exportExcel(list, "店铺主表", ShopVo.class, response); + } + + /** + * 获取闲鱼类目列表 + */ + @GetMapping("/getXyCategoryList") + public TableDataInfo getXyCategoryList() { + List list = xyCategoryService.selectXyCategoryList(); + return TableDataInfo.build(list); + } + + + /** + * 获取店铺主表详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shop:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(shopService.queryById(id)); + } + + @SaCheckPermission("zhishu:shop:query") + @GetMapping("/type/{type}") + public List getShopList (@PathVariable String type) { + Long userId = LoginHelper.getUserId(); + return shopService.queryByType(type, userId); + } + + /** + * 新增店铺主表 + */ + @SaCheckPermission("zhishu:shop:add") + @Log(title = "店铺主表", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ShopBo bo) { + Boolean mark = false; + +// bo.setShopExpirationTime(DateUtilsUtils.getNextMonths(Integer.parseInt(bo.getPayMonth()))); +// +// bo.setIsExpiration("1"); + + mark = shopService.insertByBo(bo); + + return toAjax(mark); + } + + /** + * 修改店铺主表 + */ + @SaCheckPermission("zhishu:shop:edit") + @Log(title = "店铺主表", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ShopBo bo) { + return toAjax(shopService.updateByBo(bo)); + } + + /** + * 删除店铺主表 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:shop:remove") + @Log(title = "店铺主表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(shopService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 获取店铺主表详细信息 + * + * @param id 主键 + */ + @SaIgnore + @GetMapping("/getShopInfo") + public ShopVo getShopInfo(@NotNull(message = "主键不能为空") Long id) { + return shopService.queryById(id); + } + + /** + * 根据三方店铺Id获取店铺主表详细信息 + * + * @param mailId 主键 + */ + @SaIgnore + @GetMapping("/getShopInfoByMailId") + public ShopVo getShopInfoByMailId(@NotNull(message = "主键不能为空") Long mailId, Integer shopType) { + Integer finalShopType = shopType == null ? 1 : shopType; + return shopService.queryByMailId(mailId, finalShopType); + + } + + /** + * 修改店铺订单更新时间 + * + * @param shopId + * @param startUpdatedAt + * @return + */ + @SaIgnore + @PutMapping("/updateTime") + public Boolean updateTime(@NotNull(message = "主键不能为空") Long shopId, @NotNull(message = "更新时间不能为空") Long startUpdatedAt) { + return shopService.updateTime(shopId, startUpdatedAt); + } + + /** + * 修改店铺是否开启订单状态 + * + * @param shopId + * @param status + * @return + */ + @SaIgnore + @PutMapping("/updateShopIsSynOrder") + public R updateShopIsSynOrder(@NotNull(message = "主键不能为空") Long shopId, @NotNull(message = "店铺订单同步状态不能为空") int status) { + return R.ok(shopService.updateShopIsSynOrder(shopId, status)); + } + + @SaIgnore + @PutMapping("/updateToken") + public Boolean updateToken(@RequestBody UpdateTokenRequest request) { + return shopService.updateToken(request); + } + + /** + * 获取万里牛店铺列表 + * + * @param shopId + * @return + */ + @SaIgnore + @GetMapping("/getWlnShopList") + public R> getWlnShopList(@NotNull(message = "页码不能为空") @RequestParam("page") Integer page, @NotNull(message = "条数不能为空") @RequestParam("limit") Integer limit, @NotNull(message = "店铺Id不能为空") @RequestParam("shopId") Long shopId, String shopNick) { + return R.ok(shopService.getWlnShopList(page, limit, shopId, shopNick)); + } + + /** + * 万里牛店铺授权 + * + * @param shopId + * @param shopName + * @param shopNick + * @return + */ + @SaIgnore + @GetMapping("/authorizationWln") + public R authorizationWln(@NotNull(message = "店铺Id不能为空") Long shopId, @NotNull(message = "万里牛店铺名称不能为空") String shopName, @NotNull(message = "万里牛系统ID不能为空") String shopNick) { + return R.ok(shopService.authorizationWln(shopId, shopName, shopNick)); + } + + /** + * 加密数据 + * + * @param jsonString + * @return + */ + @PostMapping("/encryption") + @SaIgnore + public Map encryption(@RequestBody String jsonString) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + EncryptionDataBo bo = mapper.readValue(jsonString, EncryptionDataBo.class); + // 手动处理shopId字段 + Map result = shopService.encryptionData(bo); + return result; + } + + /** + * 解密数据 + * + * @param data + * @return + */ + @GetMapping("/decryption") + @SaIgnore + public DecryptDataVo decryption(String data) { +// System.out.println("data:" + data); + DecryptDataVo decryptDataVo = shopService.decryptionData(data); + return decryptDataVo; + } + + /** + * 获取解密后的URL列表 + * @param data 加密后的URL + * @return 原始URL列表 + */ + @GetMapping("/getDecryptedUrlList") + @SaIgnore + public Object getDecryptedUrlList(String data) { + try { + Object decryptDataVoList = shopService.decryptDataVoList(data); + return decryptDataVoList; + } catch (Exception e) { + throw new RuntimeException("解密URL列表失败", e); + } + } + + /** + * 获取解密后的URL列表 带前缀SHXY + * @param data 加密后的URL + * @return 原始URL列表 + */ + @GetMapping("/getDecryptedUrlListPrefix") + @SaIgnore + public Object getDecryptedUrlListPrefix(String data) { + try { + // 判断前四位是否为SHXY + if (data == null || data.length() < 4) { + throw new RuntimeException("数据格式错误:数据长度不足4位"); + } + String prefix = data.substring(0, 4); + if (!"SHXY".equals(prefix)) { + throw new RuntimeException("失败:数据前缀不是SHXY"); + } + // 截取掉前四位 + String actualData = data.substring(4); + Object decryptDataVoList = shopService.decryptDataVoList(actualData); + return decryptDataVoList; + } catch (Exception e) { + throw new RuntimeException("解密URL列表失败", e); + } + } + + @GetMapping("/updateShopSkuSpec") + public R updateShopSkuSpec(String shopId,String type){ + // 当前用户id + Long userId = LoginHelper.getUserId(); + if(userId == 1){ + shopService.updateShopSkuSpec(shopId,"服务版本:"+type+",周期:1个月"); + } + return R.ok(); + } + + /** + * 获取店铺绑定的仓库 + */ +// @SaCheckPermission("zhishu:shop:bind") + @GetMapping("/getShopDepot/{shopId}") + public R getShopDepot(@NotNull(message = "店铺ID不能为空") @PathVariable Long shopId) { + // 这里调用service层方法获取店铺绑定的仓库信息 + return R.ok(shopService.getShopDepotByShopId(shopId)); + } + + /** + * 绑定仓库到店铺 + */ +// @SaCheckPermission("zhishu:shop:bind") + @Log(title = "店铺绑定仓库", businessType = BusinessType.UPDATE) + @PostMapping("/bindDepot") + public R bindDepotToShop(@RequestBody Map request) { + // 检查必要的参数是否存在 + if (request.get("shopId") == null) { + return R.fail("shopId参数不能为空"); + } + if (request.get("depotIds") == null) { // 改为 depotIds + return R.fail("depotIds参数不能为空"); + } + + try { + Long shopId = Long.valueOf(request.get("shopId").toString()); + + // 处理depotIds为数组的情况 + Object depotIdsObj = request.get("depotIds"); // 改为 depotIds + List depotIds = new ArrayList<>(); + + if (depotIdsObj instanceof Object[]) { + // 处理Object数组 + Object[] depotIdArray = (Object[]) depotIdsObj; + for (Object item : depotIdArray) { + if (item != null) { + depotIds.add(Long.valueOf(item.toString())); + } + } + } else if (depotIdsObj instanceof List) { + // 处理List + List depotIdList = (List) depotIdsObj; + for (Object item : depotIdList) { + if (item != null) { + depotIds.add(Long.valueOf(item.toString())); + } + } + } else { + return R.fail("depotIds参数格式错误,应为数组"); // 错误信息也更新 + } + + if (depotIds.isEmpty()) { + return R.fail("请至少选择一个仓库进行绑定"); + } + + boolean result = shopService.bindDepotToShop(shopId, depotIds); + return toAjax(result); + } catch (NumberFormatException e) { + return R.fail("参数格式错误,请提供有效的数字ID"); + } catch (Exception e) { + log.error("绑定仓库失败", e); + return R.fail("系统错误,绑定失败"); + } + } + + /** + * 手动开通选品中心按钮操作 + */ + + @PostMapping("/dredgeCenterBook") + @SaCheckPermission("zhishu:shop:centerBook") + @Log(title = "选品中心开通", businessType = BusinessType.UPDATE) + @SaIgnore + public R dredgeCenterBook( + @NotNull(message = "用户ID不能为空") @RequestParam Long userId, + @NotNull(message = "类型不能为空") @RequestParam Integer type) { + try { + String title = type == 1 ? "页面展示会员" : "高级搜索会员"; + String unit = type == 1 ? "年" : "月"; + String price = type == 1 ? "198000" : "9800"; + String orederType = type == 1 ? "centerBookPage" : "centerBookSearch"; + Map orderParams = new HashMap<>(); + orderParams.put("service_name", title); + orderParams.put("price", price); + orderParams.put("unit", unit); + orderParams.put("length", String.valueOf(1)); + orderParams.put("type", orederType); + orderParams.put("sort", "1"); + String orderUrl = configService.selectConfigByKey("order.url"); + String service = InterfaceUtils.postForm(orderUrl, "/api/createService", orderParams); +// String service = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/createService", params); + if (service != null) { + JSONObject jsonObject = JSONObject.parseObject(service); + if (jsonObject != null && jsonObject.containsKey("data")) { + String serviceId = jsonObject.getString("data"); + orderParams.put("serviceId", serviceId); + } + } + // 新增新后台订单表插入 + Map params1 = new HashMap<>(); + params1.put("orderType", "centerBookPage"); + params1.put("userId", String.valueOf(userId)); + params1.put("goodsId", orderParams.get("serviceId")); + params1.put("count", "1"); + String orderId = null; + String order = InterfaceUtils.postForm("https://go.order.service.buzhiyushu.cn/", "/api/orders/createOrder", params1); + System.out.println("order:"+order); + if (order != null) { + JSONObject jsonObject = JSONObject.parseObject(order); + if (jsonObject != null && jsonObject.containsKey("data")) { + JSONObject dataObject = jsonObject.getJSONObject("data"); + // 再从data对象中获取orderId + orderId = dataObject.getString("orderId"); + System.out.println("orderId:"+orderId); + params1.put("orderId", orderId); + } + } + // 获取外部接口地址 + String goUrl = configService.selectConfigByKey("go.url"); + String path = "/user/updateMemberRecord"; + + // 构建请求参数 + Map params = new HashMap<>(); + params.put("userId", userId); + params.put("type", type); + + // 调用外部接口 + String result = InterfaceUtils.getInterfacePost(goUrl, path, params); + System.out.println("result:" + result); + if (result != null && !result.isEmpty()) { + log.info("选品中心开通成功,用户ID: {}, 类型: {}, 返回结果: {}", userId, type, result); + // 解析返回的JSON + JSONObject json = JSON.parseObject(result); + int code = json.getIntValue("code"); + String msg = json.getString("msg"); + if (Objects.equals(msg, "会员记录更新成功")) { + // 修改新后台新订单表 + if (orderId != null){ + Map map1 = new HashMap(); + map1.put("orderId",orderId); + map1.put("orderInfo", "{\"remark\":\"管理员手动新增会员\"}"); + map1.put("userId",String.valueOf(userId)); + String interfaceGet = InterfaceUtils.postForm(orderUrl, "/api/orders/orderForPay", map1); + System.out.println("充值结果: "+interfaceGet); + Map orderSuccess = JsonUtils.parseObject(interfaceGet,Map.class); + Integer orderCode = (Integer) orderSuccess.get("code"); + if (orderCode == null || code != 200) { + // 这里可以打印日志或抛异常 + System.err.println("更新服务失败,返回结果:" + orderSuccess); + return R.fail("更新服务失败"+orderSuccess); + } + + } + } + Object data = json.get("data"); + if (data instanceof JSONObject dataJson) { + // 获取 data 中的字段 + String userId1 = dataJson.getString("user_id"); + SysUser user = sysUserMapper.selectUserById(Long.valueOf(userId1)); + if (user != null && user.getPhonenumber() != null){ + dataJson.put("phone", user.getPhonenumber()); + } else { + dataJson.put("phone", ""); + } + data = dataJson; + } + + // 根据 Go 返回的 code 自适应响应 + if (code == 200 || code == 201) { + return R.ok(msg, data); + } else { + return R.fail(msg, data); + } + } else { + log.error("选品中心开通失败,用户ID: {}, 类型: {}", userId, type); + return R.fail("开通失败,请稍后重试"); + } + } catch (Exception e) { + log.error("选品中心开通异常,用户ID: {}, 类型: {}", userId, type, e); + return R.fail("系统异常,开通失败"); + } + } + + @GetMapping("/todayGoods") + public Map selectTodayGoods() { + + List shopId = shopMapper.getShopIdByCreateBy(LoginHelper.getUserId()); + return runningTaskByShopServiceImpl.selectTodayGoods(shopId); + } + + @GetMapping("/todaySales") + public Map selectTodaySales() { + List shopId = shopMapper.getShopIdByCreateBy(LoginHelper.getUserId()); + return runningTaskByShopServiceImpl.selectTodaySales(shopId); + } + + @GetMapping("/limitedTimeFree") + public R limitedTimeFree(String id,String priceStr){ + System.out.println(id); + Long userId = LoginHelper.getUserId(); + ShopVo shopVo = shopService.queryById(Long.parseLong(id)); + SysUser user = sysUserMapper.queryUserByUserId(userId); + BigDecimal price = new BigDecimal(priceStr).multiply(new BigDecimal(100)); + BigDecimal balanceOld = user.getBalance(); + if (balanceOld.compareTo(price) < 0){ + return R.fail("余额不足,请前往钱包进行用户充值"); + } + BigDecimal balanceNew = balanceOld.subtract(price); + user.setBalance(balanceNew); + sysUserMapper.updateBalance(userId,user.getBalance().longValue()); + + UserRechargeBo userRechargeBo = new UserRechargeBo(); + userRechargeBo.setCommission(BigDecimal.ZERO); + userRechargeBo.setRechargPrice(price); + userRechargeBo.setRechargType("6"); + userRechargeBo.setStatus("6"); + userRechargeBo.setUserId(userId); + userRechargeBo.setCreateBy(userId); + userRechargeBo.setUpdateBy(userId); + userRechargeBo.setLogTxt("拼多多店铺:"+shopVo.getShopName()+"试用版解除上架限制"); + userRechargeBo.setOriginalPrice(balanceOld); + userRechargeBo.setUpdatePrice(balanceNew); + userRechargeService.insertByBo(userRechargeBo); + + ShopBo shopBo = new ShopBo(); + shopBo.setId(Long.parseLong(id)); + shopBo.setDeregulation("2"); + shopService.updateByBo(shopBo); + + return R.ok("订购成功"); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopDetailController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopDetailController.java new file mode 100644 index 0000000..411ae00 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopDetailController.java @@ -0,0 +1,114 @@ +package org.dromara.zhishu.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.zhishu.util.UploadUtil; +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.vo.ShopDetailVo; +import org.dromara.zhishu.domain.bo.ShopDetailBo; +import org.dromara.zhishu.service.IShopDetailService; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.springframework.web.multipart.MultipartFile; + +/** + * 商品详情 + * + * @author yxy + * @date 2025-03-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopDetail") +public class ShopDetailController extends BaseController { + + private final IShopDetailService shopDetailService; + + /** + * 查询商品详情列表 + */ + @SaCheckPermission("zhishu:shopDetail:list") + @GetMapping("/list") + public TableDataInfo list(ShopDetailBo bo, PageQuery pageQuery) { + return shopDetailService.queryPageList(bo, pageQuery); + } + + /** + * 导出商品详情列表 + */ + @SaCheckPermission("zhishu:shopDetail:export") + @Log(title = "商品详情", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ShopDetailBo bo, HttpServletResponse response) { + List list = shopDetailService.queryList(bo); + ExcelUtil.exportExcel(list, "商品详情", ShopDetailVo.class, response); + } + + /** + * 获取商品详情详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shop:setUp") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(shopDetailService.queryByShopId(id)); + } + + /** + * 新增商品详情 + */ + @SaCheckPermission("zhishu:shopDetail:add") + @Log(title = "商品详情", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ShopDetailBo bo) { + return toAjax(shopDetailService.insertByBo(bo)); + } + + /** + * 修改商品详情 + */ + @SaCheckPermission("zhishu:shopDetail:edit") + @Log(title = "商品详情", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ShopDetailBo bo) { + return toAjax(shopDetailService.updateByBo(bo)); + } + + /** + * 删除商品详情 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:shopDetail:remove") + @Log(title = "商品详情", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(shopDetailService.deleteWithValidByIds(List.of(ids), true)); + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsPublishedController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsPublishedController.java new file mode 100644 index 0000000..063efc8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsPublishedController.java @@ -0,0 +1,224 @@ +package org.dromara.zhishu.controller; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSON; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.ShopGoodsRejection; +import org.dromara.zhishu.domain.vo.PlatformIdUpdateVO; +import org.dromara.zhishu.service.IRunningTaskByShopService; +import org.dromara.zhishu.service.ShopGoodsRejectionService; +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.ShopGoodsPublishedVo; +import org.dromara.zhishu.domain.bo.ShopGoodsPublishedBo; +import org.dromara.zhishu.service.IShopGoodsPublishedService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 记录已发布书籍 + * + * @author yxy + * @date 2025-04-11 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopGoodsPublished") +public class ShopGoodsPublishedController extends BaseController { + + private final IShopGoodsPublishedService shopGoodsPublishedService; + + private final IRunningTaskByShopService runningTaskByShopService; + + + /** + * 查询记录已发布书籍列表 + */ + @SaCheckPermission("zhishu:shopGoodsPublished:list") + @GetMapping("/list") + public TableDataInfo list(ShopGoodsPublishedBo bo, PageQuery pageQuery) { + // 获取当前登录用户的ID + Long userId = LoginHelper.getUserId(); + bo.setCreateBy(userId); + return shopGoodsPublishedService.selectDataList(bo, pageQuery); + } + + @SaIgnore + @GetMapping("/pddAdd/{platformId}/{goodsId}/{shopId}/{userId}") + public void pddAdd(@PathVariable("platformId") String platformId, + @PathVariable("goodsId") String goodsId, + @PathVariable("shopId") String shopId, + @PathVariable("userId") String userId) { + ShopGoodsPublishedBo shopGoodsPublishedBo = new ShopGoodsPublishedBo(); + shopGoodsPublishedBo.setPlatformId(platformId); + shopGoodsPublishedBo.setShopGoodsId(goodsId); + shopGoodsPublishedBo.setShopId(shopId); + shopGoodsPublishedBo.setCreateBy(Long.parseLong(userId)); + shopGoodsPublishedBo.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + shopGoodsPublishedBo.setUpdateTime(DateUtils.parseDate(DateUtils.getTime())); + shopGoodsPublishedService.insertByBo(shopGoodsPublishedBo); + } + + /** + * 导出记录已发布书籍列表 + */ + @SaCheckPermission("zhishu:shopGoodsPublished:export") + @Log(title = "记录已发布书籍", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ShopGoodsPublishedBo bo, HttpServletResponse response) { + List list = shopGoodsPublishedService.queryList(bo); + ExcelUtil.exportExcel(list, "记录已发布书籍", ShopGoodsPublishedVo.class, response); + } + + /** + * 获取记录已发布书籍详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shopGoodsPublished:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(shopGoodsPublishedService.queryById(id)); + } + + /** + * 新增记录已发布书籍 + */ + @SaCheckPermission("zhishu:shopGoodsPublished:add") + @Log(title = "记录已发布书籍", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ShopGoodsPublishedBo bo) { + return toAjax(shopGoodsPublishedService.insertByBo(bo)); + } + + /** + * 修改记录已发布书籍 + */ + @SaCheckPermission("zhishu:shopGoodsPublished:edit") + @Log(title = "记录已发布书籍", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ShopGoodsPublishedBo bo) { + return toAjax(shopGoodsPublishedService.updateByBo(bo)); + } + + /** + * 删除记录已发布书籍 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:shopGoodsPublished:remove") + @Log(title = "记录已发布书籍", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(shopGoodsPublishedService.deleteWithValidByIds(List.of(ids), true)); + } + + @SaCheckPermission("zhishu:shopGoodsPublished:remove") + @Log(title = "记录已发布书籍删除全部", businessType = BusinessType.DELETE) + @DeleteMapping("/removeAll") + public Map removeAll(Long shopId){ + Map map = new HashMap(); + String msg = shopGoodsPublishedService.deleteAll(shopId); + if(msg.contains("成功")){ + map.put("code",200); + }else{ + map.put("code",500); + } + map.put("msg",msg); + return map; + } + + /** + * 根据店铺Id查询商品列表 + */ + @PostMapping("/getListByShopId") + @SaIgnore + public List getListByShopId(Long shopId, @RequestBody List platformIds) { + return shopGoodsPublishedService.selectGoodsListByShopId(shopId, platformIds); + } + + /** + * 根据店铺Id查询商品列表 + */ + @GetMapping("/getListByShopId") + @SaIgnore + public List getListByShopId(Long shopId) { + return shopGoodsPublishedService.selectGoodsListByShopId(shopId); + } + + /** + * 商品发布驳回-类目修改cat_id + */ + @GetMapping("/uodateCatId") + @SaIgnore + public Boolean uodateCatId(String shopType, Long mallId, String platformId) { + return shopGoodsPublishedService.uodateCatId(shopType, mallId, platformId); + } + + /** + * 根据店铺Id和商品Id删除失败的商品 + */ + @GetMapping("/delShopGoodsPublished") + @SaIgnore + public Boolean delShopGoodsPublished(String shopType, Long mallId, String platformId, String rejectComment) { + return shopGoodsPublishedService.delShopGoodsPublished(shopType, mallId, platformId, rejectComment); + } + + /** + * 更新孔网商品id + */ + @PostMapping("/batchUpdateKfzPlatformId") + @SaIgnore + public R batchUpdateKfzPlatformId(@RequestBody List platformIdUpdateVOList) { + shopGoodsPublishedService.batchUpdateKfzPlatformId(platformIdUpdateVOList); +// System.out.println("platformIdUpdateVOList:" + JSON.toJSONString(platformIdUpdateVOList)); + return R.ok(); + } + + /** + * 根据店铺Id和商品Id删除失败的商品 + */ + @GetMapping("/insertShopGoodsPublishedlog") + @SaIgnore + public void insertShopGoodsPublishedlog(String shopType, Long mallId, String platformId, String offshelftime) { + shopGoodsPublishedService.insertLog(shopType, mallId, platformId, offshelftime); + } + + + /** + * 已发布商品记录校验店铺商品 + */ + @PostMapping("/verifyShopGoodsPublished") + public R verifyShopGoodsPublished(String shopId){ + // 异步执行耗时任务 + CompletableFuture.runAsync(() -> { + shopGoodsPublishedService.verifyShopGoodsPublished(shopId); + }); + return R.ok("任务已提交,请前往任务列表查询结果"); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsPublishedLogController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsPublishedLogController.java new file mode 100644 index 0000000..e95b1df --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsPublishedLogController.java @@ -0,0 +1,44 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; +import org.dromara.zhishu.domain.StockChangeLog; +import org.dromara.zhishu.service.ShopGoodsPublishedLogService; +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; + +/** + * 记录已发布书籍 + * + * @author yxy + * @date 2025-04-11 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopGoodsPublishedLog") +public class ShopGoodsPublishedLogController { + + private final ShopGoodsPublishedLogService shopGoodsPublishedLogService; + + /** + * 通过平台商品id和相关Id查询商品发布记录 + */ + @GetMapping("/queryPublishedLogByOrderSn") + @SaIgnore + public R queryPublishedLogByOrderSn(@NotNull(message = "平台订单编码不能为空") String platformId, + @NotNull(message = "日志类型不能为空") String aboutId, + @NotNull(message = "平台类型不能为空") Integer platformType, + @NotNull(message = "日志类型不能为空") Integer logType, + @NotNull(message = "操作类型不能为空") Integer operationType + ) { + ShopGoodsPublishedLog log = shopGoodsPublishedLogService.queryPublishedLogByOrderSn(platformId, aboutId, platformType, logType, operationType); + return R.ok(log); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsRejectionController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsRejectionController.java new file mode 100644 index 0000000..de3fc4e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ShopGoodsRejectionController.java @@ -0,0 +1,206 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; +import org.dromara.zhishu.domain.ShopGoodsRejection; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.service.ShopGoodsPublishedLogService; +import org.dromara.zhishu.service.ShopGoodsRejectionService; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +/** + * 记录已发布书籍 + * + * @author yxy + * @date 2025-04-11 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopgoodsrejection") +public class ShopGoodsRejectionController { + + private final ShopGoodsRejectionService shopGoodsRejectionService; + + /** + * 分页查询列表 + */ + @GetMapping("/list") + public TableDataInfo list(ShopGoodsRejection bo, PageQuery pageQuery) { + TableDataInfo list = shopGoodsRejectionService.searchWithPage(bo,pageQuery); + + return list; + } + + /** + * 根据ID查询详情 + */ + @GetMapping("/{id}") + public ResponseEntity> getById(@PathVariable Long id) { + Map result = new HashMap<>(); + try { + ShopGoodsRejection rejection = shopGoodsRejectionService.findById(id); + if (rejection != null) { + result.put("success", true); + result.put("data", rejection); + return ResponseEntity.ok(result); + } else { + result.put("success", false); + result.put("message", "记录不存在"); + return ResponseEntity.notFound().build(); + } + } catch (Exception e) { + result.put("success", false); + result.put("message", "查询失败: " + e.getMessage()); + return ResponseEntity.badRequest().body(result); + } + } + + /** + * 新增记录 + */ + @PostMapping("/add") + public ResponseEntity> create(@RequestBody ShopGoodsRejection shopGoodsRejection) { + Map result = new HashMap<>(); + try { + boolean success = shopGoodsRejectionService.save(shopGoodsRejection); + if (success) { + result.put("success", true); + result.put("message", "新增成功"); + result.put("data", shopGoodsRejection); + return ResponseEntity.ok(result); + } else { + result.put("success", false); + result.put("message", "新增失败"); + return ResponseEntity.badRequest().body(result); + } + } catch (Exception e) { + result.put("success", false); + result.put("message", "新增失败: " + e.getMessage()); + return ResponseEntity.badRequest().body(result); + } + } + + /** + * 更新记录 + */ + @PutMapping("/{id}") + public ResponseEntity> update(@PathVariable Long id, @RequestBody ShopGoodsRejection shopGoodsRejection) { + Map result = new HashMap<>(); + try { + // 设置ID + shopGoodsRejection.setId(id); + boolean success = shopGoodsRejectionService.update(shopGoodsRejection); + if (success) { + result.put("success", true); + result.put("message", "更新成功"); + return ResponseEntity.ok(result); + } else { + result.put("success", false); + result.put("message", "更新失败,记录可能不存在"); + return ResponseEntity.badRequest().body(result); + } + } catch (Exception e) { + result.put("success", false); + result.put("message", "更新失败: " + e.getMessage()); + return ResponseEntity.badRequest().body(result); + } + } + + /** + * 删除记录 + */ + @DeleteMapping("/{id}") + public ResponseEntity> delete(@PathVariable Long id) { + Map result = new HashMap<>(); + try { + boolean success = shopGoodsRejectionService.delete(id); + if (success) { + result.put("success", true); + result.put("message", "删除成功"); + return ResponseEntity.ok(result); + } else { + result.put("success", false); + result.put("message", "删除失败,记录可能不存在"); + return ResponseEntity.badRequest().body(result); + } + } catch (Exception e) { + result.put("success", false); + result.put("message", "删除失败: " + e.getMessage()); + return ResponseEntity.badRequest().body(result); + } + } + + /** + * 批量删除 + */ + @DeleteMapping("/batch") + public ResponseEntity> batchDelete(@RequestBody List ids) { + Map result = new HashMap<>(); + try { + int successCount = 0; + for (Long id : ids) { + if (shopGoodsRejectionService.delete(id)) { + successCount++; + } + } + result.put("success", true); + result.put("message", "成功删除 " + successCount + " 条记录"); + result.put("successCount", successCount); + return ResponseEntity.ok(result); + } catch (Exception e) { + result.put("success", false); + result.put("message", "批量删除失败: " + e.getMessage()); + return ResponseEntity.badRequest().body(result); + } + } + + /** + * 根据店铺ID查询 + */ + @GetMapping("/shop/{shopId}") + public ResponseEntity> getByShopId(@PathVariable String shopId) { + Map result = new HashMap<>(); + try { + List list = shopGoodsRejectionService.findByShopId(shopId); + result.put("success", true); + result.put("data", list); + result.put("total", list.size()); + return ResponseEntity.ok(result); + } catch (Exception e) { + result.put("success", false); + result.put("message", "查询失败: " + e.getMessage()); + return ResponseEntity.badRequest().body(result); + } + } + + /** + * 根据平台商品ID查询 + */ + @GetMapping("/platform/{platformId}") + public ResponseEntity> getByPlatformId(@PathVariable String platformId) { + Map result = new HashMap<>(); + try { + List list = shopGoodsRejectionService.findByPlatformId(platformId); + result.put("success", true); + result.put("data", list); + result.put("total", list.size()); + return ResponseEntity.ok(result); + } catch (Exception e) { + result.put("success", false); + result.put("message", "查询失败: " + e.getMessage()); + return ResponseEntity.badRequest().body(result); + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SinglePrintController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SinglePrintController.java new file mode 100644 index 0000000..6d9c4b5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SinglePrintController.java @@ -0,0 +1,181 @@ +package org.dromara.zhishu.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +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.json.utils.JsonUtils; +import org.dromara.zhishu.domain.SinglePrint; +import org.dromara.zhishu.domain.bo.PrinterBo; +import org.dromara.zhishu.domain.vo.FastMailVo; +import org.dromara.zhishu.domain.vo.PrinterVo; +import org.dromara.zhishu.domain.vo.TLogisticsVo; +import org.dromara.zhishu.service.IFastMailService; +import org.dromara.zhishu.service.IPrinterService; +import org.dromara.zhishu.service.ITLogisticsService; +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.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.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.zhishu.domain.bo.SinglePrintBo; +import org.dromara.zhishu.service.ISinglePrintService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 单票打印 + * + * @author yxy + * @date 2026-03-27 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/singlePrint") +public class SinglePrintController extends BaseController { + + private final ISinglePrintService singlePrintService; + private final IFastMailService fastMailService; + private final ITLogisticsService logisticsService; + private final IPrinterService printerService; + + /** + * 查询单票打印列表 + */ + @SaCheckPermission("zhishu:singlePrint:list") + @GetMapping("/list") + public TableDataInfo list(SinglePrintBo bo, PageQuery pageQuery) { + return singlePrintService.queryPageList(bo, pageQuery); + } + + /** + * 导出单票打印列表 + */ + @SaCheckPermission("zhishu:singlePrint:export") + @Log(title = "单票打印", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SinglePrintBo bo, HttpServletResponse response) { + List list = singlePrintService.queryList(bo); + ExcelUtil.exportExcel(list, "单票打印", SinglePrint.class, response); + } + + /** + * 获取单票打印详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:singlePrint:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(singlePrintService.queryById(id)); + } + + /** + * 根据快递单号获取单票打印信息 + * + * @param mailNo 快递单号 + */ + @SaCheckPermission("zhishu:singlePrint:query") + @GetMapping("/getByMailNo/{mailNo}") + public R getInfoByMailNo(@NotNull(message = "快递单号不能为空") + @PathVariable String mailNo) { + return R.ok(singlePrintService.queryByMailNo(mailNo)); + } + + + @PostMapping("/add") + public R add(@RequestBody Map dataMap){ + // 运费模板 + String logisticsId = dataMap.get("logisticsData").toString(); + TLogisticsVo logisticsVo = logisticsService.queryById(Long.parseLong(logisticsId)); + dataMap.put("logisticsVo", JsonUtils.toJsonString(logisticsVo)); + // 快递账号 + String fastMailId = dataMap.get("fastMailId").toString(); + FastMailVo fastMailVo = fastMailService.queryById(Long.parseLong(fastMailId)); + dataMap.put("fastMailVo",JsonUtils.toJsonString(fastMailVo)); + // 根据当前时间戳+5位随机数生成 orderSn + // 获取当前时间戳(毫秒) + long timestamp = System.currentTimeMillis(); + // 生成5位随机数(10000-99999) + int randomNum = new Random().nextInt(90000) + 10000; + String orderSn = timestamp + String.valueOf(randomNum); + dataMap.put("orderSn",orderSn); + String data = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/singlePrint/addSinglePrint",dataMap); + Map mapData = JsonUtil.transferToObj(data,Map.class); + return R.ok(mapData); + } + + @GetMapping("/printOne") + public R printOne(String id){ + String res = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/singlePrint/printOne?id="+id); + Map resMap = JsonUtil.transferToObj(res,Map.class); + return R.ok(resMap); + } + + @PostMapping("/pddCloudPrint") + public R pddCloudPrint(@RequestBody Map dataMap){ + if(dataMap.get("fastMailId") != null){ + // 不为空则需要手动查询一下快递账号的token + FastMailVo fastMailVo = fastMailService.queryById(Long.parseLong(dataMap.get("fastMailId").toString())); + Map remarkMap = JsonUtil.transferToObj(fastMailVo.getRemark(),Map.class); + dataMap.put("accessToken",remarkMap.get("token").toString()); + } + String printerId = dataMap.get("printerId").toString(); + PrinterVo printerVo = printerService.queryById(Long.parseLong(printerId)); + dataMap.put("printer",printerVo); + Map data = new HashMap(); + data.put("data",JsonUtil.transferToJson(dataMap)); + String str = InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/pddCloudPrint/pddCloudPrint",data); + return R.ok(); + } + + @GetMapping("/cancelBmOrder") + public R cancelBmOrder(String id){ + String res = InterfaceUtils.getInterface(UrlUtil.getOrderServiceUrl(),"/api/singlePrint/cancelBmOrder?id="+id); + Map resMap = JsonUtil.transferToObj(res,Map.class); + if (resMap.get("code").equals("200")){ + return R.ok(resMap.get("msg").toString()); + }else{ + return R.fail(resMap.get("msg").toString()); + } + } + + + /** + * 删除单票打印 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:singlePrint:remove") + @Log(title = "单票打印", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(singlePrintService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 根据快递单号删除 + * + * @param mailNo 快递单号 + */ + @SaCheckPermission("zhishu:singlePrint:remove") + @Log(title = "单票打印", businessType = BusinessType.DELETE) + @DeleteMapping("/deleteByMailNo/{mailNo}") + public R removeByMailNo(@NotNull(message = "快递单号不能为空") + @PathVariable String mailNo) { + return toAjax(singlePrintService.deleteByMailNo(mailNo)); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SynchronizationShopLogController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SynchronizationShopLogController.java new file mode 100644 index 0000000..9a3058c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/SynchronizationShopLogController.java @@ -0,0 +1,74 @@ +package org.dromara.zhishu.controller; + +import java.util.List; +import java.util.Map; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.dromara.zhishu.domain.SynchronizationShopLog; +import org.dromara.zhishu.domain.bo.SynchronizationShopLogBo; +import org.dromara.zhishu.domain.vo.SynchronizationShopLogVo; +import org.dromara.zhishu.service.ISynchronizationShopLogService; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +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.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 同步店铺商品库存日志 + * + * @author yxy + * @date 2026-04-14 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/synchronizationShopLog") +public class SynchronizationShopLogController extends BaseController { + + private final ISynchronizationShopLogService synchronizationShopLogService; + + /** + * 查询同步店铺商品库存日志列表 + */ + @SaCheckPermission("zhishu:synchronizationShopLog:list") + @GetMapping("/list") + public TableDataInfo> list(SynchronizationShopLogBo bo, PageQuery pageQuery) { + return synchronizationShopLogService.queryPageList(bo, pageQuery); + } + + @GetMapping("/getLogList") + public List getLogList(SynchronizationShopLogBo bo){ + return synchronizationShopLogService.queryList(bo); + } + + /** + * 导出同步店铺商品库存日志列表 + */ + @SaCheckPermission("zhishu:synchronizationShopLog:export") + @Log(title = "同步店铺商品库存日志", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(SynchronizationShopLogBo bo, HttpServletResponse response) { + List list = synchronizationShopLogService.queryList(bo); + ExcelUtil.exportExcel(list, "同步店铺商品库存日志", SynchronizationShopLogVo.class, response); + } + + /** + * 获取同步店铺商品库存日志详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:synchronizationShopLog:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(synchronizationShopLogService.queryById(id)); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TAuditController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TAuditController.java new file mode 100644 index 0000000..f3f1b1a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TAuditController.java @@ -0,0 +1,139 @@ +package org.dromara.zhishu.controller; + +import java.util.List; + +import io.github.linpeilie.BaseMapper; +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.beans.factory.annotation.Autowired; +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.TAuditVo; +import org.dromara.zhishu.domain.bo.TAuditBo; +import org.dromara.zhishu.service.ITAuditService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 审核 + * + * @author Lion Li + * @date 2025-04-01 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/audit") +public class TAuditController extends BaseController { + + @Autowired + private final ITAuditService tAuditService; + + + /** + * 查询审核列表 + */ + @SaCheckPermission("zhishu:audit:list") + @GetMapping("/list") + public TableDataInfo list(TAuditBo bo, PageQuery pageQuery) { + return tAuditService.queryPageList(bo, pageQuery); + } + + /** + * 导出审核列表 + */ + @SaCheckPermission("zhishu:audit:export") + @Log(title = "审核", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TAuditBo bo, HttpServletResponse response) { + List list = tAuditService.queryList(bo); + ExcelUtil.exportExcel(list, "审核", TAuditVo.class, response); + } + + /** + * 获取审核详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:audit:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tAuditService.queryById(id)); + } + + /** + * 新增审核 + */ + @SaCheckPermission("zhishu:audit:add") + @Log(title = "审核", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TAuditBo bo) { + return toAjax(tAuditService.insertByBo(bo)); + } + + /** + * 修改审核 + */ +// @SaCheckPermission("zhishu:audit:edit") + @Log(title = "审核", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TAuditBo bo) { + return toAjax(tAuditService.updateByBo(bo)); + } + + /** + * 删除审核 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:audit:remove") + @Log(title = "审核", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tAuditService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 修改审核通过状态 + * + */ +// @SaCheckPermission("zhishu:audit:updateStatus") + @Log(title = "审核状态", businessType = BusinessType.UPDATE) + @PutMapping("/updateStatus") + public R updateStatus(@RequestBody TAuditBo bo) { + return toAjax(tAuditService.updateByStatus(bo)); + } + + + /** + * 修改审核未通过状态 + * + */ +// @SaCheckPermission("zhishu:audit:updateStatus") +// @Log(title = "审核状态", businessType = BusinessType.INSERT) + @PostMapping("/failSend") + public R failSend(@RequestBody TAuditBo bo) { + //修改审核状态,为未通过(1) + tAuditService.updateByStatus(bo); + //将修改内容写入t_audit_log的日志表里 + Integer message = tAuditService.InsertLog(bo); + return toAjax(message); + } + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TBookAuditController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TBookAuditController.java new file mode 100644 index 0000000..224eb8f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TBookAuditController.java @@ -0,0 +1,115 @@ +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.TBookAuditVo; +import org.dromara.zhishu.domain.bo.TBookAuditBo; +import org.dromara.zhishu.service.ITBookAuditService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 图书审核管理 + * + * @author Lion Li + * @date 2025-04-18 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/bookAudit") +public class TBookAuditController extends BaseController { + + private final ITBookAuditService tBookAuditService; + + /** + * 查询图书审核管理列表 + */ + @SaCheckPermission("zhishu:bookAudit:list") + @GetMapping("/list") + public TableDataInfo list(TBookAuditBo bo, PageQuery pageQuery) { + return tBookAuditService.queryPageList(bo, pageQuery); + } + + /** + * 导出图书审核管理列表 + */ + @SaCheckPermission("zhishu:bookAudit:export") + @Log(title = "图书审核管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TBookAuditBo bo, HttpServletResponse response) { + List list = tBookAuditService.queryList(bo); + ExcelUtil.exportExcel(list, "图书审核管理", TBookAuditVo.class, response); + } + + /** + * 获取图书审核管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:bookAudit:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tBookAuditService.queryById(id)); + } + + /** + * 新增图书审核管理 + */ + @SaCheckPermission("zhishu:bookAudit:add") + @Log(title = "图书审核管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TBookAuditBo bo) { + return toAjax(tBookAuditService.insertByBo(bo)); + } + + /** + * 修改图书审核管理 + */ + @SaCheckPermission("zhishu:bookAudit:edit") + @Log(title = "图书审核管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TBookAuditBo bo) { + return toAjax(tBookAuditService.updateByBo(bo)); + } + + /** + * 删除图书审核管理 + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:bookAudit:remove") + @Log(title = "图书审核管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tBookAuditService.deleteWithValidByIds(List.of(ids), true)); + } + + + /** + * 修改图书审核状态 + */ + @Log(title = "图书审核管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/updateStatus") + public R updateStatus(@Validated(EditGroup.class) @RequestBody TBookAuditBo bo) { + return toAjax(tBookAuditService.updateStatus(bo)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TDepotController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TDepotController.java new file mode 100644 index 0000000..afb13ca --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TDepotController.java @@ -0,0 +1,174 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +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.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +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 org.dromara.zhishu.service.ITDepotService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 仓库信息设置 + * + * @author Lion Li + * @date 2025-03-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/depot/depot") +public class TDepotController extends BaseController { + + private final ITDepotService tDepotService; + + + /** + * 查询仓库信息设置列表 + */ + @SaCheckPermission("depot:depot:list") + @GetMapping("/list") + public TableDataInfo list(TDepotBo bo, PageQuery pageQuery) { + return tDepotService.queryPageList(bo, pageQuery); + } + + + /** + * 导出仓库信息设置列表 + */ + @SaCheckPermission("depot:depot:export") + @Log(title = "仓库信息设置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TDepotBo bo, HttpServletResponse response) { + List list = tDepotService.queryList(bo); + ExcelUtil.exportExcel(list, "仓库信息设置", TDepotVo.class, response); + } + + /** + * 获取仓库信息设置详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("depot:depot:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tDepotService.queryById(id)); + } + + /** + * 新增仓库信息设置 + */ + @SaCheckPermission("depot:depot:add") + @Log(title = "仓库信息设置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + @SaIgnore + public R add(@Validated(AddGroup.class) @RequestBody TDepotBo bo) { + try{ + tDepotService.insertByBo(bo); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } +// return toAjax(tDepotService.insertByBo(bo)); + return R.ok(bo); + } + + /** + * 修改仓库信息设置 + */ + @SaCheckPermission("depot:depot:edit") + @Log(title = "仓库信息设置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + @SaIgnore + public R edit(@Validated(EditGroup.class) @RequestBody TDepotBo bo) { + try{ + tDepotService.updateByBo(bo); + }catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + return R.ok(bo); + } + + /** + * 删除仓库信息设置 + * + * @param ids 主键串 + */ + @SaCheckPermission("depot:depot:remove") + @Log(title = "仓库信息设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + @SaIgnore + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids, + @RequestParam(required = false) Long LocalUserId) { + return toAjax(tDepotService.deleteWithValidByIds(List.of(ids), true,LocalUserId)); + } + + @GetMapping("/getIds") + public Map getIds(@RequestParam String depotName, + @RequestParam String freightName, + @RequestParam String shelvesName) { + return tDepotService.getIds(depotName, freightName, shelvesName); + } + + /** + * 获取二级货区信息 + * @param id + * @return + */ + @GetMapping("/shelves/{id}") + public R> getSheInfo(@PathVariable Long id) { + List list =tDepotService.queryShelvesList(id); + System.out.println(list); + return R.ok(list); + } + + /** + * 获取三级货区信息 + * @param id + * @return + */ + @GetMapping("/freight/{id}") + public R> getFreInfo(@PathVariable Long id) { + List list =tDepotService.queryTFreightList(id); + System.out.println(list); + return R.ok(list); + } + + @GetMapping("/getDepotAll") + public TableDataInfo getDepotAll(){ + List list = tDepotService.queryListAll(); + return TableDataInfo.build(list); + } + + @GetMapping("/getDepotId") + @SaIgnore + public TableDataInfo getDepotId(Long userId,String code){ + List list = tDepotService.selectDepotIdByUserIdAndCode(userId,code); + return TableDataInfo.build(list); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TDistrictController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TDistrictController.java new file mode 100644 index 0000000..af347ba --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TDistrictController.java @@ -0,0 +1,209 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +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.zhishu.domain.bo.TDistrictBo; +import org.dromara.zhishu.domain.vo.DistrictsVo; +import org.dromara.zhishu.domain.vo.TDistrictVo; +import org.dromara.zhishu.service.ITDistrictService; +import org.dromara.zhishu.util.JsonExporterUtils; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/district") +public class TDistrictController extends BaseController { + + private final ITDistrictService tDistrictService; + + /** + * 查询【请填写功能名称】列表 + */ + @SaCheckPermission("system:district:list") + @GetMapping("/list") + public TableDataInfo list(TDistrictBo bo, PageQuery pageQuery) { + return tDistrictService.queryPageList(bo, pageQuery); + } + + /** + * 导出【请填写功能名称】列表 + */ + @SaCheckPermission("system:district:export") + @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TDistrictBo bo, HttpServletResponse response) { + List list = tDistrictService.queryList(bo); + ExcelUtil.exportExcel(list, "【请填写功能名称】", TDistrictVo.class, response); + } + + /** + * 获取【请填写功能名称】详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:district:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { + return R.ok(tDistrictService.queryById(id)); + } + + /** + * 新增【请填写功能名称】 + */ + @SaCheckPermission("system:district:add") + @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TDistrictBo bo) { + return toAjax(tDistrictService.insertByBo(bo)); + } + + /** + * 修改【请填写功能名称】 + */ + @SaCheckPermission("system:district:edit") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TDistrictBo bo) { + return toAjax(tDistrictService.updateByBo(bo)); + } + + /** + * 删除【请填写功能名称】 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:district:remove") + @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { + return toAjax(tDistrictService.deleteWithValidByIds(List.of(ids), true)); + } + + @GetMapping("/getDistrictTree") + public List> getDistrictTree(){ + List> mapList = new ArrayList<>(); + List list = tDistrictService.selectDistrictByPid("0"); + for(TDistrictVo districtVo : list){ + Map map = new HashMap<>(); + map.put("value", districtVo.getId()); + map.put("label", districtVo.getName()); + //获取市 + List> childrenMapList = new ArrayList<>(); + List childrenList = tDistrictService.selectDistrictByPid(String.valueOf(districtVo.getId())); + for(TDistrictVo children : childrenList){ + Map childrenMap = new HashMap<>(); + childrenMap.put("value", children.getId()); + childrenMap.put("label", children.getName()); + + List> childrenMapTwoList = new ArrayList<>(); + List childrenTwoList = tDistrictService.selectDistrictByPid(String.valueOf(children.getId())); + for (TDistrictVo childrenTwo : childrenTwoList){ + Map childrenTwoMap = new HashMap<>(); + childrenTwoMap.put("value", childrenTwo.getId()); + childrenTwoMap.put("label", childrenTwo.getName()); + childrenMapTwoList.add(childrenTwoMap); + } + childrenMap.put("children", childrenMapTwoList); + + childrenMapList.add(childrenMap); + } + map.put("children", childrenMapList); + mapList.add(map); + } + return mapList; + } + + /** + * 获取所有省级数据 + */ + @SaIgnore + @GetMapping("/provinces") + public R> getProvinces() { + TDistrictBo bo = new TDistrictBo(); + bo.setLevel(0L); // 省级数据level=0 + bo.setStatus(0L); // 状态正常 + return R.ok(tDistrictService.selectList()); + } + + /** + * 根据省ID获取市级数据 + * + * @param provinceId 省ID + */ + @SaIgnore + @GetMapping("/cities/{provinceId}") + public R> getCitiesByProvinceId(@PathVariable Long provinceId) { + TDistrictVo vo = new TDistrictVo(); + vo.setPid(provinceId); // 父ID为省ID + vo.setLevel(1L); // 市级数据level=1 + vo.setStatus(0L); // 状态正常 + return R.ok(tDistrictService.selectCityList(vo)); + } + + /** + * 根据市ID获取区县级数据 + * + * @param cityId 市ID + */ + @SaIgnore + @GetMapping("/districts/{cityId}") + public R> getDistrictsByCityId(@PathVariable Long cityId) { + TDistrictVo vo = new TDistrictVo(); + vo.setPid(cityId); // 父ID为市ID + vo.setLevel(2L); // 区县级数据level=2 + vo.setStatus(0L); // 状态正常 + return R.ok(tDistrictService.selectAreaList(vo)); + } + + /** + * 导出地址数据JSON文件 + */ + @SaIgnore + @GetMapping(value = "/districts", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getDistricts() throws IOException { + // 获取地区数据 + TDistrictVo vo = new TDistrictVo(); + vo.setStatus(0L); // 状态正常 + // 查询区划信息数据 + List districtsList = tDistrictService.selectDistricts(vo); + // 使用json导出工具类,传入导出数据对象并指定文件名称 + return JsonExporterUtils.exportJsonAsFile(districtsList, "districts.json"); + } + + /** + * 根据区划名称查询区划列表 + */ + @SaIgnore + @PostMapping("/queryListByName") + public List queryListByName(@RequestBody List districtNames) { + return tDistrictService.queryListByName(districtNames); + } + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TFreightController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TFreightController.java new file mode 100644 index 0000000..455efef --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TFreightController.java @@ -0,0 +1,148 @@ +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.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.TFreight; +import org.dromara.zhishu.domain.bo.TFreightBo; +import org.dromara.zhishu.domain.vo.TFreightVo; +import org.dromara.zhishu.domain.vo.TShelvesVo; +import org.dromara.zhishu.service.ITFreightService; +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-04-19 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/freight") +public class TFreightController extends BaseController { + + private final ITFreightService tFreightService; + + + @GetMapping("/getDepotTree") + public Map getDepotTree(){ + Map map = new HashMap(); + map.put("code",200); + map.put("msg","查询成功"); + map.put("data",tFreightService.selectDepotTree()); + return map; + } + + /** + * 查询三级货区管理列表 + */ + @SaCheckPermission("zhishu:freight:list") + @GetMapping("/list") + public TableDataInfo list(TFreightBo bo, PageQuery pageQuery) { + return tFreightService.queryPageList(bo, pageQuery); + } + + /** + * 导出三级货区管理列表 + */ + @SaCheckPermission("zhishu:freight:export") + @Log(title = "三级货区管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TFreightBo bo, HttpServletResponse response) { + List list = tFreightService.queryList(bo); + ExcelUtil.exportExcel(list, "三级货区管理", TFreightVo.class, response); + } + + /** + * 获取三级货区管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:freight:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tFreightService.queryById(id)); + } + + /** + * 新增三级货区管理 + */ + @SaCheckPermission("zhishu:freight:add") + @Log(title = "三级货区管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @SaIgnore + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TFreightBo bo) { + try{ + tFreightService.insertByBo(bo); + return R.ok(bo); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + + /** + * 修改三级货区管理 + */ + @SaCheckPermission("zhishu:freight:edit") + @Log(title = "三级货区管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + @SaIgnore + public R edit(@Validated(EditGroup.class) @RequestBody TFreightBo bo) { + try{ + tFreightService.updateByBo(bo); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + return R.ok(bo); + } + + /** + * 删除三级货区管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:freight:remove") + @Log(title = "三级货区管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + @SaIgnore + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids, + @RequestParam(required = false) Long LocalUserId) { + return toAjax(tFreightService.deleteWithValidByIds(List.of(ids), true,LocalUserId)); + } + + /** + * 查询货架id,code列表 + */ +// @SaIgnore + @SaCheckPermission("shelves:shelves:sheList") + @GetMapping("/sheList") + @SaIgnore + public TableDataInfo listShe() { + List list= tFreightService.querySheNameList(); + return TableDataInfo.build(list); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TInviteCodeController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TInviteCodeController.java new file mode 100644 index 0000000..00b7203 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TInviteCodeController.java @@ -0,0 +1,120 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +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.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.zhishu.domain.TInviteCode; +import org.dromara.zhishu.domain.bo.InviteCodeBo; +import org.dromara.zhishu.domain.vo.InviteCodeVo; +import org.dromara.zhishu.service.ITInviteCodeService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 邀请码管理 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/invite") +public class TInviteCodeController extends BaseController { + + private final ITInviteCodeService inviteCodeService; + + /** + * 查询我的邀请码列表 + */ + @GetMapping("/list") + @SaIgnore + public R> list() { + Long userId = LoginHelper.getUserId(); + List list = inviteCodeService.queryListByUserId(userId); + // 不需要显示邀请码是否已使用 + if (list != null) { + for (InviteCodeVo vo : list) { + vo.setUsed(null); + } + } + return R.ok(list); + } + + /** + * 查询邀请码分页列表 + */ + @SaCheckPermission("zhishu:invite:list") + @GetMapping("/page") + @SaIgnore + public TableDataInfo page(InviteCodeBo bo, PageQuery pageQuery) { + // 设置当前登录用户ID作为查询条件 + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + + TableDataInfo tableDataInfo = inviteCodeService.queryPageList(bo, pageQuery); + // 不需要显示邀请码是否已使用 + if (tableDataInfo != null && tableDataInfo.getRows() != null) { + for (InviteCodeVo vo : tableDataInfo.getRows()) { + vo.setUsed(null); + } + } + return tableDataInfo; + } + + /** + * 获取邀请码详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:invite:query") + @GetMapping("/{id}") + public R getInfo(@PathVariable("id") Long id) { + InviteCodeVo vo = inviteCodeService.queryById(id); + if (vo != null) { + vo.setUsed(null); + } + return R.ok(vo); + } + + /** + * 生成邀请码 + */ + @Log(title = "邀请码管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping("/generate") + public R generate(@RequestBody InviteCodeBo bo) { + // 设置当前登录用户为邀请人 + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + + return R.ok(inviteCodeService.generateInviteCode(bo)); + } + + /** + * 验证邀请码 + */ + @SaIgnore + @GetMapping("/validate") + public R validate(@RequestParam("code") String code) { + TInviteCode inviteCode = inviteCodeService.validateInviteCode(code); + return R.ok(inviteCode != null); + } + + /** + * 使用邀请码(注册时调用) + */ + @SaIgnore + @PostMapping("/use") + public R useInviteCode(@RequestParam("code") String code, @RequestParam("userId") Long userId) { + return R.ok(inviteCodeService.useInviteCode(code, userId)); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TInviteRelationsController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TInviteRelationsController.java new file mode 100644 index 0000000..dc602f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TInviteRelationsController.java @@ -0,0 +1,113 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.StreamUtils; +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.bo.SysPostBo; +import org.dromara.system.domain.bo.SysRoleBo; +import org.dromara.system.domain.vo.SysRoleVo; +import org.dromara.system.domain.vo.SysUserInfoVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysPostService; +import org.dromara.system.service.ISysRoleService; +import org.dromara.system.service.ISysUserService; +import org.dromara.zhishu.domain.TInviteRelations; +import org.dromara.zhishu.domain.bo.TInviteRelationsBo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.TInviteRelationsVo; +import org.dromara.zhishu.service.ITInviteRelationsService; +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.Map; + +import java.util.List; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/inviteRelations") +public class TInviteRelationsController { + + private final ITInviteRelationsService tInviteRelationsService; + private final ISysUserService userService; + private final ISysRoleService roleService; + private final ISysPostService postService; + + @SaIgnore + @GetMapping("/list") + public R> list() { + try { + List data = tInviteRelationsService.selectByInviterId(LoginHelper.getUserId()); + if (data == null) { + return R.fail(400, "no data"); + } + Map row = new HashMap<>(); + row.put("rows", data); + return R.ok(row); + } catch (Exception e) { + return R.fail(400, e.getMessage()); + } + } + + + @SaIgnore + @GetMapping("/userShopList") + public R> userShopList() { + try { + List data = tInviteRelationsService.selectUserShopList(LoginHelper.getUserId()); + if (data == null) { + return R.fail(400, "no data"); + } + Map row = new HashMap<>(); + row.put("rows", data); + return R.ok(row); + } catch (Exception e) { + return R.fail(400, e.getMessage()); + } + } + + /** + * 查询用户信息 + * @param userId + * @return + */ + @SaCheckPermission("inviteRelations:user:query") + @GetMapping("/{userId}") + public R getInfo(@PathVariable Long userId) { + SysUserInfoVo userInfoVo = new SysUserInfoVo(); + + // 获取用户基本信息 + SysUserVo sysUser = userService.selectUserById(userId); + userInfoVo.setUser(sysUser); + + // 获取用户角色ID列表 + userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId)); + + // 获取用户岗位信息(如果有部门) + if (ObjectUtil.isNotNull(sysUser.getDeptId())) { + SysPostBo postBo = new SysPostBo(); + postBo.setDeptId(sysUser.getDeptId()); + userInfoVo.setPosts(postService.selectPostList(postBo)); + userInfoVo.setPostIds(postService.selectPostListByUserId(userId)); + } + + // 获取所有角色列表(过滤掉超级管理员) + SysRoleBo roleBo = new SysRoleBo(); + roleBo.setStatus(SystemConstants.NORMAL); + List roles = roleService.selectRoleList(roleBo); + userInfoVo.setRoles(StreamUtils.filter(roles, r -> !r.isSuperAdmin())); + + return R.ok(userInfoVo); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TLogisticsController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TLogisticsController.java new file mode 100644 index 0000000..daab6cb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TLogisticsController.java @@ -0,0 +1,143 @@ +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.dromara.zhishu.domain.bo.PrinterBo; +import org.dromara.zhishu.domain.bo.TLogisticsBo; +import org.dromara.zhishu.domain.vo.PrinterVo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TLogisticsVo; +import org.dromara.zhishu.service.ITLogisticsService; +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-04-22 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/logistics") +public class TLogisticsController extends BaseController { + + private final ITLogisticsService tLogisticsService; + + /** + * 查询物流管理列表 + */ + @GetMapping("/list") + public TableDataInfo list(TLogisticsBo bo, PageQuery pageQuery) { + return tLogisticsService.queryPageList(bo, pageQuery); + } + + /** + * 查询全部打印机设置 + * @param bo + * @return + */ + @GetMapping("/listNoPage") + public List listNoPage(TLogisticsBo bo){ + return tLogisticsService.queryList(bo); + } + + /** + * 导出物流管理列表 + */ + @SaCheckPermission("zhishu:logistics:export") + @Log(title = "物流管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TLogisticsBo bo, HttpServletResponse response) { + List list = tLogisticsService.queryList(bo); + ExcelUtil.exportExcel(list, "物流管理", TLogisticsVo.class, response); + } + + /** + * 获取物流管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:logistics:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tLogisticsService.queryById(id)); + } + + /** + * 新增物流管理 + */ + @Log(title = "物流管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + @SaIgnore + public R add(@Validated(AddGroup.class) @RequestBody TLogisticsBo bo) { + return toAjax(tLogisticsService.insertByBo(bo)); + } + + /** + * 修改物流管理 + */ + @Log(title = "物流管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + @SaIgnore + public R edit(@Validated(EditGroup.class) @RequestBody TLogisticsBo bo) { + return toAjax(tLogisticsService.updateByBo(bo)); + } + + /** + * 删除物流管理 + * + * @param ids 主键串 + */ + @Log(title = "物流管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + @SaIgnore + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tLogisticsService.deleteWithValidByIds(List.of(ids), true)); + } + +// @SaCheckPermission("zhishu:logistics:namelist") + @GetMapping("/namelist") + @SaIgnore + public TableDataInfo list1() { + List list= tLogisticsService.queryNameList(); + return TableDataInfo.build(list); + } + + @GetMapping("/getList") + @SaIgnore + public TableDataInfo getList(Long userId) { + List list= tLogisticsService.getList(userId); + return TableDataInfo.build(list); + } + + /** + * 小程序获取运费模板 + */ + @GetMapping("/xcx/list") + @SaIgnore + public TableDataInfo xcxList(@RequestParam Long userId) { + List list= tLogisticsService.queryNameListByXcx(userId); + return TableDataInfo.build(list); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShelvesController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShelvesController.java new file mode 100644 index 0000000..fbfa17e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShelvesController.java @@ -0,0 +1,188 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +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.zhishu.domain.bo.TShelvesBo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TFreightVo; +import org.dromara.zhishu.domain.vo.TShelvesVo; +import org.dromara.zhishu.service.ITDepotService; +import org.dromara.zhishu.service.ITShelvesService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 货架信息 + * + * @author Lion Li + * @date 2025-03-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/shelves/shelves") +public class TShelvesController extends BaseController { + + private final ITShelvesService tShelvesService; + private final ITDepotService tDepotService; + + /** + * 查询货架信息列表 + */ + @SaCheckPermission("shelves:shelves:list") + @GetMapping("/list") + public TableDataInfo list(TShelvesBo bo, PageQuery pageQuery) { + return tShelvesService.queryPageList(bo, pageQuery); + } + + /** + * 导出货架信息列表 + */ + @SaCheckPermission("shelves:shelves:export") + @Log(title = "货架信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TShelvesBo bo, HttpServletResponse response) { + List list = tShelvesService.queryList1(); + ExcelUtil.exportExcel(list, "货架信息", TShelvesVo.class, response); + } + + /** + * 获取货架信息详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("shelves:shelves:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tShelvesService.queryById(id)); + } + + /** + * 前台本地回显用查询函数 + */ + @SaCheckPermission("shelves:shelves:query") + @GetMapping("/forLocal/{depotId}/{code}") + public R getInfo(@PathVariable("depotId") Long depotId, @PathVariable("code") String code) { + return R.ok(tShelvesService.queryFoundId(depotId, code)); + } + + /** + * 新增货架信息 + */ + @SaCheckPermission("shelves:shelves:add") + @Log(title = "货架信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + @SaIgnore + public R add(@Validated(AddGroup.class) @RequestBody TShelvesBo bo) { + try{ + tShelvesService.insertByBo(bo); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + return R.ok(bo); + } + + /** + * 修改货架信息 + */ + @SaCheckPermission("shelves:shelves:edit") + @Log(title = "货架信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + @SaIgnore + public R edit(@Validated(EditGroup.class) @RequestBody TShelvesBo bo) { + try{ + tShelvesService.updateByBo(bo); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + return R.ok(bo); + } + + /** + * 删除货架信息 + * + * @param ids 主键串 + */ + @SaCheckPermission("shelves:shelves:remove") + @Log(title = "货架信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + @SaIgnore + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids, + @RequestParam(required = false) Long LocalUserId) { + return toAjax(tShelvesService.deleteWithValidByIds(List.of(ids), true,LocalUserId)); + } + + /** + * 查询仓库信息列表 + */ +// @SaIgnore + @SaCheckPermission("shelves:shelves:namelist") + @GetMapping("/namelist") + @SaIgnore + public TableDataInfo list1(String phoneNumber) { + List list= tDepotService.queryNameList(phoneNumber); + return TableDataInfo.build(list); + } + + /** + * 查询货架id,code列表 + */ + @GetMapping("/sheNamelist") + @SaIgnore + public TableDataInfo listShe(String depotId) { + List list= tDepotService.querySheNameList(depotId); + return TableDataInfo.build(list); + } + /** + * 查询货位id,code列表 + */ + + @GetMapping("/freNamelist") + @SaIgnore + public TableDataInfo listFre(String sheId) { + List list= tDepotService.queryFreNameList(sheId); + return TableDataInfo.build(list); + } + + @GetMapping("/sheNamelist/{depotId}") + @SaIgnore + public TableDataInfo listShe1(@PathVariable String depotId) { + List list= tDepotService.querySheNameList(depotId); + return TableDataInfo.build(list); + } + @GetMapping("/freNamelist/{sheId}") + @SaIgnore + public TableDataInfo listFre1(@PathVariable String sheId) { + List list= tDepotService.queryFreNameList(sheId); + return TableDataInfo.build(list); + } + + @GetMapping("/getShelvesId") + @SaIgnore + public TableDataInfo getShelvesId(String depotId,String code) { + List list= tShelvesService.selectShelvesIdByDepotIdAndCode(depotId,code); + return TableDataInfo.build(list); + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopDepotAotuController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopDepotAotuController.java new file mode 100644 index 0000000..81e3f8f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopDepotAotuController.java @@ -0,0 +1,52 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import lombok.RequiredArgsConstructor; +import jakarta.validation.constraints.*; +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.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.zhishu.domain.vo.TShopDepotAotuVo; +import org.dromara.zhishu.domain.bo.TShopDepotAotuBo; +import org.dromara.zhishu.service.ITShopDepotAotuService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 店铺自动发布仓库关联 + * + * @author Lion Li + * @date 2025-09-05 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopDepotAotu") +public class TShopDepotAotuController extends BaseController { + + private final ITShopDepotAotuService tShopDepotAotuService; + + /** + * 查询店铺自动发布仓库关联列表 + */ + @SaCheckPermission("zhishu:shopDepotAotu:list") + @GetMapping("/list") + public TableDataInfo list(@ModelAttribute TShopDepotAotuBo bo, PageQuery pageQuery) { + return tShopDepotAotuService.queryPageList(bo, pageQuery); + } + + /** + * 获取店铺自动发布仓库关联详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shopDepotAotu:list") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tShopDepotAotuService.queryById(id)); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopOrderDetailController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopOrderDetailController.java new file mode 100644 index 0000000..02e7c24 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TShopOrderDetailController.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.TShopOrderDetailVo; +import org.dromara.zhishu.domain.bo.TShopOrderDetailBo; +import org.dromara.zhishu.service.ITShopOrderDetailService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 订单详情 + * + * @author Lion Li + * @date 2025-03-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopOrderDetail") +public class TShopOrderDetailController extends BaseController { + + private final ITShopOrderDetailService tShopOrderDetailService; + + /** + * 查询订单详情列表 + */ + @SaCheckPermission("zhishu:shopOrderDetail:list") + @GetMapping("/list") + public TableDataInfo list(TShopOrderDetailBo bo, PageQuery pageQuery) { + return tShopOrderDetailService.queryPageList(bo, pageQuery); + } + + /** + * 导出订单详情列表 + */ + @SaCheckPermission("zhishu:shopOrderDetail:export") + @Log(title = "订单详情", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(TShopOrderDetailBo bo, HttpServletResponse response) { + List list = tShopOrderDetailService.queryList(bo); + ExcelUtil.exportExcel(list, "订单详情", TShopOrderDetailVo.class, response); + } + + /** + * 获取订单详情详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shopOrderDetail:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(tShopOrderDetailService.queryById(id)); + } + + /** + * 新增订单详情 + */ + @SaCheckPermission("zhishu:shopOrderDetail:add") + @Log(title = "订单详情", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TShopOrderDetailBo bo) { + return toAjax(tShopOrderDetailService.insertByBo(bo)); + } + + /** + * 修改订单详情 + */ + @SaCheckPermission("zhishu:shopOrderDetail:edit") + @Log(title = "订单详情", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TShopOrderDetailBo bo) { + return toAjax(tShopOrderDetailService.updateByBo(bo)); + } + + /** + * 删除订单详情 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:shopOrderDetail:remove") + @Log(title = "订单详情", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(tShopOrderDetailService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TestController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TestController.java new file mode 100644 index 0000000..7349e78 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/TestController.java @@ -0,0 +1,93 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import jakarta.annotation.Resource; +import org.redisson.Redisson; +import org.redisson.api.RLock; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.TimeUnit; + +@RestController +@RequestMapping("/test") +public class TestController { + + + @Resource + Redisson redisson; + + @Resource + StringRedisTemplate stringRedisTemplate; + + @RequestMapping("/sub_stock") + @SaIgnore + public String deductStock5() { + String lockKey = "lock_good_stock"; + RLock lock = redisson.getLock(lockKey); + lock.lock(60, TimeUnit.SECONDS); + try { + int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("good_stock")); + if (stock > 0) { + int realStock = stock - 1; + stringRedisTemplate.opsForValue().set("good_stock", realStock + ""); + System.out.println("扣减成功,剩余库存:" + realStock); + } else { + System.out.println("扣减失败,库存不足"); + } + } finally { + lock.unlock(); + } + return "ok"; + } + + @SaIgnore + @RequestMapping("/add_stock") + + public String addStock() { + stringRedisTemplate.opsForValue().set("good_stock", "60"); + return "ok"; + } + + @SaIgnore + @RequestMapping("/get_stock") + + public String get_stock() { + return stringRedisTemplate.opsForValue().get("good_stock"); + } + + + @SaIgnore + @RequestMapping("/sub_stock1") + + public String sub_stock1() { + String lockKey = "lock_good_stock"; + RLock lock = redisson.getLock(lockKey); + lock.lock(30, TimeUnit.SECONDS); + try { + int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("good_stock")); + if(stock>0){ + stringRedisTemplate.opsForValue().set("good_stock", stock-1 + ""); + System.out.println("库存不足"); + }else{ + System.out.println("库存不足"); + } + + }catch (Exception e){ + + }finally { + lock.unlock(); + } + + + + + + return stringRedisTemplate.opsForValue().get("good_stock"); + } + + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserAccountController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserAccountController.java new file mode 100644 index 0000000..638b4ec --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserAccountController.java @@ -0,0 +1,116 @@ +package org.dromara.zhishu.controller; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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.UserAccountVo; +import org.dromara.zhishu.domain.bo.UserAccountBo; +import org.dromara.zhishu.service.IUserAccountService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 账号管理 + * + * @author yxy + * @date 2026-02-25 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/userAccount") +public class UserAccountController extends BaseController { + + private final IUserAccountService userAccountService; + + /** + * 查询账号管理列表 + */ + @SaCheckPermission("zhishu:userAccount:list") + @GetMapping("/list") + public TableDataInfo list(UserAccountBo bo, PageQuery pageQuery) { + return userAccountService.queryPageList(bo, pageQuery); + } + + @SaCheckPermission("zhishu:userAccount:list") + @GetMapping("/listNoPage") + public Map> listNoPage(UserAccountBo bo) { + Map> map = new HashMap<>(); + map.put("adminList",userAccountService.queryListAdmin(bo)); + map.put("userList",userAccountService.queryList(bo)); + return map; + } + + /** + * 导出账号管理列表 + */ + @SaCheckPermission("zhishu:userAccount:export") + @Log(title = "账号管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(UserAccountBo bo, HttpServletResponse response) { + List list = userAccountService.queryList(bo); + ExcelUtil.exportExcel(list, "账号管理", UserAccountVo.class, response); + } + + /** + * 获取账号管理详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:userAccount:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(userAccountService.queryById(id)); + } + + /** + * 新增账号管理 + */ + @SaCheckPermission("zhishu:userAccount:add") + @Log(title = "账号管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody UserAccountBo bo) { + return toAjax(userAccountService.insertByBo(bo)); + } + + /** + * 修改账号管理 + */ + @SaCheckPermission("zhishu:userAccount:edit") + @Log(title = "账号管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody UserAccountBo bo) { + return toAjax(userAccountService.updateByBo(bo)); + } + + /** + * 删除账号管理 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:userAccount:remove") + @Log(title = "账号管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(userAccountService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserInfoController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserInfoController.java new file mode 100644 index 0000000..8de46ab --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserInfoController.java @@ -0,0 +1,25 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.satoken.utils.LoginHelper; +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.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/userInfo") +public class UserInfoController { + + @SaIgnore + @GetMapping(value = "/getUserId") + public Long getUserId(@RequestParam("token") String token){ + LoginUser user = LoginHelper.getLoginUser(token); + return user.getUserId(); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserRechargeController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserRechargeController.java new file mode 100644 index 0000000..f89f678 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/UserRechargeController.java @@ -0,0 +1,356 @@ +package org.dromara.zhishu.controller; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSONObject; +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.DateUtils; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.ISysUserService; +import org.dromara.system.service.IUserTransferService; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.UserAccountVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.IUserAccountService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.WxPayUtil; +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.UserRechargeVo; +import org.dromara.zhishu.domain.bo.UserRechargeBo; +import org.dromara.zhishu.service.IUserRechargeService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 用户充值 + * + * @author yxy + * @date 2025-04-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/userRecharge") +public class UserRechargeController extends BaseController { + + private final IUserRechargeService userRechargeService; + private final ISysConfigService configService; + private final IUserAccountService userAccountService; + private final ISysUserService userService; + private final IShopService shopService; + + + /** + * 查询用户充值列表 + */ + @SaCheckPermission("zhishu:userRecharge:list") + @GetMapping("/list") + public TableDataInfo list(UserRechargeBo bo, PageQuery pageQuery) { + return userRechargeService.queryPageList(bo, pageQuery); + } + + /** + * 导出用户充值列表 + */ + @SaCheckPermission("zhishu:userRecharge:export") + @Log(title = "用户充值", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(UserRechargeBo bo, HttpServletResponse response) { + List list = userRechargeService.queryList(bo); + ExcelUtil.exportExcel(list, "用户充值", UserRechargeVo.class, response); + } + + /** + * 获取用户充值详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:userRecharge:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(userRechargeService.queryById(id)); + } + + @GetMapping(value = "/configKey/{configKey}") + public R getConfigKey(@PathVariable String configKey) { + return R.ok(configService.selectConfigByKey(configKey)); + } + + /** + * 新增用户充值 + */ + @SaCheckPermission("zhishu:userRecharge:add") + @Log(title = "用户充值", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody UserRechargeBo bo) { + return toAjax(userRechargeService.insertByBo(bo)); + } + + @PostMapping("/userRechargeNoCommission") + public R userRechargeNoCommission(@RequestBody UserRechargeBo bo){ + //支付方式 1 微信 + String type = bo.getRechargType(); + //充值金额 单位 元 + BigDecimal price = bo.getRechargPrice(); + //计算后金额 单位 分 + BigDecimal priceResult = price.multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP); + + bo.setCommission(BigDecimal.ZERO); + + //获取登录用户id + String userId = LoginHelper.getUserId().toString(); + if(type.equals("1")){ + //换算手续费为 分 + bo.setRechargPrice(bo.getRechargPrice().multiply(new BigDecimal(100))); + //创建任务 + bo.setUserId(Long.parseLong(userId)); + //状态 0 待支付 1 支付完成 2 支付过期 + bo.setStatus("0"); + userRechargeService.insertByBo(bo); + String data = WxPayUtil.wxPay(bo.getId(),Integer.parseInt(priceResult.toString()),price.toString()); + + String base64Str = WxPayUtil.generateQRCode(data); + + Map map = new HashMap(); + map.put("img",base64Str); + map.put("id", bo.getId()); + return R.ok(map); + } + return R.fail("充值订单生成失败,请联系管理员"); + } + + @PostMapping("/userRecharge") + public R userRecharge(@RequestBody UserRechargeBo bo){ + //支付方式 1 微信 2 线下支付 3 卡密支付 + String type = bo.getRechargType(); + //充值金额 单位 元 + BigDecimal price = bo.getRechargPrice(); + + //获取登录用户id + String userId = LoginHelper.getUserId().toString(); + + if(type.equals("1")){ + //手续费 单位 元 + String commissionStr = new BigDecimal(configService.selectConfigByKey("becharge.commission")).divide(new BigDecimal(10000)).toString(); + BigDecimal commission = price.multiply(new BigDecimal(commissionStr)); + //计算后金额 单位 分 + BigDecimal priceResult = price.add(commission).multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP); + //手续费换算单位为分 + commission = commission.multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP); + + if(commission.compareTo(new BigDecimal(0)) == 0){ + commission = new BigDecimal(1); + } + bo.setCommission(commission); + + + + //换算手续费为 分 + bo.setRechargPrice(bo.getRechargPrice().multiply(new BigDecimal(100))); + //创建任务 + bo.setUserId(Long.parseLong(userId)); + //状态 0 待支付 1 支付完成 2 支付过期 3 审核中 4 审核通过 5 拒绝 + bo.setStatus("0"); + userRechargeService.insertByBo(bo); + String data = WxPayUtil.wxPay(bo.getId(),Integer.parseInt(priceResult.toString()),price.toString()); + + String base64Str = WxPayUtil.generateQRCode(data); + + Map map = new HashMap(); + map.put("img",base64Str); + map.put("id", bo.getId()); + return R.ok(map); + }else if (type.equals("2")){ + // 出账用户 + UserAccountVo billingAccountVo = userAccountService.queryById(Long.parseLong(bo.getBillingAccount())); + // 入账用户 + UserAccountVo depositAccountVo = userAccountService.queryById(Long.parseLong(bo.getDepositAccount())); + // 充值金额 + price = price.multiply(new BigDecimal(100)); + // 线下充值 + JSONObject jsonObject = new JSONObject(); + jsonObject.put("rechargPrice",price); + jsonObject.put("billingAccount",bo.getBillingAccount()); + jsonObject.put("billingTxt","【"+billingAccountVo.getAccountType()+"】"+"【"+billingAccountVo.getAccountName()+"】"+"【"+billingAccountVo.getAccount()+"】"); + jsonObject.put("depositAccount",bo.getDepositAccount()); + jsonObject.put("depositTxt","【"+depositAccountVo.getAccountType()+"】"+"【"+depositAccountVo.getAccountName()+"】"+"【"+depositAccountVo.getAccount()+"】"); + jsonObject.put("transactionId",bo.getTransactionId()); + jsonObject.put("remark",bo.getRemark()); + jsonObject.put("voucherImg",bo.getVoucherImg()); + + String json = jsonObject.toString(); + bo.setAllDataStr(json); + bo.setRechargPrice(price); + bo.setLogTxt("入账账户:"+jsonObject.get("depositTxt")); + //状态 0 待支付 1 支付完成 2 支付过期 3 审核中 4 审核通过 5 拒绝 + bo.setStatus("3"); + userRechargeService.insertByBo(bo); + return R.ok("提交充值订单成功"); + }else if (type.equals("3")){ + // 卡密支付 + String cardKey = bo.getCardKey(); + String result = InterfaceUtils.getInterface("https://wallet.api.buzhiyushu.cn","/api/card/activate/"+cardKey+"/ERP-"+userId); + Map resultMap = JsonUtil.transferToObj(result,Map.class); + String msg = resultMap.get("message").toString(); + String code = resultMap.get("code").toString(); + if (code.equals("200")){ + // 成功 + Map dataMap = (Map) resultMap.get("data"); + BigDecimal points = new BigDecimal(dataMap.get("points").toString()).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN); // 直接舍弃小数部分; + SysUserVo userVo = userService.selectUserById(Long.parseLong(userId)); + BigDecimal newPrice = userVo.getBalance().add(points); + bo.setRechargPrice(points); + bo.setStatus("1"); + bo.setLogTxt("卡密:"+cardKey); + bo.setOriginalPrice(userVo.getBalance()); + bo.setUpdatePrice(newPrice); + bo.setSuccessTime(DateUtils.getNowDate()); + userRechargeService.insertByBo(bo); + SysUserBo userBo = new SysUserBo(); + userBo.setUserId(userVo.getUserId()); + userBo.setBalance(newPrice); + userService.updateUser(userBo); + return R.ok(msg); + }else{ + return R.fail(500,"支付失败:"+msg); + } + } + + return R.fail("充值订单生成失败,请联系管理员"); + } + + + @PostMapping("/balancePayment") + public R balancePayment(@RequestBody Map map){ + Long userId = map.get("userId") == null ? LoginHelper.getUserId() : Long.parseLong(map.get("userId").toString()); + Long shopId = map.get("shopId") == null ? null : Long.parseLong(map.get("shopId").toString()); + int logType = map.get("logType") == null ? 0 : Integer.parseInt(map.get("logType").toString()); + BigDecimal rechargPrice = map.get("rechargPrice") == null ? new BigDecimal(0) : new BigDecimal(map.get("rechargPrice").toString()); + rechargPrice = rechargPrice.multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN); + return userRechargeService.balancePayment(userId,shopId,logType,rechargPrice); + } + + + @PostMapping("/apiBalancePayment") + @SaIgnore + public R apiBalancePayment(Long userId,Long shopId,int logType,Long rechargPrice){ + BigDecimal newRechargPrice = new BigDecimal(rechargPrice).multiply(new BigDecimal(100)).setScale(0, RoundingMode.DOWN); + return userRechargeService.balancePayment(userId,shopId,logType,newRechargPrice); + } + + @PostMapping("/review") + public R review(@RequestBody Map map){ + // type 0 拒绝 1 通过 + String type = map.get("type"); + String status = null; + if (type.equals("1")){ + status = "4"; + }else{ + status = "5"; + } + String idsStr = map.get("ids"); + String[] ids = idsStr.split(","); + for (String id : ids){ + // 如果是通过,则增加用户的金额 + UserRechargeVo vo = userRechargeService.queryById(Long.parseLong(id)); + if (!vo.getStatus().equals("3")){ + continue; + } + UserRechargeBo bo = new UserRechargeBo(); + if (type.equals("1")){ + // 申请人 + String createBy = vo.getCreateBy(); + // 申请金额 + Long rechargPrice = vo.getRechargPrice(); + SysUserVo userVo = userService.selectUserById(Long.parseLong(createBy)); + BigDecimal newPrice = userVo.getBalance().add(new BigDecimal(rechargPrice)); + SysUserBo userBo = new SysUserBo(); + userBo.setUserId(userVo.getUserId()); + userBo.setBalance(newPrice); + userService.updateUser(userBo); + // 记录新旧价格 + bo.setOriginalPrice(userVo.getBalance()); + bo.setUpdatePrice(newPrice); + bo.setSuccessTime(DateUtils.getNowDate()); + } + bo.setId(Long.parseLong(id)); + bo.setStatus(status); + userRechargeService.updateByBo(bo); + } + + return R.ok(); + } + + /** + * 充值金额到钱包里 + * @return + */ + @PostMapping("/addUserBalance") + public R addUserBalance(@RequestBody UserRechargeBo bo){ + return userRechargeService.addUserBalance(bo); + } + + + @GetMapping("/checkTask/{id}") + public String checkTask(@PathVariable("id") String id){ + UserRechargeVo userRechargeVo = userRechargeService.queryById(Long.parseLong(id)); + return userRechargeVo.getStatus(); + } + + @GetMapping("/editRechargeToError/{id}") + public void editRechargeToError(@PathVariable("id") String id){ + UserRechargeBo bo = new UserRechargeBo(); + bo.setId(Long.parseLong(id)); + bo.setStatus("2"); + userRechargeService.updateByBo(bo); + } + + /** + * 修改用户充值 + */ + @SaCheckPermission("zhishu:userRecharge:edit") + @Log(title = "用户充值", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody UserRechargeBo bo) { + return toAjax(userRechargeService.updateByBo(bo)); + } + + /** + * 删除用户充值 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:userRecharge:remove") + @Log(title = "用户充值", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(userRechargeService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ViolationController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ViolationController.java new file mode 100644 index 0000000..a21ea15 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ViolationController.java @@ -0,0 +1,221 @@ +package org.dromara.zhishu.controller; + +import java.util.List; +import java.util.Map; + +import cn.dev33.satoken.annotation.SaIgnore; +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.utils.DateUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.Violation; +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.ViolationVo; +import org.dromara.zhishu.domain.bo.ViolationBo; +import org.dromara.zhishu.service.IViolationService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 违规 + * + * @author yxy + * @date 2025-06-23 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/violation") +public class ViolationController extends BaseController { + + private final IViolationService violationService; + + /** + * 查询违规列表 + */ + @SaCheckPermission("zhishu:violation:list") + @GetMapping("/list") + public TableDataInfo list(ViolationBo bo, PageQuery pageQuery) { + return violationService.queryPageList(bo, pageQuery); + } + + + @SaIgnore + @PostMapping("/newList") + public TableDataInfo newList(@RequestBody Map map){ + // 安全地解析分页参数 + Integer pageSize = map.get("pageSize") != null ? + Integer.parseInt(map.get("pageSize").toString()) : 10; + Integer pageNum = map.get("pageNum") != null ? + Integer.parseInt(map.get("pageNum").toString()) : 1; + + PageQuery pageQuery = new PageQuery(pageSize, pageNum); + + // 安全地解析查询参数 + String type = map.get("type") != null ? map.get("type").toString() : ""; + String name = map.get("name") != null ? map.get("name").toString() : ""; + String review = map.get("review") != null ? map.get("review").toString() : ""; + String status = map.get("status") != null ? map.get("status").toString() : ""; + + ViolationBo bo = new ViolationBo(); + bo.setType(type); + bo.setName(name); + bo.setReview(review); + bo.setStatus(status); + + // 直接返回 TableDataInfo,包含完整的分页信息 + return violationService.queryPageList(bo, pageQuery); + } + + @SaIgnore + @PostMapping("/errorSubmit") + public void errorSubmit(@RequestBody Map map){ + String[] ids = map.get("ids").toString().split(","); + String remark = map.get("remark") == null ? "" : map.get("remark").toString(); + String review = map.get("review") == null ? "" : map.get("review").toString(); + + for (String id : ids){ + ViolationBo bo = new ViolationBo(); + bo.setId(Long.parseLong(id)); + bo.setRemark(remark); + bo.setReview(review); + violationService.updateByBo(bo); + } + } + + @SaIgnore + @PostMapping("/successSubmit") + public void successSubmit(@RequestBody Map map){ + String[] ids = map.get("ids").toString().split(","); + String review = map.get("review") == null ? "" : map.get("review").toString(); + for (String id : ids){ + ViolationBo bo = new ViolationBo(); + bo.setId(Long.parseLong(id)); + bo.setReview(review); + violationService.updateByBo(bo); + } + } + + @SaIgnore + @PostMapping("/removeSubmit") + public void removeSubmit(@RequestBody Map map){ + String[] ids = map.get("ids").toString().split(","); + + Long[] idsArr = new Long[ids.length]; + for(int i=0;i editType(@RequestBody Map map){ + + List ids = (List) map.get("ids"); + String type = map.get("type").toString(); + + for(String id : ids){ + ViolationBo bo = new ViolationBo(); + bo.setId(Long.parseLong(id)); + bo.setReview(type); + violationService.updateByBo(bo); + } + return R.ok(); + } + + /** + * 导出违规列表 + */ + @SaCheckPermission("zhishu:violation:export") + @Log(title = "违规", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ViolationBo bo, HttpServletResponse response) { + List list = violationService.queryList(bo); + ExcelUtil.exportExcel(list, "违规", ViolationVo.class, response); + } + + /** + * 获取违规详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:violation:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(violationService.queryById(id)); + } + + /** + * 新增违规 + */ + @SaCheckPermission("zhishu:violation:add") + @Log(title = "违规", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ViolationBo bo) { + //未审核状态 + bo.setReview("0"); + //发起人 + bo.setUserid(LoginHelper.getUserId()); + //创建人为管理员 + bo.setCreateBy(1L); + bo.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + return toAjax(violationService.insertByBo(bo)); + } + + /** + * 修改违规 + */ + @SaCheckPermission("zhishu:violation:edit") + @Log(title = "违规", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ViolationBo bo) { + return toAjax(violationService.updateByBo(bo)); + } + + /** + * 删除违规 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:violation:remove") + @Log(title = "违规", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(violationService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WarehouseSettingsController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WarehouseSettingsController.java new file mode 100644 index 0000000..df42b69 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WarehouseSettingsController.java @@ -0,0 +1,114 @@ +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.WarehouseSettings; +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.WarehouseSettingsVo; +import org.dromara.zhishu.domain.bo.WarehouseSettingsBo; +import org.dromara.zhishu.service.IWarehouseSettingsService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 设置 + * + * @author yxy + * @date 2025-12-19 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/warehouseSettings") +public class WarehouseSettingsController extends BaseController { + + private final IWarehouseSettingsService warehouseSettingsService; + + /** + * 查询设置列表 + */ + @SaCheckPermission("zhishu:warehouseSettings:list") + @GetMapping("/list") + public TableDataInfo list(WarehouseSettingsBo bo, PageQuery pageQuery) { + return warehouseSettingsService.queryPageList(bo, pageQuery); + } + + /** + * 导出设置列表 + */ + @SaCheckPermission("zhishu:warehouseSettings:export") + @Log(title = "设置", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(WarehouseSettingsBo bo, HttpServletResponse response) { + List list = warehouseSettingsService.queryList(bo); + ExcelUtil.exportExcel(list, "设置", WarehouseSettingsVo.class, response); + } + + /** + * 获取设置详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:warehouseSettings:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(warehouseSettingsService.queryById(id)); + } + + /** + * 新增设置 + */ + @SaCheckPermission("zhishu:warehouseSettings:add") + @Log(title = "设置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody WarehouseSettingsBo bo) { + return toAjax(warehouseSettingsService.insertByBo(bo)); + } + + /** + * 修改设置 + */ + @SaCheckPermission("zhishu:warehouseSettings:edit") + @Log(title = "设置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody WarehouseSettingsBo bo) { + return toAjax(warehouseSettingsService.updateByBo(bo)); + } + + @SaCheckPermission("zhishu:warehouseSettings:edit") + @Log(title = "设置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping("/editStatus") + public R editStatus(@Validated(EditGroup.class) @RequestBody WarehouseSettingsBo bo) { + return toAjax(warehouseSettingsService.updateStatus(bo)); + } + + /** + * 删除设置 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:warehouseSettings:remove") + @Log(title = "设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(warehouseSettingsService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WaveDetailController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WaveDetailController.java new file mode 100644 index 0000000..b565c73 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WaveDetailController.java @@ -0,0 +1,79 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.dto.WaveDetailRequestDto; +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.core.domain.R; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.zhishu.service.IWaveDetailService; + +import java.util.HashMap; +import java.util.Map; + +/** + * 波次信息 + * + * @author Lion Li + * @date 2026-01-22 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/wave/detail") +public class WaveDetailController extends BaseController { + + private final IWaveDetailService waveDetailService; + + /** + * 新增波次信息 + */ + @Log(title = "波次信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @SaIgnore + @PostMapping("/insert") + public R insert(@RequestBody WaveDetailRequestDto requestDto) { + Boolean result = waveDetailService.insertWaveDetail(requestDto.getUserId(), requestDto); + return result ? R.ok() : R.fail(); + } + + + /** + * 获取波次ID + */ + @Log(title = "波次信息", businessType = BusinessType.OTHER) + @RepeatSubmit() + @SaIgnore + @GetMapping("/getWaveId") + public Map getWaveId(@RequestParam("employeeName") String employeeName, @RequestParam("userId") String userId) { + Map result = new HashMap<>(); + try { + String waveId = waveDetailService.getEmployeeId(employeeName, userId); + result.put("code", 200); + result.put("data", waveId); + result.put("message", "获取波次ID成功"); + } catch (Exception e) { + result.put("code", 500); + result.put("data", null); + result.put("message", "获取波次ID失败: " + e.getMessage()); + } + return result; + } + + + /** + * 统计波次工作数量 + */ + @Log(title = "波次信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @SaIgnore + @PostMapping("/count") + public R count(@RequestParam String waveId, @RequestParam String employeeId, @RequestParam Integer submitCount) { + Boolean result = waveDetailService.countVerWave(waveId, employeeId, submitCount); + return result ? R.ok() : R.fail(); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WhiteListController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WhiteListController.java new file mode 100644 index 0000000..810d09d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/WhiteListController.java @@ -0,0 +1,141 @@ +package org.dromara.zhishu.controller; + +import java.net.InetAddress; +import java.net.UnknownHostException; +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.common.core.utils.StringUtils; +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.WhiteListVo; +import org.dromara.zhishu.domain.bo.WhiteListBo; +import org.dromara.zhishu.service.IWhiteListService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 白名单 + * + * @author yxy + * @date 2025-06-25 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/whiteList") +public class WhiteListController extends BaseController { + + private final IWhiteListService whiteListService; + + /** + * 查询白名单列表 + */ + @SaCheckPermission("zhishu:whiteList:list") + @GetMapping("/list") + public TableDataInfo list(WhiteListBo bo, PageQuery pageQuery) { + return whiteListService.queryPageList(bo, pageQuery); + } + + @GetMapping("/selectAll") + public String selectAll() { + + List voList = whiteListService.selectAll(); + + String ips = ""; + for(WhiteListVo vo : voList){ + if(StringUtils.isEmpty(ips)){ + ips = vo.getIp(); + }else{ + ips = ips + "," + vo.getIp(); + } + } + return ips; + } + + /** + * 导出白名单列表 + */ + @SaCheckPermission("zhishu:whiteList:export") + @Log(title = "白名单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(WhiteListBo bo, HttpServletResponse response) { + List list = whiteListService.queryList(bo); + ExcelUtil.exportExcel(list, "白名单", WhiteListVo.class, response); + } + + /** + * 获取白名单详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:whiteList:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(whiteListService.queryById(id)); + } + + @PostMapping("/setWhiteList") + public R setWhiteList(String ips) { + //清空白名单表 + whiteListService.deleteAll(); + + + //分割ips,创建WhiteListBo进行insert + String[] ipArray = ips.split(","); + for (String ip : ipArray){ + WhiteListBo bo = new WhiteListBo(); + bo.setIp(ip); + bo.setCreateBy(1L); + whiteListService.insertByBo(bo); + } + return R.ok(); + } + + /** + * 新增白名单 + */ + @SaCheckPermission("zhishu:whiteList:add") + @Log(title = "白名单", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody WhiteListBo bo) { + return toAjax(whiteListService.insertByBo(bo)); + } + + /** + * 修改白名单 + */ + @SaCheckPermission("zhishu:whiteList:edit") + @Log(title = "白名单", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody WhiteListBo bo) { + return toAjax(whiteListService.updateByBo(bo)); + } + + /** + * 删除白名单 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:whiteList:remove") + @Log(title = "白名单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(whiteListService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XcxController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XcxController.java new file mode 100644 index 0000000..c11a019 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XcxController.java @@ -0,0 +1,481 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.api.Http; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.core.domain.R; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.impl.SysUserServiceImpl; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.WxPayUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.Base64; + +@RestController +@RequestMapping("/xcx") +public class XcxController { + + @Autowired + private IShopService shopService; + + // 微信小程序支付相关配置 + private static final String APPID = "wx703b8fb6c3da692a"; + private static final String MERCHANT_ID = "1524946931"; + private static final String NOTIFY_URL = "https://api.buzhiyushu.cn/weChat/wxPayCallBack"; + private final ISysConfigService configService; + + public XcxController(ISysConfigService configService) { + this.configService = configService; + } + + @GetMapping("/getShopId/{userId}") + @SaIgnore + public R> getShopId(@PathVariable Long userId) { + return R.ok(shopService.getShopId(userId)); + } + + /** + * 小程序JSAPI支付统一下单 + */ + @SaIgnore + @PostMapping("/jsapiPay") + public R> jsapiPay(@RequestBody Map requestData) { + try { + // 获取请求参数 + String openid = (String) requestData.get("openid"); + Long taskId = Long.valueOf(requestData.get("taskId").toString()); + Integer total = Integer.valueOf(requestData.get("total").toString()); + String totalStr = (String) requestData.get("totalStr"); + String description = (String) requestData.get("description"); + + if (openid == null || openid.isEmpty()) { + return R.fail("openid不能为空"); + } + + System.out.println("JSAPI支付请求参数: openid=" + openid + ", appid=" + APPID); + + // 生成订单号 + String outTradeNo = UUID.randomUUID().toString().replace("-", ""); + System.out.println("生成的订单号: " + outTradeNo); + // 调用WxPayUtil的xcxPay方法,传入openid和订单号 + // 注意:需要修改WxPayUtil.xcxPay方法,添加outTradeNo参数 + String prepayId = WxPayUtil.xcxPay(taskId, total, totalStr, openid, APPID, outTradeNo); + System.out.println("获取到的prepayId: " + prepayId); + + // 生成小程序调起支付的参数 + Map payParams = generatePayParams(prepayId); + payParams.put("outTradeNo", outTradeNo); + System.out.println("生成的支付参数: " + JsonUtils.toJsonString(payParams)); + + // 直接返回支付参数,不要嵌套 + return R.ok(payParams); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("支付下单失败:" + e.getMessage()); + } + } + + /** + * 调用微信支付API + */ + private String callWxPayApi(String path, Map requestData) throws Exception { + String url = "https://api.mch.weixin.qq.com" + path; + String requestBody = requestData != null ? JsonUtils.toJsonString(requestData) : ""; + + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost request = new HttpPost(url); + request.setHeader("Content-Type", "application/json"); + request.setHeader("Accept", "application/json"); + + // 添加微信支付签名 + String signature = WxPayUtil.generateSignature(requestBody, path); + request.setHeader("Authorization", "WECHATPAY2-SHA256-RSA2048 " + signature); + + if (requestData != null) { + StringEntity entity = new StringEntity(requestBody, "UTF-8"); + request.setEntity(entity); + } + + try (CloseableHttpResponse response = httpClient.execute(request)) { + HttpEntity responseEntity = response.getEntity(); + if (responseEntity != null) { + return EntityUtils.toString(responseEntity); + } + } + } + return null; + } + + /** + * 生成小程序调起支付的参数 + */ + private Map generatePayParams(String prepayId) throws Exception { + // 构建请求参数 + String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); + // 生成随机字符串 + String nonceStr = UUID.randomUUID().toString().replace("-", ""); + // 构建package参数 + String packageStr = "prepay_id=" + prepayId; + // 构建签名字符串 + String signString = APPID + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageStr + "\n"; + String paySign = WxPayUtil.generatePaySign(signString); + Map payParams = new HashMap<>(); + payParams.put("appId", APPID); + payParams.put("timeStamp", timeStamp); + payParams.put("nonceStr", nonceStr); + payParams.put("package", packageStr); + payParams.put("signType", "RSA"); + payParams.put("paySign", paySign); + return payParams; + } + + /** + * 查询订单状态 + */ + @SaIgnore + @PostMapping("/queryOrder") + public R> queryOrder(@RequestBody Map requestData) { + try { + String outTradeNo = (String) requestData.get("outTradeNo"); + if (outTradeNo == null || outTradeNo.isEmpty()) { + return R.fail("订单号不能为空"); + } + + // 使用专门的GET请求方法调用微信API + String path = "/v3/pay/transactions/out-trade-no/" + outTradeNo + "?mchid=" + MERCHANT_ID; + String result = callWxPayApiGet(path); + + if (result == null || result.isEmpty()) { + return R.fail("查询订单返回为空"); + } + + Map responseMap = JsonUtils.parseObject(result, Map.class); + System.out.println("查询订单结果: " + result); + return R.ok(responseMap); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("查询订单失败:" + e.getMessage()); + } + } + + /** + * 调用微信支付API (GET方法) + */ + private String callWxPayApiGet(String path) throws Exception { + String url = "https://api.mch.weixin.qq.com" + path; + + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + org.apache.http.client.methods.HttpGet request = new org.apache.http.client.methods.HttpGet(url); + request.setHeader("Content-Type", "application/json"); + request.setHeader("Accept", "application/json"); + + // 生成时间戳和随机串 + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonceStr = UUID.randomUUID().toString().replace("-", ""); + + // 构建签名字符串 - GET请求的格式 + String signString = "GET\n" + path + "\n" + timestamp + "\n" + nonceStr + "\n\n"; + String signature = WxPayUtil.generatePaySign(signString); + + // 构建完整的认证头 + String token = "WECHATPAY2-SHA256-RSA2048 " + + "mchid=\"" + MERCHANT_ID + "\"," + + "nonce_str=\"" + nonceStr + "\"," + + "signature=\"" + signature + "\"," + + "timestamp=\"" + timestamp + "\"," + + "serial_no=\"1FD5B441796BE0250622018DF43EC4BAFB34FB78\""; + + request.setHeader("Authorization", token); + + System.out.println("查询订单URL: " + url); + System.out.println("查询订单认证头: " + token); + + try (CloseableHttpResponse response = httpClient.execute(request)) { + HttpEntity responseEntity = response.getEntity(); + if (responseEntity != null) { + return EntityUtils.toString(responseEntity); + } + } + } + return null; + } + + /** + * 关闭订单 + */ + @SaIgnore + @PostMapping("/closeOrder") + public R closeOrder(@RequestBody Map requestData) { + try { + String outTradeNo = (String) requestData.get("outTradeNo"); + + Map requestMap = new HashMap<>(); + requestMap.put("mchid", MERCHANT_ID); + + String path = "/v3/pay/transactions/out-trade-no/" + outTradeNo + "/close"; + String result = callWxPayApi(path, requestMap); + + return R.ok("订单关闭成功"); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("关闭订单失败:" + e.getMessage()); + } + } + + /** + * 申请退款 + */ + @SaIgnore + @PostMapping("/refund") + public R> refund(@RequestBody Map requestData) { + try { + String outTradeNo = (String) requestData.get("outTradeNo"); + Integer total = Integer.valueOf(requestData.get("total").toString()); + Integer refund = Integer.valueOf(requestData.get("refund").toString()); + + Map requestMap = new HashMap<>(); + requestMap.put("out_trade_no", outTradeNo); + requestMap.put("out_refund_no", "refund_" + UUID.randomUUID().toString().replace("-", "")); + + // 设置金额信息 + Map amount = new HashMap<>(); + amount.put("refund", refund); + amount.put("total", total); + amount.put("currency", "CNY"); + requestMap.put("amount", amount); + + String path = "/v3/refund/domestic/refunds"; + String result = callWxPayApi(path, requestMap); + Map responseMap = JsonUtils.parseObject(result, Map.class); + + return R.ok(responseMap); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("申请退款失败:" + e.getMessage()); + } + } + + /** + * 查询退款状态 + */ + @SaIgnore + @GetMapping("/queryRefund") + public R> queryRefund(@RequestParam String outRefundNo) { + try { + String path = "/v3/refund/domestic/refunds/" + outRefundNo; + String result = callWxPayApi(path, null); + Map responseMap = JsonUtils.parseObject(result, Map.class); + + return R.ok(responseMap); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("查询退款失败:" + e.getMessage()); + } + } + + /** + * 微信支付回调接口 + */ + @SaIgnore + @PostMapping("/wxPayCallBack") + public String wxPayCallBack(HttpServletRequest request, HttpServletResponse response) { + try { + // 获取请求头和请求体 + Map headers = WxPayUtil.getHeaders(request); + String requestBody = WxPayUtil.getRequestBody(request); + + // 记录回调信息 + System.out.println("接收到微信支付回调: " + requestBody); + + // 获取签名相关信息 + String timestamp = headers.get("wechatpay-timestamp"); + String nonce = headers.get("wechatpay-nonce"); + String signature = headers.get("wechatpay-signature"); + String serialNo = headers.get("wechatpay-serial"); + + // 验证签名 + // 这里需要根据证书序列号获取对应的公钥 + // PublicKey publicKey = ... 获取公钥的逻辑 + + // 解析请求体 + Map bodyMap = JsonUtils.parseObject(requestBody, Map.class); + Map resourceMap = (Map) bodyMap.get("resource"); + + // 获取加密数据 + String ciphertext = (String) resourceMap.get("ciphertext"); + String nonce64 = (String) resourceMap.get("nonce"); + String associatedData = (String) resourceMap.get("associated_data"); + + // 解密数据 + String decryptedData = WxPayUtil.decryptToString( + associatedData != null ? associatedData.getBytes() : new byte[0], + Base64.getDecoder().decode(nonce64), + ciphertext, + WxPayUtil.getApiV3Key().getBytes() + ); + + // 解析解密后的数据 + Map decryptedMap = JsonUtils.parseObject(decryptedData, Map.class); + + // 获取商户订单号和交易状态 + String outTradeNo = (String) decryptedMap.get("out_trade_no"); + String tradeState = (String) decryptedMap.get("trade_state"); + String transactionId = (String) decryptedMap.get("transaction_id"); + String attach = (String) decryptedMap.get("attach"); + + // 处理支付结果 + if ("SUCCESS".equals(tradeState)) { + // 支付成功,更新订单状态 + // 这里可以调用订单服务更新状态 + Long taskId = Long.valueOf(attach); + System.out.println("支付成功,taskId: " + taskId + ", 订单号: " + outTradeNo); + // TODO: 处理业务逻辑,例如更新订单状态 + } + + // 返回成功 + Map result = new HashMap<>(); + result.put("code", "SUCCESS"); + result.put("message", "成功"); + return JsonUtils.toJsonString(result); + } catch (Exception e) { + e.printStackTrace(); + // 返回失败 + Map result = new HashMap<>(); + result.put("code", "FAIL"); + result.put("message", e.getMessage()); + return JsonUtils.toJsonString(result); + } + } + + // 查询用户是否为小程序孔网翻新会员 + @SaIgnore + @GetMapping("/queryUserIsKwfwMember") + public R> queryUserIsKwfwMember(@RequestParam String userId) { + try { + long userIdLong = Long.parseLong(userId); + Map params = new HashMap<>(); + params.put("userId", userIdLong); // 保持小写 u + params.put("type", 3); // 小写 t + params.put("payStatus", 0); // 小写 p + + // 调用外部接口 + String path = "/user/checkPaymentRecord"; + String goUrl = configService.selectConfigByKey("go.url"); +// String goUrl = "http://localhost:9004/api"; + String responseStr = InterfaceUtils.getInterfacePost(goUrl, path, params); + + // 解析响应JSON + Map responseMap = JsonUtils.parseObject(responseStr, Map.class); + if (responseMap == null) { + Map errorResult = new HashMap<>(); + errorResult.put("isMember", false); + return R.fail("响应数据解析失败", errorResult); + } + + // 检查响应状态码 + Integer code = (Integer) responseMap.get("code"); + if (code == null || code != 200) { + String msg = (String) responseMap.get("msg"); + Map errorResult = new HashMap<>(); + errorResult.put("isMember", false); + return R.fail("接口调用失败: " + (msg != null ? msg : "未知错误"), errorResult); + } + + // 提取data字段的值 + Boolean isMember = (Boolean) responseMap.get("data"); + Map result = new HashMap<>(); + result.put("isMember", isMember != null ? isMember : false); + + return R.ok("查询成功", result); + + } catch (Exception e) { + // 异常处理 + Map errorResult = new HashMap<>(); + errorResult.put("isMember", false); + return R.fail("查询失败: " + e.getMessage(), errorResult); + } + } + + /** + * 扫码获取在售/已售商品 + * + * @param keyword 搜索关键词(ISBN) + * @param dataType 数据类型,0表示在售商品,1表示已售商品 + * @param cookie 请求Cookie信息 + * @return 商品信息结果 + */ + @SaIgnore + @GetMapping("/getOnSaleGoods") + public R> getOnSaleGoods(@RequestParam String keyword, + @RequestParam(defaultValue = "0") int dataType, + @RequestParam String cookie) { + try { + // 构建请求URL + String baseUrl = "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list"; + + // 构建请求参数 + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl) + .queryParam("dataType", dataType) + .queryParam("keyword", keyword) +// .queryParam("page", 1) + .queryParam("userArea", "13003000000"); + + // 创建请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Accept", "application/json, text/plain, */*"); + headers.set("Accept-Language", "zh-CN,zh;q=0.9"); + headers.set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"); + headers.set("Referer", "https://search.kongfz.com/product/?dataType=" + dataType + "&keyword=" + keyword + "&page=1"); + headers.set("Cookie", "PHPSESSID="+cookie); + + // 创建RestTemplate实例 + RestTemplate restTemplate = new RestTemplate(); + + // 发送请求并获取响应 + ResponseEntity response = restTemplate.exchange( + builder.toUriString(), + HttpMethod.GET, + new org.springframework.http.HttpEntity<>(headers), + String.class + ); + + // 解析响应数据 + String responseBody = response.getBody(); + Map responseMap = JsonUtils.parseObject(responseBody, Map.class); + + // 构建返回结果 + Map result = new HashMap<>(); + result.put("data", responseMap); + result.put("status", response.getStatusCode().value()); + + return R.ok(result); + } catch (Exception e) { + e.printStackTrace(); + return R.fail("获取商品信息失败:" + e.getMessage()); + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XyBindController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XyBindController.java new file mode 100644 index 0000000..694c5ca --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/XyBindController.java @@ -0,0 +1,179 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.DateUtils; +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.ShopBo; +import org.dromara.zhishu.domain.bo.XyBindBo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.XyBindVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.IXyBindService; +import org.dromara.zhishu.service.impl.XianYvQueryShopImpl; +import org.redisson.api.RList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Map; + +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/xy/api") +public class XyBindController { + + private final IXyBindService xyBindService; + private final IShopService shopService; + private final XianYvQueryShopImpl xianYvQueryShop; + + @GetMapping("/list") + public TableDataInfo listByCreateBy(XyBindBo bo, PageQuery pageQuery) { + return xyBindService.queryPageList(bo, pageQuery); + } + + @SaIgnore + @GetMapping("/insertBlind/{appName}/{mallId}/{token}") + public R insertBlind(@PathVariable("appName") String appName,@PathVariable("mallId") Long mallId,@PathVariable("token") String token) { + Long userId = LoginHelper.getUserId(); + XyBindBo bo = new XyBindBo(); + if(xyBindService.queryById(token) != null){ + return R.fail("您已绑定该店铺"); + } else { + bo.setAppName(appName); + bo.setMallId(mallId); + bo.setToken(token); + bo.setCreateBy(userId); + + xyBindService.insertByBo(bo); + return R.ok("成功绑定店铺"); + } + } + + @SaIgnore + @GetMapping("/updateXyBind/{token}/{appName}") + public R updateXyBind(@PathVariable("token") String token, @PathVariable("appName") String appName) { + Long userId = LoginHelper.getUserId(); + + // 根据token查询绑定信息 + XyBindVo existingBind = xyBindService.queryById(token); + if(existingBind == null){ + return R.fail("未找到对应的绑定信息"); + } + + // 更新appName + XyBindBo bo = new XyBindBo(); + bo.setToken(token); + bo.setAppName(appName); + bo.setUpdateBy(userId); + + // 调用更新服务 + boolean success = xyBindService.updateByBo(bo); + if(success) { + return R.ok("成功更新闲管家名"); + } else { + return R.fail("更新失败"); + } + } + + @SaIgnore + @GetMapping("/deleteXyBind/{token}") + public R deleteXyBind(@PathVariable("token") String token) { + Long userId = LoginHelper.getUserId(); + + // 根据token查询绑定信息 + XyBindVo existingBind = xyBindService.queryById(token); + if(existingBind == null){ + return R.fail("未找到对应的绑定信息"); + } + + // 删除绑定信息 + boolean success = xyBindService.deleteByToken(token); + if(success) { + return R.ok("成功删除绑定信息"); + } else { + return R.fail("删除失败"); + } + } + + // 同步闲鱼店铺 + @SaIgnore + @GetMapping("/syncShop/{appName}/{mallId}/{token}") + public R syncShop(@PathVariable("appName") String appName,@PathVariable("mallId") Long mallId,@PathVariable("token") String token) { + Long userId = LoginHelper.getUserId(); + + R>> shopResult = xianYvQueryShop.XianYvQueryShop(mallId.toString(), token); + + if ((shopResult.getCode() == 200) && shopResult.getData() != null && !shopResult.getData().isEmpty()) { + List> xyUser = shopResult.getData(); + + // 循环创建店铺,每个店铺名称创建一个店铺记录 + for (Map userInfo : xyUser) { + + String userName = userInfo.get("user_name"); + String shopName = userInfo.get("shop_name"); + String expirationTime = userInfo.get("expiration_time"); + + ShopVo shopVo = shopService.selectByGoofishShopKey(userName); + ShopBo shopBo = new ShopBo(); + if (shopVo != null) { + shopBo.setId(shopVo.getId()); + shopBo.setShopName(shopVo.getShopName()); + shopBo.setMallId(Long.parseLong(mallId.toString())); + shopBo.setToken(token); + long timestamp = Long.parseLong(expirationTime) * 1000L; + shopBo.setExpirationTime(new Date(timestamp)); + shopBo.setShopAliasName(shopVo.getShopName()); + shopBo.setShopKey(shopVo.getShopKey()); + shopBo.setShopGroup(appName); + long currentTimestamp = System.currentTimeMillis(); + shopBo.setUpdateTime(new Date(currentTimestamp)); + if (currentTimestamp < timestamp) { + shopBo.setShopAuthorize("1"); + } + + shopService.updateByBo(shopBo); + } else { + // 创建咸鱼店铺 + shopBo.setShopName(shopName); // 使用接口返回的店铺名称 + shopBo.setMallId(Long.parseLong(mallId.toString())); + shopBo.setToken(token); + shopBo.setShopKey(userName); + shopBo.setShopAliasName(shopName); // 使用接口返回的店铺名称 + long timestamp = Long.parseLong(expirationTime) * 1000L; + shopBo.setExpirationTime(new Date(timestamp)); // 使用接口返回的店铺过期时间 + shopBo.setShopAuthorize("1"); + shopBo.setShopGroup(appName); + + shopBo.setShopType("5"); + shopBo.setAddTime(DateUtils.parseDate(DateUtils.getTime())); + shopBo.setCreateBy(userId); + shopBo.setCreateTime(DateUtils.parseDate(DateUtils.getTime())); + shopBo.setTenant_id("000000"); + shopBo.setShopAuthorize("1"); + long currentTimestamp = System.currentTimeMillis(); + shopBo.setUpdateTime(new Date(currentTimestamp)); + + shopService.insertByBo(shopBo); + + // 可以添加日志记录 + System.out.println("成功创建店铺: " + shopName); + } + } + + return R.ok("成功创建 " + xyUser.size() + " 个店铺"); + + } else { + return R.ok("账户店铺为空,无法添加"); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopGoodsController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopGoodsController.java new file mode 100644 index 0000000..cacb31a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopGoodsController.java @@ -0,0 +1,861 @@ +package org.dromara.zhishu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.pdd.pop.sdk.common.util.JsonUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.base.BaseException; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.core.ExcelResult; +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.oss.entity.UploadResult; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.web.core.BaseController; +import org.dromara.system.domain.SysUser; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.StockChangeLog; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.bo.BatchUpdateCargoBo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsDetailBo; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.dto.request.*; +import org.dromara.zhishu.domain.excel.GoodsExcel; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.domain.vo.ProductSubmitResultVo; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.service.factory.ShopGoodsFactory; +import org.dromara.zhishu.service.strategy.ShopGoodsStrategy; +import org.dromara.zhishu.util.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.http.*; + +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +/** + * 商品信息 + * + * @author Lion Li + * @date 2025-03-07 + */ +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +@Lazy +@RequestMapping("/zhishu/shopGoods") +public class ZhishuShopGoodsController extends BaseController { + + private final IZhishuShopGoodsService zhishuShopGoodsService; + private final IShopService shopService; + private final IShopGoodsPublishedService shopGoodsPublishedService; + private final ITaskService taskService; + private final IZhishuShopGoodsDetailService zhishuShopGoodsDetailService; + private final ITFreightService freightService; + private final ITShelvesService shelvesService; + private final ITDepotService depotService;; + + @Autowired + private IRunningTaskByShopService iRunningTaskByShopService; + + @Autowired + private ISysConfigService configService; + + + @Autowired + private RestTemplate restTemplate; + /** + * 查询商品信息列表 + */ + @SaCheckPermission("zhishu:shopGoods:list") + @GetMapping("/list") + @SaIgnore + public TableDataInfo list(ZhishuShopGoodsBo bo, PageQuery pageQuery) { + return zhishuShopGoodsService.queryPageList(bo, pageQuery); + } + + /** + * 导出商品信息列表 + */ + @SaCheckPermission("zhishu:shopGoods:export") + @Log(title = "商品信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ZhishuShopGoodsBo bo, HttpServletResponse response) { + List list = zhishuShopGoodsService.queryList(bo); + ExcelUtil.exportExcel(list, "商品信息", ZhishuShopGoodsVo.class, response); + } + + /** + * 获取商品信息详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shopGoods:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable String id) { + return R.ok(zhishuShopGoodsService.queryById(id)); + } + + /** + * 根据商品条码查询商品信息 + * + * @param barcode 商品条码 + * @return 商品信息 + */ + @GetMapping("/info") + public R> getProductByBarcode(@RequestParam String barcode) { + return R.ok(zhishuShopGoodsService.getProductByBarcode(barcode)); + } + + /** + * 提交商品信息 + * + * @param form 商品信息表单 + * @return 无 + */ + @PostMapping("/submit") + @SaIgnore + @RepeatSubmit + public R submitProduct(@RequestBody ProductForm form) { + ProductSubmitResultVo result = zhishuShopGoodsService.submitProduct(form); + return R.ok(result); + } + + + /** + * 版权页上传 + * + * @param form + * @return + */ + @PostMapping("/submitFromCopyrightPage") + @SaIgnore + @RepeatSubmit + public R submitFromCopyrightPage(@RequestBody ProductForm form) { + return R.ok(zhishuShopGoodsService.submitFromCopyrightPage(form)); + } + + /** + * 重复书籍 + * + * @param form + * @return + */ + @PostMapping("/repeatBook") + @SaIgnore + @RepeatSubmit + public R repeatBook(@RequestBody ProductForm form) { + return R.ok(zhishuShopGoodsService.repeatBook(form)); + } + + /** + * isbn比价 + */ + @GetMapping("/kongfz/search") + @SaIgnore + @RepeatSubmit + public R> searchBooks(@RequestParam("keyword") String keyword, // 同时支持ISBN/书名 + @RequestParam(value = "searchType", defaultValue = "category") String searchType, + @RequestParam("sortType") String sortType, + @RequestParam("conditionValue") String conditionValue, + @RequestParam("cookies") String cookies, + @RequestParam(value = "publisher", required = false) String publisher, // 设置为非必需 + @RequestParam(value = "author", required = false) String author) { // 设置为非必需 + List products = zhishuShopGoodsService.getProductByKongfz(keyword, searchType, sortType, conditionValue, cookies, publisher, author); + return R.ok(products); + } + + /** + * 根据书名获取作者和出版社信息 + */ + @GetMapping("/getAuthorAndPublisher") + @SaIgnore + public R> getAuthorAndPublisher(@RequestParam("keyword") String keyword, @RequestParam("cookies") String cookies) { + List products = zhishuShopGoodsService.getAuthorAndPublisher(keyword, cookies); + return R.ok(products); + } + + /** + * python获取商品信息 + */ + @PostMapping("/python/{isbn}") + @SaIgnore + @RepeatSubmit + public R pythonGetProductByBarcode(@RequestParam String isbn) { + ProductVo productVo = zhishuShopGoodsService.queryBookByPython(isbn); + return R.ok(productVo); + } + + /** + * xcx上书记录 + * + * @param + * @return + */ + @GetMapping("/xcx/{phoneNumber}") + @Log(title = "商品信息", businessType = BusinessType.UPDATE) + @SaIgnore + public R> edit( + @PathVariable String phoneNumber, + @RequestParam(defaultValue = "1") int pageNum, + @RequestParam(defaultValue = "10") int pageSize, + @RequestParam(required = false) String date) { + TableDataInfo page = zhishuShopGoodsService.selectShopGoodsByPhoneNumber(phoneNumber, pageNum, pageSize, date); + return R.ok(page); + } + + /** + * 查询获取对应商品数据 + */ + @GetMapping("/getGoodsData") + @SaIgnore + public R> getGoodsData(@RequestParam String code, + @RequestParam Long userId, + @RequestParam(defaultValue = "1") int pageNum, + @RequestParam(defaultValue = "10") int pageSize, + @RequestParam(required = false) String date) { + TableDataInfo page = zhishuShopGoodsService.queryGoodListByArtNo(code, userId, pageNum, pageSize, date); + return R.ok(page); + } + + /** + * 修改xcx货号 + */ + @PostMapping("/batchMoveItems") + @SaIgnore + public R batchMoveItems(@RequestParam(value = "itemIds") List itemIds, + @RequestParam("warehouse") String warehouse, + @RequestParam("shelf") String shelf, + @RequestParam("freight") String freight, + @RequestParam(value = "userId") Long userId) { + try { + String result = zhishuShopGoodsService.batchMoveItems(itemIds, warehouse,shelf, freight, userId); + return R.ok(result); + } catch (Exception e) { + log.error("批量移动商品位置异常", e); + return R.fail("操作失败:" + e.getMessage()); + } + } + + /** + * 新增商品信息 + */ + @SaCheckPermission("zhishu:shopGoods:add") + @Log(title = "商品信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ZhishuShopGoodsBo bo) { + return toAjax(zhishuShopGoodsService.insertByBo(bo)); + } + + /** + * 修改商品信息 + */ + @SaCheckPermission("zhishu:shopGoods:edit") + @Log(title = "商品信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ZhishuShopGoodsBo bo) { +// 获取当前用户id + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + return toAjax(zhishuShopGoodsService.updateByBo(bo)); + } + + /** + * 删除商品信息 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:shopGoods:remove") + @Log(title = "商品信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable String[] ids, Boolean isProSynch) { + return toAjax(zhishuShopGoodsService.deleteWithValidByIds(List.of(ids), isProSynch)); + } + + /** + * 上传图片 + */ + @PostMapping("/uploadImages") + @SaIgnore + public Map uploadImg(@RequestParam("file") MultipartFile file) { + return zhishuShopGoodsService.uploadImg(file); + // 获取token + } + + /** + * 上传图片 + */ + @GetMapping("/SynShopImg") + @SaIgnore + public R synShopImg(@RequestParam("userId") Long userId) { + zhishuShopGoodsService.synShopImg(userId); + return R.ok(); + } + /** + * 同步pdd图片 + */ + @GetMapping("/synPddShopImg") + @SaIgnore + public R synPddShopImg(@RequestParam("userId") Long userId) { + zhishuShopGoodsService.synPddShopImg(userId); + return R.ok(); + } + + /** + * 导入商品信息 + */ + @PostMapping("/importExcel") + public R importExcel(@RequestParam("file") MultipartFile file, + @RequestParam("depotId") Long depotId, + @RequestParam("firstDepotId") Long firstDepotId, + @RequestParam("secondDepotId") Long secondDepotId, + @RequestParam("code") String code) { + ExcelResult list = null; + try (InputStream inputStream = file.getInputStream()) { + // 商品信息列表 + list = ExcelUtil.importExcel(inputStream, GoodsExcel.class, true); + + } catch (IOException e) { + throw new RuntimeException(e); + } + String Filename = file.getOriginalFilename(); + + TFreightVo tFreightVo = freightService.queryById(depotId); + String allowDistribution = "0"; + if (tFreightVo == null){ + return R.fail("三级货架不存在"); + }else{ + allowDistribution = tFreightVo.getAllowDistribution(); + } + + // 添加到数据库 + List shopGoodsBoList = new ArrayList<>(); + for (GoodsExcel goodsExcel : list.getList()) { + System.out.println(JsonUtil.transferToJson(goodsExcel)); + ZhishuShopGoodsBo zhishuShopGoodsBo = new ZhishuShopGoodsBo(); + // 赋值.. +// zhishuShopGoodsBo.setId(UUID.randomUUID().toString()); +// zhishuShopGoodsBo.setItemNumber(goodsExcel.getGoodsNo()); + zhishuShopGoodsBo.setUserId(LoginHelper.getUserId()); + zhishuShopGoodsBo.setGoodsName(goodsExcel.getGoodsName()); + zhishuShopGoodsBo.setArtNo(goodsExcel.getArtNo()); + zhishuShopGoodsBo.setIsbn(goodsExcel.getIsbn()); + zhishuShopGoodsBo.setConditionCode(String.valueOf(goodsExcel.getConditionCode())); + zhishuShopGoodsBo.setPrice(goodsExcel.getPrice()); + zhishuShopGoodsBo.setInventory(goodsExcel.getInventory()); +// zhishuShopGoodsBo.setFixPrice(goodsExcel.getFixPrice()); +// zhishuShopGoodsBo.setProductId(goodsExcel.getGoodsNo()); +// zhishuShopGoodsBo.setIsArtNoConversion(goodsExcel.getIsArtNoConversion()); + zhishuShopGoodsBo.setDepotId(firstDepotId); + zhishuShopGoodsBo.setIsJoinDistribution(Integer.parseInt(allowDistribution)); + shopGoodsBoList.add(zhishuShopGoodsBo); + } + // 批量导入数据库 + Boolean b = zhishuShopGoodsService.insertListGoodsInfo(shopGoodsBoList, firstDepotId, secondDepotId, depotId, Filename, code,null,"7"); + + return toAjax(b); + } + + @PostMapping("/importApi") + @SaIgnore + public R importApi(Long userId,String goodsName,String artNo,String isbn,String conditionCode,Long price,Long inventory, + Long depotId,String code){ + TFreightVo tFreightVo = freightService.queryById(depotId); + String allowDistribution = "0"; + if (tFreightVo == null){ + return R.fail("三级货架不存在"); + }else{ + allowDistribution = tFreightVo.getAllowDistribution(); + } + + TShelvesVo shelvesVo = shelvesService.queryById(tFreightVo.getShelvesId()); + TDepotVo depotVo = depotService.queryById(Long.parseLong(shelvesVo.getDepotId())); + Long firstDepotId = depotVo.getId(); + Long secondDepotId = shelvesVo.getId(); + + + List shopGoodsBoList = new ArrayList<>(); + ZhishuShopGoodsBo zhishuShopGoodsBo = new ZhishuShopGoodsBo(); + zhishuShopGoodsBo.setUserId(userId); + zhishuShopGoodsBo.setGoodsName(goodsName); + zhishuShopGoodsBo.setArtNo(artNo); + zhishuShopGoodsBo.setIsbn(isbn); + zhishuShopGoodsBo.setConditionCode(conditionCode); + zhishuShopGoodsBo.setPrice(price); + zhishuShopGoodsBo.setInventory(inventory); + zhishuShopGoodsBo.setDepotId(firstDepotId); + zhishuShopGoodsBo.setIsJoinDistribution(Integer.parseInt(allowDistribution)); + shopGoodsBoList.add(zhishuShopGoodsBo); + // 获取当前时间秒级时间戳 + Long timestamp = System.currentTimeMillis() / 1000; + // 批量导入数据库 + Boolean b = zhishuShopGoodsService.insertListGoodsInfo(shopGoodsBoList, firstDepotId, secondDepotId, depotId, "接口调用-"+timestamp, code,userId,"6"); + return toAjax(b); + } + + @SaCheckPermission("zhishu:shopGoods:goodsAdd") + @PostMapping("/goodsAdd") + public R goodsAdd(@RequestBody Map map, HttpServletRequest request) { + Map headers = PddResultUtil.getPddHeaderMap(request); + map.put("userId", LoginHelper.getUserId()); + // 调用本地服务 + map.putAll(headers); + zhishuShopGoodsService.goodsAdd(map); + return toAjax(1); + } + + /** + * 初始化库存 + */ + @GetMapping("/batchInitInventoryToRedis") + @SaIgnore + public Boolean batchInitInventoryToRedis() { + zhishuShopGoodsService.batchInitInventoryToRedis(); + return true; + } + + /** + * 查询库存 + */ + @GetMapping("/queryInventory") + @SaIgnore + public R queryInventory(@NotNull(message = "商品Id不能为空") Long shopGoodsId) { + Integer inventory = zhishuShopGoodsService.queryInventory(shopGoodsId); + return R.ok(inventory); + } + + + /** + * 操作库存 + */ + @PostMapping("/operatingInventory") + @SaIgnore + public Boolean operatingInventory(@RequestBody OperatingInventoryVo operatingInventoryVo) { + System.out.println("接收到操作库存请求:" + JSONObject.toJSONString(operatingInventoryVo)); + // 根据平台类型和平台店铺Id查询出店铺Id + ShopVo shopVo; + if(operatingInventoryVo.getShopType() == 5){ + //如果是闲鱼店铺,则mallId存的是店铺id + shopVo = shopService.queryById(operatingInventoryVo.getMallId()); + }else{ + shopVo = shopService.queryByMailId(operatingInventoryVo.getMallId(), operatingInventoryVo.getShopType()); + } + Assert.isTrue(ObjectUtil.isNotNull(shopVo), "店铺不存在"); + for (OperatingInventoryVo.GoodsItem goodsItem : operatingInventoryVo.getGoodsItems()) { + // 根据店铺Id和商品平台Id查询出商品Id + ShopGoodsPublishedVo shopGoodsPublishedVo = shopGoodsPublishedService.queryByPlatformId(shopVo.getId().toString(), goodsItem.getPlatformId()); + // 根据商品Id进行库存操作 + Assert.isTrue(ObjectUtil.isNotNull(shopGoodsPublishedVo), "商品不存在"); + Boolean result = zhishuShopGoodsService.operatingGoodsInventory(shopVo.getId(), operatingInventoryVo.getShopType(), operatingInventoryVo.getOperationType(), shopGoodsPublishedVo, goodsItem.getCount(), operatingInventoryVo.getOrderSn()); + if (!result) { + log.error("库存操作失败:操作类型-{},商品Id-{},数量-{}", operatingInventoryVo.getOperationType(), shopGoodsPublishedVo.getShopGoodsId(), goodsItem.getCount()); + } + } + return true; + } + + + /** + * 操作库存 + */ + @PostMapping("/goofishoperatingInventory") + @SaIgnore + public Boolean goofishoperatingInventory(@RequestBody OperatingInventoryVo operatingInventoryVo) { + System.out.println("接收到操作库存请求:" + JSONObject.toJSONString(operatingInventoryVo)); + // 根据平台类型和平台店铺Id查询出店铺Id + ShopVo shopVo = shopService.queryByMailId(operatingInventoryVo.getMallId(), operatingInventoryVo.getShopType()); + Assert.isTrue(ObjectUtil.isNotNull(shopVo), "店铺不存在"); + for (OperatingInventoryVo.GoodsItem goodsItem : operatingInventoryVo.getGoodsItems()) { + ZhishuShopGoodsVo zhishuShopGoodsVo = zhishuShopGoodsService.selectShopGoodsByArtNo(goodsItem.getPlatformId()); + // 根据店铺Id和商品平台Id查询出商品Id + + // 根据商品Id进行库存操作 + Assert.isTrue(ObjectUtil.isNotNull(zhishuShopGoodsVo), "商品不存在"); + Boolean result = zhishuShopGoodsService.goofishoperatingGoodsInventory(shopVo.getId(), operatingInventoryVo.getShopType(), operatingInventoryVo.getOperationType(), zhishuShopGoodsVo, goodsItem.getCount(), operatingInventoryVo.getOrderSn()); + if (!result) { + log.error("库存操作失败:操作类型-{},商品Id-{},数量-{}", operatingInventoryVo.getOperationType(), zhishuShopGoodsVo.getId(), goodsItem.getCount()); + } + } + return true; + } + + + + + /** + * 拉取孔夫子/万里牛商品 + * + * @param shopId + * @return + */ + @SaIgnore + @GetMapping("/synchronizationGoods") + public R synchronizationGoods(@NotNull(message = "店铺Id不能为空") @RequestParam("shopId") Long shopId, Integer shopType) { + if (ObjectUtil.isNull(shopType)) { + ShopVo shopVo = shopService.queryById(shopId); + shopType = Integer.valueOf(shopVo.getShopType()); + } + try { + Objects.requireNonNull(ShopGoodsFactory.getStrategy(shopType)).synchronizationGoods(shopId); + return R.ok("拉取成功"); + } catch (Exception e) { + return R.fail(e.getMessage()); + } + } + + /** + * 比对存入表格 + */ + @SaIgnore + @PostMapping("/goodsComparison") + public Boolean goodsComparison(@RequestBody GoodsComparisonRequest request) { + zhishuShopGoodsService.goodsComparison(request); + return true; + } + + /** + * 分批比对商品 + */ + @SaIgnore + @DeleteMapping("/deleteTaskDataByShopId") + public Boolean deleteTaskDataByShopId(@RequestParam("shopId") Long shopId) { + zhishuShopGoodsService.deleteTaskDataByShopId(shopId); + return true; + } + /** + * 拉取孔网数据到erp商品表 + */ + @SaIgnore + @PostMapping("/batchGoodsComparison") + public Boolean batchGoodsComparison(@RequestBody BatchGoodsRequest request) { + System.out.println("接收到批量比对请求:" + JSONObject.toJSONString(request)+"zhuxiaodong"); + zhishuShopGoodsService.createShopGoodsList(request); + // zhishuShopGoodsService.batchGoodsComparison(request); + return true; + } + + /** + * 根据用户选择货号规则将商品存入数据库 + */ + @SaIgnore + @PostMapping("/saveShopGoodsInDb") + public R saveShopGoodsInDb(@Validated @RequestBody SaveGoodsVo saveGoodsVo) { + try { + zhishuShopGoodsService.saveShopGoodsInDb(saveGoodsVo); + return R.ok("保存成功"); + } catch (Exception e) { + return R.fail(e.getMessage()); + } + } + + + /** + * 随机修改孔夫子货号(仅测试使用) + */ + @SaIgnore + @GetMapping("/randomUpdateArtNo") + public R randomUpdateArtNo(Long userId, Long shopId) { + try { + zhishuShopGoodsService.randomUpdateArtNo(userId, shopId); + return R.ok("修改"); + } catch (Exception e) { + return R.fail(e.getMessage()); + } + } + + // /** + // * 导入Excel恢复孔夫子货号(回滚备用) + // */ + // @SaIgnore + // @PostMapping("/rollbackUpdateArtNo") + // public R rollbackUpdateArtNo(Long userId,Long shopId) { + // try { + // zhishuShopGoodsService.randomUpdateArtNo(userId,shopId); + // return R.ok("修改"); + // } catch (Exception e) { + // return R.fail(e.getMessage()); + // } + // } + + /** + * 获取商品变更库存数据 + * + * @param id 主键 + */ + @GetMapping("/stockLog/{id}") + public R> getStockLog(@PathVariable String id) { + List list = zhishuShopGoodsService.selectShopStockLog(id); + return R.ok(list); + } + + // 通过传入的货号,查询出对应的仓库id,返回仓库id和货架id和货位id + @GetMapping("/getDepotIds") + @SaIgnore + public R getDepotIds(String artNo, String userId) { + Map map = zhishuShopGoodsService.selectDepotIds(userId, artNo); + return R.ok(map); + } + + @PostMapping("/editShopGoodsPrice") + @SaIgnore + public void editShopGoodsPrice(@RequestBody Map map) { + String artNo = map.get("artNo").toString(); + String price = map.get("price").toString(); + + ZhishuShopGoodsVo vo = zhishuShopGoodsService.selectShopGoodsByArtNo(artNo); + + ZhishuShopGoodsBo bo = new ZhishuShopGoodsBo(); + bo.setId(vo.getId()); + bo.setPrice(Long.parseLong(price)); + zhishuShopGoodsService.updateByBo(bo); + } + + @GetMapping("/getShopGoodsByArtNo") + @SaIgnore + public Map getShopGoodsByArtNo(String artNo){ + Map map = new HashMap(); + ZhishuShopGoodsVo vo = zhishuShopGoodsService.selectShopGoodsByArtNo(artNo); + if(vo != null){ + map.put("code",200); + map.put("msg","查询成功"); + map.put("data",vo); + }else{ + map.put("code",500); + map.put("msg","未查询到商品数据"); + } + return map; + } + + /** + * 通过平台订单Id查询库存操作日志 + */ + @GetMapping("/queryStockChangeLogByOrderSn") + @SaIgnore + public R queryStockChangeLogByOrderSn(@NotNull(message = "平台订单编码不能为空") String orderSn, @NotNull(message = "库存操作日志类型不能为空") Integer type) { + StockChangeLog stockChangeLogVo = zhishuShopGoodsService.queryStockChangeLogByOrderSn(orderSn, type); + return R.ok(stockChangeLogVo); + } + + /** + * 操作下架商品 + */ + @PostMapping("/operatingSoldOut") + @SaIgnore + public Boolean operatingSoldOut(@RequestBody OperatingSoldOutRequest request) { + System.out.println("接收到操作下架商品请求:" + JSONObject.toJSONString(request)); + // 根据平台类型和平台店铺Id查询出店铺Id + ShopVo shopVo = shopService.queryByMailId(request.getMallId(), request.getPlatformType()); + Assert.isTrue(ObjectUtil.isNotNull(shopVo), "店铺不存在"); + for (OperatingInventoryVo.GoodsItem goodsItem : request.getGoodsItems()) { + // 根据店铺Id和商品平台Id查询出商品Id + ShopGoodsPublishedVo shopGoodsPublishedVo = shopGoodsPublishedService.queryByPlatformId(shopVo.getId().toString(), goodsItem.getPlatformId()); + // 根据商品Id进行下架操作 + Assert.isTrue(ObjectUtil.isNotNull(shopGoodsPublishedVo), "商品不存在"); + Boolean result = zhishuShopGoodsService.operatingGoodsSoldOut(shopVo.getId(), request.getPlatformType(), request.getLogType(), request.getOperationType(), shopGoodsPublishedVo, request.getOrderSn()); + if (!result) { + log.error("下架操作失败:操作类型-{},商品Id-{},数量-{}", request.getOperationType(), shopGoodsPublishedVo.getShopGoodsId(), goodsItem.getCount()); + } + } + return true; + } + + /** + * 通过userId查询对应用户商品表数据条数 + */ + @GetMapping("/queryGoodsCountByUserId") + @SaIgnore + public R queryGoodsCountByUserId(@NotNull(message = "用户ID不能为空") Long userId) { + Long count = zhishuShopGoodsService.queryGoodsCountByUserId(userId); + return R.ok(count); + } + + /** + * 通过userId查询对应用户 + */ + @GetMapping("/queryUserIdByUserId") + @SaIgnore + public R queryUserIdByShopId(@NotNull(message = "店铺ID不能为空") Long userId) { + SysUser user = zhishuShopGoodsService.queryUserByUserId(userId); + return R.ok(user); + } + + /** + * 批量修改货区 + */ + @SaIgnore + @PutMapping("/batchUpdateAre") + public R editBatchAre(@RequestBody BatchUpdateCargoBo bo) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + return toAjax(zhishuShopGoodsService.batchUpdateCargo(bo)); + } + + /** + * 同步至自营书品 + */ + @SaIgnore + @GetMapping("/syncRunningTaskToShopGoods") + public R syncRunningTaskToShopGoods(@NotNull(message = "店铺ID不能为空") String shopId, + @RequestParam("freightId") String freightId, + @RequestParam("id") String id) { + Long userId = LoginHelper.getUserId(); + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 判断是2-孔网店铺还是1-拼多多店铺 + TaskBo taskBo = new TaskBo(); + // 存储任务信息 + taskBo.setTaskType("SYNC_MY_GOODS"); + taskBo.setRelationId(Long.valueOf(id)); + taskBo.setFileName("同步至自营书品"); + taskBo.setShopIds(shopId); + taskBo.setShopNames(shopVo.getShopName()); + taskBo.setDataNum(0L); + taskBo.setTaskStatus("0"); + taskService.insertByBo(taskBo); + // 获取当前用户id + CompletableFuture.runAsync(() -> { + try { + zhishuShopGoodsService.syncRunningTaskToShopGoods(Long.valueOf(shopId), Long.valueOf(freightId),userId,taskBo); + }catch (Exception e) { + log.error("同步至自营书品失败", e); + } + }); + return R.ok("创建同步任务成功,请前往任务列表查看任务进度"); + } + + @PostMapping("/synchronousTask") + @SaIgnore + public R synchronousTask(String shopId){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 拼多多同步任务 + if (shopVo.getShopType().equals("1")){ + TaskBo taskBo = new TaskBo(); + taskBo.setTaskType("SYNC_MY_GOODS"); + taskBo.setFileName("同步任务"); + taskBo.setShopIds(shopId); + taskBo.setShopNames(shopVo.getShopName()); + taskBo.setDataNum(0L); + taskBo.setTaskStatus("0"); + taskBo.setCreateBy(shopVo.getCreateBy()); + taskService.insertByBo(taskBo); + + // 获取当前用户id + CompletableFuture.runAsync(() -> { + try { + zhishuShopGoodsService.synchronousTask(shopVo,taskBo); + }catch (Exception e) { + log.error("同步至自营书品失败", e); + } + }); + } + + return R.ok("创建同步任务成功,请前往任务列表查看任务进度"); + } + + /** + * 批量修改店铺商品下架/改价 + * + * @return + */ + @SaIgnore + @PostMapping("/updateShopGoodsPrice") + public R updateShopGoodsPrice(@Validated @RequestBody UpdateShopGoodsPriceRequest request) { + // 查询店铺类型 + ShopVo shopVo = shopService.queryById(request.getShopId()); + Integer shopType = Integer.valueOf(shopVo.getShopType()); + Long mallId = shopVo.getMallId(); + String token = shopVo.getToken(); + + if (ObjectUtil.isNull(mallId) || ObjectUtil.isEmpty(token)) { + return R.fail("当前店铺未授权或授权过期"); + } + // 根据店铺类型选择不同策略 + ShopGoodsStrategy strategy = Objects.requireNonNull(ShopGoodsFactory.getStrategy(shopType)); + if (ObjectUtil.isNull(strategy)) { + return R.fail("获取策略失败错误", false); + } + Boolean result; + // 根据操作类型:0-下架 1.改价 做不同操作 + switch (request.getType()) { + case 0: + // 0-下架 + result = strategy.setShopGoodsOnSaleStatus(mallId, token, 0, request.getItems()); + break; + case 1: + // 1.改价 + result = strategy.updateShopGoodsPrice(mallId, token, request.getItems()); + break; + default: + return R.fail("操作类型错误", false); + } + return R.ok(result); + } + + @SaIgnore + @PostMapping("/updategoodszxd") + public void updategoodszxd(String shopId, String platformId) { + System.out.println("shopId:"+shopId); + System.out.println("platformId:"+platformId); + ShopVo shop= shopService.queryById(Long.parseLong(shopId)); + // 再去从库查询skuId 根据店铺Id和商品id + List successDataItemDtos = iRunningTaskByShopService.selectByGoodsId("t_running_task_" + shop.getId(), platformId); + Map allData = new HashMap(); + allData.put("shopId", shop.getId()); + allData.put("mallId", successDataItemDtos.get(0).getSkuId()); + allData.put("token", shop.getToken()); + allData.put("goodsId", platformId); + allData.put("quantity", 0); + + String pddIp = configService.selectConfigByKey("fuwubpdd.ip"); + InterfaceUtils.getInterfacePost(pddIp, "/api/pdd/inventory/inventorySync", allData); + } + + @SaIgnore + @PostMapping("/insertGoodsDetails") + public void insertGoodsDetails(@Validated @RequestBody ZhishuShopGoodsDetailBo bo) { + zhishuShopGoodsDetailService.insertByBo(bo); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopGoodsDetailController.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopGoodsDetailController.java new file mode 100644 index 0000000..7dfe02d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/controller/ZhishuShopGoodsDetailController.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.ZhishuShopGoodsDetailVo; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsDetailBo; +import org.dromara.zhishu.service.IZhishuShopGoodsDetailService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 商品信息补全表 + * + * @author yxy + * @date 2025-06-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/zhishu/shopGoodsDetail") +public class ZhishuShopGoodsDetailController extends BaseController { + + private final IZhishuShopGoodsDetailService zhishuShopGoodsDetailService; + + /** + * 查询商品信息补全表列表 + */ + @SaCheckPermission("zhishu:shopGoodsDetail:list") + @GetMapping("/list") + public TableDataInfo list(ZhishuShopGoodsDetailBo bo, PageQuery pageQuery) { + return zhishuShopGoodsDetailService.queryPageList(bo, pageQuery); + } + + /** + * 导出商品信息补全表列表 + */ + @SaCheckPermission("zhishu:shopGoodsDetail:export") + @Log(title = "商品信息补全表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(ZhishuShopGoodsDetailBo bo, HttpServletResponse response) { + List list = zhishuShopGoodsDetailService.queryList(bo); + ExcelUtil.exportExcel(list, "商品信息补全表", ZhishuShopGoodsDetailVo.class, response); + } + + /** + * 获取商品信息补全表详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("zhishu:shopGoodsDetail:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(zhishuShopGoodsDetailService.queryById(id)); + } + + /** + * 新增商品信息补全表 + */ + @SaCheckPermission("zhishu:shopGoodsDetail:add") + @Log(title = "商品信息补全表", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody ZhishuShopGoodsDetailBo bo) { + return toAjax(zhishuShopGoodsDetailService.insertByBo(bo)); + } + + /** + * 修改商品信息补全表 + */ + @SaCheckPermission("zhishu:shopGoodsDetail:edit") + @Log(title = "商品信息补全表", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody ZhishuShopGoodsDetailBo bo) { + return toAjax(zhishuShopGoodsDetailService.updateByBo(bo)); + } + + /** + * 删除商品信息补全表 + * + * @param ids 主键串 + */ + @SaCheckPermission("zhishu:shopGoodsDetail:remove") + @Log(title = "商品信息补全表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(zhishuShopGoodsDetailService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/converter/PriceDivideBy100Converter.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/converter/PriceDivideBy100Converter.java new file mode 100644 index 0000000..0906d0c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/converter/PriceDivideBy100Converter.java @@ -0,0 +1,96 @@ +package org.dromara.zhishu.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.converters.ReadConverterContext; +import com.alibaba.excel.converters.WriteConverterContext; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class PriceDivideBy100Converter implements Converter { + + @Override + public Class supportJavaTypeKey() { + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + // 价格在Excel中是数字类型 + return CellDataTypeEnum.NUMBER; + } + + /** + * 读取Excel时:将Excel中的数字(元)转换为String(分) + * 兼容数值和字符串类型 + */ + @Override + public String convertToJavaData(ReadConverterContext context) { + if (context == null || context.getReadCellData() == null) { + return "0"; + } + try { + ReadCellData cellData = context.getReadCellData(); + BigDecimal priceInYuan = null; + + // 根据单元格类型获取数值 + switch (cellData.getType()) { + case NUMBER: + // 数值类型:直接获取 + priceInYuan = cellData.getNumberValue(); + break; + + case STRING: + // 字符串类型:转换为BigDecimal + String stringValue = cellData.getStringValue(); + if (stringValue == null || stringValue.trim().isEmpty()) { + return "0"; + } + try { + // 去除千分位逗号和空格 + stringValue = stringValue.trim().replaceAll(",", "").replaceAll(" ", ""); + priceInYuan = new BigDecimal(stringValue); + } catch (NumberFormatException e) { + return "0"; + } + break; + + default: + // 其他类型返回0 + return "0"; + } + + // 数值转换:元转分 + if (priceInYuan == null) { + return "0"; + } + + BigDecimal priceInCent = priceInYuan.multiply(BigDecimal.valueOf(100)); + return priceInCent.setScale(0, RoundingMode.HALF_UP).toString(); + + } catch (Exception e) { + return "0"; + } + } + + /** + * 写入Excel时:将String(分)转换为Excel中的数字(元) + */ + @Override + public WriteCellData convertToExcelData(WriteConverterContext context) { + String value = context.getValue(); + if (value == null || value.isEmpty()) { + return new WriteCellData<>(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)); + } + try { + BigDecimal priceInCent = new BigDecimal(value); + // 分转元:除以100,保留2位小数 + BigDecimal priceInYuan = priceInCent.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); + return new WriteCellData<>(priceInYuan); + } catch (NumberFormatException e) { + return new WriteCellData<>(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/converter/QualityConverter.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/converter/QualityConverter.java new file mode 100644 index 0000000..d008532 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/converter/QualityConverter.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.converter; + +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; + +public class QualityConverter implements Converter { // 改为 String + + @Override + public Class supportJavaTypeKey() { // 改为 String.class + return String.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public WriteCellData convertToExcelData(String codeStr, ExcelContentProperty contentProperty, + GlobalConfiguration globalConfiguration) throws Exception { + if (codeStr == null || codeStr.trim().isEmpty()) { + return new WriteCellData<>(""); + } + + try { + // 将字符串转为整数进行判断 + int code = Integer.parseInt(codeStr); + String qualityDesc; + switch (code) { + case 100: + qualityDesc = "全新"; + break; + case 95: + qualityDesc = "九五品"; + break; + case 90: + qualityDesc = "九品"; + break; + case 85: + qualityDesc = "八五品"; + break; + case 80: + qualityDesc = "八品"; + break; + case 75: + qualityDesc = "七五品"; + break; + case 70: + qualityDesc = "七品"; + break; + case 65: + qualityDesc = "六五品"; + break; + case 60: + qualityDesc = "六品"; + break; + default: + qualityDesc = codeStr; + break; + } + return new WriteCellData<>(qualityDesc); + } catch (NumberFormatException e) { + // 如果不是数字,直接返回原值 + return new WriteCellData<>(codeStr); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Account.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Account.java new file mode 100644 index 0000000..5079a90 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Account.java @@ -0,0 +1,116 @@ +package org.dromara.zhishu.domain; + +import lombok.*; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.IdType; +import org.dromara.common.mybatis.core.domain.BaseEntity; + + +/** + * 账务记录实体类 + * 对应表名:account + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("account") +public class Account extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 业务号(唯一) + */ + private String accountNo; + + /** + * 相关id + */ + private Long aboutId; + + /** + * 业务类型 0-预留 1225 闲鱼 1221 pdd 1222 孔夫子 + */ + private Integer type; + + /** + * 交易类型 1-收入 2-支出 + */ + private Integer tradeType; + + /** + * 支付渠道 wechat/alipay/... + */ + private String payType; + + /** + * 订单总金额(分) + */ + private Long totalAmount; + + /** + * 入账相关ID + */ + private Long getById; + + /** + * 出账相关ID + */ + private Long setById; + + /** + * 交易状态 0-预留 1-待处理 2-成功 3-失败 4-回滚 + */ + private Integer tradeStatus; + + /** + * 重试次数 + */ + private Integer retryCount; + + /** + * 备注 + */ + private String note; + + /** + * 扩展字段(JSON) + */ + private String extendJson; + + /** + * 创建人 + */ + private Long createdBy; + + /** + * 创建时间戳(毫秒) + */ + private Long createdTime; + + /** + * 更新人 + */ + private Long updatedBy; + + /** + * 更新时间戳(毫秒) + */ + private Long updatedTime; + + /** + * 删除标识 0-正常 1-删除 + */ + private Integer isDel; + + /** + * 当时余额 + */ + private Long balance; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ArtNoMove.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ArtNoMove.java new file mode 100644 index 0000000..8034069 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ArtNoMove.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +@TableName("t_art_no_move") +public class ArtNoMove { + 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/BookBaseInfoPhp.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/BookBaseInfoPhp.java new file mode 100644 index 0000000..0b1ba6b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/BookBaseInfoPhp.java @@ -0,0 +1,32 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; +import org.dromara.common.tenant.core.TenantEntity; +import org.dromara.zhishu.domain.vo.BookBaseInfoVo; + +import java.util.List; + +@Data +public class BookBaseInfoPhp extends TenantEntity { + + /** + * 页数 + */ + private String currentPage; + /** + * 最后一页 + */ + private String lastPage; + /** + * 条数 + */ + private String perPage; + /** + * 查询数据 + */ + private List data; + /** + * 总条数 + */ + private String total; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/CourierLog.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/CourierLog.java new file mode 100644 index 0000000..9c2dc00 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/CourierLog.java @@ -0,0 +1,95 @@ +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-03-18 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("courier_log") +public class CourierLog extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "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/DepotOrder.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/DepotOrder.java new file mode 100644 index 0000000..afe3219 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/DepotOrder.java @@ -0,0 +1,57 @@ +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_depot_order + * + * @author yxy + * @date 2025-06-03 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_depot_order") +public class DepotOrder extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 店铺订单id + */ + private String shopOrderId; + + /** + * 处理人 + */ + private Long userId; + + /** + * 商品信息 + */ + private String itemList; + + /** + * 仓库订单状态 0 待发货 1 已发货 2 无库存 3 转发任务 + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Employee.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Employee.java new file mode 100644 index 0000000..cb05952 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Employee.java @@ -0,0 +1,47 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serial; + +@Data +@TableName("wave_employee") +public class Employee { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 表主键(员工ID) + */ + private String id; + + /** + * 员工姓名 + */ + private String name; + + /** + * 所属用户id + */ + private Long userId; + + /** + * 创建时间 + */ + @TableField("creat_time") + private Long creatTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Long updateTime; + + /** + * 删除标志 + */ + private Integer delFlag; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ErpGoodsOrder.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ErpGoodsOrder.java new file mode 100644 index 0000000..c50f7cc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ErpGoodsOrder.java @@ -0,0 +1,286 @@ +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 org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; + +import java.io.Serial; +import java.util.List; + +/** + * 平台订单对象 erp_goods_order + * + * @author yxy + * @date 2025-12-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("erp_goods_order") +public class ErpGoodsOrder extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + 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 createdBy; + + + /** + * 创建时间 时间戳 + */ + 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首字母(大写)用于分区 + */ + @TableId(value = "shop_md5_prefix") + 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 erpAssReasonOther; + + /** + * 拒绝原因 + */ + private String erpAssRemark; + + + /** + * 商品列表对象 + */ + private List zhishuShopGoodsList; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ExcelTask.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ExcelTask.java new file mode 100644 index 0000000..b94140f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ExcelTask.java @@ -0,0 +1,77 @@ +package org.dromara.zhishu.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; + +/** + * 任务列表对象 t_task_list + * + * @author yxy + * @date 2025-03-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_task_list") +public class ExcelTask extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + 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; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 线程id + */ + private Long threadId; + /** + * 用户id + */ + private Long userId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/FastMail.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/FastMail.java new file mode 100644 index 0000000..5b9caba --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/FastMail.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_fast_mail + * + * @author yxy + * @date 2025-06-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_fast_mail") +public class FastMail extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 类型 1 韵达 + */ + private String type; + + /** + * 账号 + */ + private String partnerId; + + /** + * 联调密码 + */ + private String secret; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 面单类型 1 网点面单 2 拼多多面单 + */ + private String fastMailType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/GoodsAutoFail.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/GoodsAutoFail.java new file mode 100644 index 0000000..1f04c76 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/GoodsAutoFail.java @@ -0,0 +1,59 @@ +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_goods_auto_fail + * + * @author yxy + * @date 2025-09-29 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_goods_auto_fail") +public class GoodsAutoFail extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + private String shopName; + + /** + * 商品id + */ + private Long goodsId; + + private String goodsName; + + /** + * 商品isbn + */ + private String isbn; + + /** + * 货号 + */ + private String artNo; + + /** + * 日志 + */ + private String callBackData; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/GoodsDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/GoodsDto.java new file mode 100644 index 0000000..0f96f66 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/GoodsDto.java @@ -0,0 +1,36 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; + +import java.util.List; + +@Data +public class GoodsDto { + + //商品编号 + private String goodsId; + + //商品数量 + private String goodsCount; + + //商品名称 + private String goodsName; + + //商品销售价格 + private String goodsPrice; + + //商品规格 + private String goodsSpec; + + //商品图片 + private List goodsImgs; + + //商家外部编码(商品) + private String outerGoodsId; + + //商家外部编码(SKU) /商品id + private String outerId; + + //商品规格编码 + private String skuId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/LicenseResult.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/LicenseResult.java new file mode 100644 index 0000000..9c3d4cf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/LicenseResult.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; + +/** + * 营业执照信息 + */ +@Data +public class LicenseResult { +// 图片路径 + private String url; + // 提示信息 + private String message; +// 地址 + private String address; + private String angle; +// 经营类型 + private String business; +// 时间 + private String period; +// 法人 + private String person; +// 注册金额 + private String capital; +// 注册名称 + private String name; +// 注册号 + private String regNum; +// 注册权机关 + private String RegistrationAuthority; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/LocalMultipartFile.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/LocalMultipartFile.java new file mode 100644 index 0000000..6fbd853 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/LocalMultipartFile.java @@ -0,0 +1,56 @@ +package org.dromara.zhishu.domain; + +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class LocalMultipartFile implements MultipartFile { + + private final File file; + + public LocalMultipartFile(File file) { + this.file = file; + } + + @Override + public String getName() { + return file.getName(); + } + + @Override + public String getOriginalFilename() { + return file.getName(); + } + + @Override + public String getContentType() { + return "application/octet-stream"; // 可根据实际文件类型修改 + } + + @Override + public boolean isEmpty() { + return file.length() == 0; + } + + @Override + public long getSize() { + return file.length(); + } + + @Override + public byte[] getBytes() throws IOException { + return java.nio.file.Files.readAllBytes(file.toPath()); + } + + @Override + public InputStream getInputStream() throws IOException { + return new FileInputStream(file); + } + + @Override + public void transferTo(File dest) throws IOException, IllegalStateException { + java.nio.file.Files.copy(file.toPath(), dest.toPath()); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Logistics.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Logistics.java new file mode 100644 index 0000000..32c8100 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Logistics.java @@ -0,0 +1,127 @@ +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; +import java.math.BigDecimal; + +/** + * 物流模板对象 t_logistics + * + * @author ruoyi + * @date 2023-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_logistics") +public class Logistics extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @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 Double firWbv; + + /** + * 首费 单位:元 + */ + private BigDecimal firPrice; + + /** + * 续重 续本 续件 + */ + private Double continueWbv; + + /** + * 续费 单位:元 + */ + private BigDecimal continuePrice; + + /** + * 模板状态(0正常 1停用) + */ + private String status; + + /** + * 租户编码 + */ + private String tenantId; + + /** + * 运送范围 + */ + private String shippingRange; + + /** + * 仓库ID + */ + private Long warehouseId; + + /** + * 配送说明 + */ + 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/NewUserInfo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/NewUserInfo.java new file mode 100644 index 0000000..5388986 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/NewUserInfo.java @@ -0,0 +1,102 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +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; + +/** + * @author chen + * @date 2023/1/10 16:08 + * @description 新用户信息 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("t_audit_info") +public class NewUserInfo{ + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 审核id + */ + + private Long auditId; + /** + * 企业名称 + */ + private String companyName; + + /** + * 企业类型 + */ + private String companyType ; + + /** + * 联系人名 + */ + private String contactPerson; + + /** + * 联系方式 + */ + private String contactPhone;; + + /** + * 邮箱 + */ + private String email; + + /** + * 身份证图片 + */ + private String cardIdentity; + + + /** + * 营业执照名称 + */ + private String licenseName; + + /** + * 营业执照编号 + */ + private String licenseNumber; + + /** + * 营业执照 + */ + private String license; + + /** + * 备注 + */ + 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/Notice.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Notice.java new file mode 100644 index 0000000..2040621 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Notice.java @@ -0,0 +1,56 @@ +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_notice + * + * @author yxy + * @date 2025-05-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_notice") +public class Notice extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 发件人 + */ + private String sender; + + /** + * 收件人 + */ + private String recipient; + + /** + * 消息 + */ + private String content; + + /** + * 状态 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/PddLoginVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PddLoginVo.java new file mode 100644 index 0000000..debe6bd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PddLoginVo.java @@ -0,0 +1,58 @@ +package org.dromara.zhishu.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 登录验证信息 + * + * @author Michelle.Chung + */ +@Data +public class PddLoginVo { + + /** + * 授权令牌 + */ + @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-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PriceTemplate.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PriceTemplate.java new file mode 100644 index 0000000..ac77ffd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PriceTemplate.java @@ -0,0 +1,76 @@ +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.math.BigDecimal; + +import java.io.Serial; + +/** + * 价格模板对象 t_price_template + * + * @author yxy + * @date 2025-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_price_template") +public class PriceTemplate extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 价格模板名称 + */ + private String templateName; + + /** + * 价格类型 0 书价 1 总价(书价+运费) + */ + private String priceType; + + /** + * 增加比例 + */ + private BigDecimal proportion; + + /** + * 增加金额 + */ + private BigDecimal addAmount; + + /** + * 价格模板状态(0正常 1停用) + */ + private String status; + + /** + * 价格区间最大值 + */ + private Integer highPrice; + /** + * 价格区间最小值 + */ + private Integer lowPrice; + /** + * 价格参数 + */ + private String rangePrice; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PrintTemplate.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PrintTemplate.java new file mode 100644 index 0000000..e89de1a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/PrintTemplate.java @@ -0,0 +1,55 @@ +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_print_template + * + * @author yxy + * @date 2026-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_print_template") +public class PrintTemplate extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 快递类型 + */ + private String expressType; + + /** + * 模板名称 + */ + private String printTemplateName; + + /** + * 0正常 1停用 + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 包裹信息json字符串 + */ + private String parcelInformation; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Printer.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Printer.java new file mode 100644 index 0000000..6151cfa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Printer.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_printer + * + * @author yxy + * @date 2026-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_printer") +public class Printer extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 打印机类型 1 本地打印机 2 拼多多云打印机 + */ + private String printType; + + /** + * 拼多多云打印机共享码 + */ + private String shareCode; + + /** + * 打印机/云打印机编号 + */ + private String printer; + + /** + * 打印机名称 + */ + private String printerName; + + /** + * 是否启用全程打印 + */ + private String isRemotePrinting; + + /** + * 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/ProfitSharingLog.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ProfitSharingLog.java new file mode 100644 index 0000000..9b10c39 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ProfitSharingLog.java @@ -0,0 +1,111 @@ +package org.dromara.zhishu.domain; + +import lombok.*; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.IdType; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serializable; + +/** + * 分润记录实体类 + * 对应表名:profit_sharing_log + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("profit_sharing_log") +public class ProfitSharingLog extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 订单ID + */ + private Long orderId; + + /** + * 订单编号 + */ + private String orderSn; + + /** + * 分润规则ID + */ + private Long cfgId; + + /** + * 状态 0-待出款 1-已出款 + */ + private Integer status; + + /** + * 分润受益方ID(平台 商家 上级) + */ + private Long beneficiaryId; + + /** + * 分润受益方名字 + */ + private String beneficiaryName; + + /** + * 计算基准金额(单位:分) + */ + private Long calcBaseAmount; + + /** + * 分润比例 + */ + private Integer shareRate; + + /** + * 分润金额(单位:分) + */ + private Long shareAmount; + + /** + * 结算时间戳(毫秒) + */ + private Long settlementTime; + + /** + * 账期(例如202509,用于按月度对账) + */ + private Long accountingPeriod; + + /** + * 创建时间戳(毫秒) + */ + private Long createdTime; + + /** + * 创建人ID + */ + private Long createdBy; + + /** + * 更新时间戳(毫秒) + */ + private Long updatedTime; + + /** + * 更新人ID + */ + private Long updatedBy; + + /** + * 是否启用 0-启用 1-禁用 + */ + private Integer isDel; + + private Long startTime; + + private Long endTime; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/RunningTask.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/RunningTask.java new file mode 100644 index 0000000..59c65df --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/RunningTask.java @@ -0,0 +1,91 @@ +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_running_task + * + * @author yxy + * @date 2025-07-23 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_running_task") +public class RunningTask extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 任务id + */ + private Long taskId; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 优先级 + */ + private Long priority; + + /** + * 内容json字符串 + */ + private String data; + + /** + * 状态 0 未执行 1 执行中 2 执行完成 + */ + private String status; + + /** + * 需要被修改的状态 + */ + private String editStatus; + + /** + * 任务执行完返回的数据 + */ + private String callBackData; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 商品id + */ + private Long goodsId; + + /** + * 随机数 + */ + private Long randomNum; + + + /** + * 任务类型 + */ + private String taskType; + + /** + * 完成数据 + */ + private String successData; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopContext.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopContext.java new file mode 100644 index 0000000..4ae951c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopContext.java @@ -0,0 +1,52 @@ +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_context + * + * @author yxy + * @date 2025-09-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_context") +public class ShopContext extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 商品描述 + */ + private String context; + + /** + * 状态(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/ShopDepot.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopDepot.java new file mode 100644 index 0000000..57856b3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopDepot.java @@ -0,0 +1,33 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + + +// ShopDepot.java 实体类 +@Data +@TableName("t_shop_depot_aotu") +public class ShopDepot { + @TableId(type = IdType.AUTO) + private Long id; + + private Long shopId; + + private Long depotId; + + private Long createBy; + + private Date createTime; + + private Long updateBy; + + private Date updateTime; + + @TableField(exist = false) + private String depotName; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopDetail.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopDetail.java new file mode 100644 index 0000000..0bf5060 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopDetail.java @@ -0,0 +1,291 @@ +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; +import java.math.BigDecimal; + +/** + * 商品详情对象 t_shop_detail + * + * @author yxy + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shop_detail") +public class ShopDetail extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + 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; + + /** + * 擦亮方式 0擦亮原商品 1发布新商品 + */ + private String polishType; + + /** + * 闲鱼店铺发布品类 0 图书 1 其他 + */ + private String publishType; + + /** + * 闲鱼类目ID + */ + private String categoryId; + + /** + * 频率 + */ + private int frequency; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodIsbn.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodIsbn.java new file mode 100644 index 0000000..21f0dc9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ShopGoodIsbn.java @@ -0,0 +1,28 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 商品统一书号 + */ +@Data +@TableName("t_shop_good_isbn") +public class ShopGoodIsbn { + @TableId(value = "id") + private Long id; + /** + * 商品id + */ + private String shopGoodsId; + /** + * 商品isbn + */ + private String goodIsbn; + /** + * 商品统一书号 + */ + private String goodUnifyIsbn; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SinglePrint.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SinglePrint.java new file mode 100644 index 0000000..904972b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SinglePrint.java @@ -0,0 +1,98 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; + +/** + * 单票打印对象 t_single_print + * + * @author yxy + * @date 2026-03-27 + */ +@Data +public class SinglePrint { + + /** + * 主键ID + */ + private Long id; + + /** + * 快递单号 + */ + private String mailNo; + + /** + * 发件人名称 + */ + private String senderName; + + /** + * 发件人联系方式 + */ + private String senderPhone; + + /** + * 发货地详细地址 + */ + private String senderAddress; + + /** + * 收件人名称 + */ + private String receiverName; + + /** + * 收件人联系方式 + */ + private String receiverPhone; + + /** + * 收件人详细地址 + */ + private String receiverAddress; + + /** + * 物品名称 + */ + private String itemName; + + /** + * 物品数量 + */ + private Integer itemNum; + + /** + * 物品备注 + */ + private String itemRemark; + + /** + * 打单账号id + */ + private Long fastMailId; + + /** + * 打单账号信息 + */ + private String fastMailText; + + /** + * 创建人id + */ + private Long createBy; + + /** + * 创建时间时间戳 + */ + private Long createAt; + + /** + * 备注 + */ + private String remark; + + /** + * 状态 1正常 2回收 + */ + private String status; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Spec.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Spec.java new file mode 100644 index 0000000..b2221d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Spec.java @@ -0,0 +1,97 @@ +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_spec + * + * @author yxy + * @date 2025-03-27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_spec") +public class Spec extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + 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; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Statistic.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Statistic.java new file mode 100644 index 0000000..0ae58eb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Statistic.java @@ -0,0 +1,44 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; + +/** + * 统计类 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class Statistic extends TenantEntity { + + /** + * 库房数量 + */ + private Long warehousesNum; + + /** + * 货架数量 + */ + private Long shelvesNum; + + /** + * 仓库名称 + */ + private String warehousesName; + + /** + * 入库量 + */ + private Long inQuantity; + + /** + * 出库量 + */ + private Long outQuantity; + + /** + * 书籍种类 + */ + private String bookCategory; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SyncLog.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SyncLog.java new file mode 100644 index 0000000..c89aba4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SyncLog.java @@ -0,0 +1,49 @@ +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; + +/** + * 迁移日志对象 sync_log + * + * @author yxy + * @date 2026-06-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sync_log") +public class SyncLog extends BaseEntity { + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键id + */ + @TableId(value = "id") + private Long id; + + /** + * 用户id + */ + private Long userId; + + /** + * 迁移类型 1 货区 2 商品 + */ + private String type; + + /** + * 创建人(迁移时间) + */ + private Long createBy; + + /** + * 迁移结果 + */ + private String msg; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SynchronizationShopLog.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SynchronizationShopLog.java new file mode 100644 index 0000000..f209f56 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/SynchronizationShopLog.java @@ -0,0 +1,110 @@ +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-04-14 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("synchronization_shop_log") +public class SynchronizationShopLog extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + 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 createAt; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + 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/TAudit.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TAudit.java new file mode 100644 index 0000000..5fdf12a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TAudit.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-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_audit") +public class TAudit 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/TDistrict.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TDistrict.java new file mode 100644 index 0000000..afcabe0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TDistrict.java @@ -0,0 +1,71 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +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; +import java.io.Serializable; +import java.util.Date; + +@Data +@TableName("t_district") +public class TDistrict implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 区划信息id + */ + @TableId(value = "id") + 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; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TFreight.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TFreight.java new file mode 100644 index 0000000..53ab765 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TFreight.java @@ -0,0 +1,72 @@ +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_freight + * + * @author Lion Li + * @date 2025-04-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_freight") +public class TFreight extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 货位id + */ + @TableId(value = "id") + private Long id; + + /** + * 货架id + */ + private Long shelvesId; + + /** + * 货位编码 + */ + private String code; + + /** + * 货位名称 + */ + private String name; + + /** + * 货位单位 + */ + private String unit; + + /** + * 货位容量 + */ + private Long capMax; + + /** + * 货号 + */ + private String artNo; + + /** + * 仓库状态(0正常 1停用) + */ + private String status; + + private String tenantId; + + /** + * 是否开启分销 0否 1是 + */ + private String allowDistribution; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShelves.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShelves.java new file mode 100644 index 0000000..ecffbbb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TShelves.java @@ -0,0 +1,64 @@ +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.tenant.core.TenantEntity; + +import java.io.Serial; + +/** + * 货架信息对象 t_shelves + * + * @author Lion Li + * @date 2025-03-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_shelves") +public class TShelves extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 货架id + */ + @TableId(value = "id") + private Long id; + + /** + * 货架名称 + */ + private String name; + + + /** + * 货架容量 + */ + private Long sheCapMax; + + /** + * 货架单位 + */ + private String unit; + + /** + * 仓库id + */ + private Long depotId; + + /** + * 货架状态(0正常 1停用) + */ + private String status; + + /** + * 货架编码 + */ + private String code; + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TUserPlatform.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TUserPlatform.java new file mode 100644 index 0000000..9d1a2c1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TUserPlatform.java @@ -0,0 +1,86 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import com.baomidou.mybatisplus.annotation.IdType; +import java.util.Date; + +/** + * 用户平台关联对象 t_user_platform + * + * @author yxy + */ +@Data +@TableName("t_user_platform") +public class TUserPlatform extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(type = IdType.AUTO) + private String id; + + /** + * 类型 1 拼多多 2 孔夫子 3 淘宝.... + */ + private String type; + + /** + * erp用户id + */ + private Long userId; + + /** + * 三方平台id + */ + private String platformId; + + /** + * 三方平台名称 + */ + private String platformName; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + private String delFlag; + + /** + * 租户编码 + */ + private String tenantId; + + /** + * 创建部门 + */ + private Long createDept; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新人 + */ + private Long updateBy; + + /** + * 更新时间 + */ + private Date updateTime; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Task.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Task.java new file mode 100644 index 0000000..4644774 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Task.java @@ -0,0 +1,78 @@ +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_task + * + * @author yxy + * @date 2025-03-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_task") +public class Task extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + 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; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 线程id + */ + private String threadId; + + /** + * 关系id + */ + private Long relationId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TaskPause.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TaskPause.java new file mode 100644 index 0000000..4c56543 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/TaskPause.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; + +import java.util.Date; + +/** + * 暂停任务 + */ +@Data +public class TaskPause { + + private Long id; + + private Long taskId; + + private Long shopId; + + private Long createBy; + + private Date createTime; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserAccount.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserAccount.java new file mode 100644 index 0000000..e33eebc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserAccount.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_user_account + * + * @author yxy + * @date 2026-02-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_user_account") +public class UserAccount extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 出入帐账户类型 0 出账 1 入账 + */ + private String type; + + /** + * 账号类型 + */ + private String accountType; + + /** + * 账号名称 + */ + private String accountName; + + /** + * 账号 + */ + private String account; + + /** + * 是否默认账号 0 否 1 是 + */ + private String isDefault; + + /** + * 店铺状态(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/UserRecharge.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserRecharge.java new file mode 100644 index 0000000..6f1cb48 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/UserRecharge.java @@ -0,0 +1,95 @@ +package org.dromara.zhishu.domain; + +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.common.tenant.core.TenantEntity; +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; + +/** + * 用户充值对象 t_user_recharge + * + * @author yxy + * @date 2025-04-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_user_recharge") +public class UserRecharge extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + 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; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 手续费 + */ + private BigDecimal commission; + + /** + * 是否充值到余额中 + */ + private String isBalance; + + /** + * 日志备注 + */ + private String logTxt; + + /** + * 原始金额 + */ + private BigDecimal originalPrice; + + /** + * 更新金额 + */ + private BigDecimal updatePrice; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Violation.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Violation.java new file mode 100644 index 0000000..9fd0aa8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Violation.java @@ -0,0 +1,75 @@ +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_violation + * + * @author yxy + * @date 2025-06-23 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_violation") +public class Violation extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 类型 0 isbn 1 书名 2 作者 3 出版社 + */ + private String type; + + /** + * 审核原因 + */ + private String content; + + /** + * 发起人 + */ + private Long userid; + + /** + * 是否审核 0 未审核 1 已审核 + */ + private String review; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 审核意见 + */ + private String remark; + + /** + * 审核内容 + */ + private String name; + + /** + * 分类 + */ + private String sort; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WarehouseSettings.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WarehouseSettings.java new file mode 100644 index 0000000..32cace7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WarehouseSettings.java @@ -0,0 +1,87 @@ +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; +import java.math.BigDecimal; + +/** + * 设置对象 warehouse_settings + * + * @author yxy + * @date 2025-12-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("warehouse_settings") +public class WarehouseSettings extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @TableId(value = "id") + private Long id; + + /** + * 设置模板名称 + */ + private String settingName; + + /** + * 库存同步形式 0 下单减库存 1 支付减库存 + */ + private Long stockSynchronizeType; + + /** + * 是否自动下发 0 否 1 是 + */ + private Long autoIssue; + + /** + * 是否开启亏损保护 0 否 1 是 + */ + private Long lossProtection; + + /** + * 利润下限 + */ + private BigDecimal profitFloor; + + /** + * 是否启用 0 否 1 是 + */ + private Long status; + + /** + * 是否删除 0 否 1 是 + */ + @TableLogic + private Long delFlag; + + /** + * 退款后是否自动回退库存 0否 1是 + */ + private Long stockRollback; + + /** + * 创建时间时间戳 + */ + private Long createAt; + + /** + * 修改时间时间戳 + */ + private Long updateAt; + + /** + * 店铺id + */ + private String shopIds; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WarehouseSettingsAttribute.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WarehouseSettingsAttribute.java new file mode 100644 index 0000000..04824a4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WarehouseSettingsAttribute.java @@ -0,0 +1,25 @@ +package org.dromara.zhishu.domain; + +import lombok.Data; + +/** + * 匹配规则 warehouse_settings_attribute + * + * @author yxy + * @date 2025-12-19 + */ +@Data +public class WarehouseSettingsAttribute { + + private Long id; + + /** + * 规则名称 + */ + private String attributeName; + + /** + * 备注 + */ + private String remark; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Wave.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Wave.java new file mode 100644 index 0000000..8f05287 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/Wave.java @@ -0,0 +1,66 @@ +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; + +/** + * 波次对象 wave + * + * @author Lion Li + * @date 2026-01-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wave") +public class Wave extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private String id; + + /** + * 人员ID + */ + private String staffId; + + /** + * 人员姓名 + */ + private String staffName; + + /** + * 数量 + */ + private Long count; + + /** + * 是否支付 + */ + private Long isPay; + + /** + * 创建时间 + */ + private Long createdTime; + + /** + * 更新时间 + */ + private Long updatedTime; + + /** + * 是否删除 + */ + private Long isDel; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WaveDetail.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WaveDetail.java new file mode 100644 index 0000000..296cf7b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WaveDetail.java @@ -0,0 +1,76 @@ +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; + +/** + * 波次信息对象 wave_detail + * + * @author Lion Li + * @date 2026-01-22 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("wave_detail") +public class WaveDetail extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + + /** + * 用户ID + */ + private Long userId; + + /** + * 波次ID + */ + private String waveId; + + /** + * ISBN + */ + private String isbn; + + /** + * 品相 + */ + private String quality; + + /** + * 仓储ID + */ + private Long stockId; + + /** + * 仓储编号 + */ + private String stockNum; + + /** + * 创建时间 + */ + private Long createdTime; + + /** + * 更新时间 + */ + private Long updatedTime; + + /** + * 是否已删除 + */ + private Long isDel; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WhiteList.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WhiteList.java new file mode 100644 index 0000000..452caf4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/WhiteList.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_white_list + * + * @author yxy + * @date 2025-06-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_white_list") +public class WhiteList extends TenantEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * ip + */ + private String ip; + + /** + * 状态(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/XyBind.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/XyBind.java new file mode 100644 index 0000000..588e638 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/XyBind.java @@ -0,0 +1,50 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +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; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_xy_bind") +public class XyBind extends BaseEntity { + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 闲管家名称 + */ + private String appName; + + /** + * 闲管家应用id + */ + private Long mallId; + + /** + * 闲管家应用密钥 + */ + private String token; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/XyCategory.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/XyCategory.java new file mode 100644 index 0000000..b3ad0c7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/XyCategory.java @@ -0,0 +1,27 @@ +package org.dromara.zhishu.domain; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("xy_category_id") +public class XyCategory extends BaseEntity { + /** + * 行业 + */ + private String industry; + + /** + * 类目 + */ + private String category; + + /** + * id + */ + private String id; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopImages.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopImages.java new file mode 100644 index 0000000..0383b08 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/ZhishuShopImages.java @@ -0,0 +1,47 @@ +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; + +/** + * 商品图片对象 zhishu_shop_images + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("zhishu_shop_images") +public class ZhishuShopImages extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private String id; + + /** + * 商品ID + */ + private String goodsId; + + /** + * 存放路径 + */ + private String path; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableLogic + private String delFlag; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BatchUpdateCargoBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BatchUpdateCargoBo.java new file mode 100644 index 0000000..6d812dc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BatchUpdateCargoBo.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BatchUpdateCargoBo { + //商品ids + private List ids; + //货区ids + private List areas; + //是否同步线上 0,1 + private Boolean isOnline; + //用户id + private Long userId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookBaseInfoBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookBaseInfoBo.java new file mode 100644 index 0000000..5cf4a93 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookBaseInfoBo.java @@ -0,0 +1,228 @@ +package org.dromara.zhishu.domain.bo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +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.BookBaseInfo; +import org.dromara.zhishu.domain.vo.BookPic; + +import java.util.Date; +import java.util.List; + +/** + * 基础信息业务对象 book_base_info + * + * @author + * @date 2025-03-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = BookBaseInfo.class, reverseConvertGenerate = false) +public class BookBaseInfoBo extends BaseEntity { + + /** id */ + @NotBlank(message = "id不能为空", groups = { EditGroup.class }) + private String id; + + /** 书名 */ + private String bookName; + + /** 书图片 */ + private BookPic bookPic; + private String isBookPic; + private String isBookPicS; + + /** 小图(外部接口需要) */ + private BookPic bookPicS; // 新增 + private String bookPicB; // 新增 + private String bookPicW; // 新增 + + /** ISBN */ + 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; + + /** 已售 */ + @JsonProperty("buy_count") + private String buyCount; + + /** 在售 */ + @JsonProperty("sell_count") + private String sellCount; + + /** 内容简介 */ + private String content; + + /** 备注 */ + private String remark; + + /** 叶子类目 id */ + private Long catId; + + /** 已售数量(外部接口字段 buy_counts) */ + private String buy_counts; // 改为String类型以支持范围值如"5,99999" + + /** 在售数量(外部接口字段 sell_counts) */ + private String sell_counts; // 改为String类型以支持范围值 + + /** 出版时间(另一格式) */ + private String publicationTimes; + + /** 违规书号 0正常 1违规 */ + private Integer vioBook; + + /** 套装书 0正常 1违规 */ + private Integer bookSet; + + /** 一号多书 0正常 1违规 */ + private Integer onenumMbooks; + + /** 违规出版社 */ + private Integer illPublisher; + + /** 违规作者 */ + private Integer illAuthor; + + /** 店铺 ids */ + private List shopIds; + + /** 数据总数 */ + private Integer total; + + /** 店铺名称 */ + private List shopNames; + + /** 是否核价 0/1 */ + private Boolean ispricing; + + /** 核价数量 */ + private Integer numbers; + + /** 销量选择 */ + private Integer saleSelect; + + /** 分类 */ + private String category; + + /** 图片类型 官图-1 实图-0 */ + private String picType; + + /** ISBN 分类 9787-1 非9787-0 */ + private String categoryType; + + /** 是否套装 1是 0否 */ + private Integer isSuit; // 改 Integer + + /** 销量范围 */ + private String totalSale_range; + + + /* ------------------------- + * 以下为外部接口新增字段 + * ------------------------- */ + + /** day_sale_7 */ + private Integer daySale7; + + /** day_sale_15 */ + private Integer daySale15; + + /** day_sale_30 */ + private Integer daySale30; + + /** day_sale_60 */ + private Integer daySale60; + + /** day_sale_90 */ + private Integer daySale90; + + /** day_sale_180 */ + private Integer daySale180; + + /** day_sale_365 */ + private Integer daySale365; + + /** this_year_sale */ + private Integer thisYearSale; + + /** last_year_sale */ + private Integer lastYearSale; + + /** total_sale */ + private Integer totalSale; + + /** 外部接口:book_pic_obj.small */ + private String picSmall; + + /** 外部接口:book_pic_obj.large */ + private String picLarge; + + /** 外部接口:book_pic_obj_s.small */ + private String picSmallS; + + /** 外部接口:book_pic_obj_s.large */ + private String picLargeS; + + /** 更新时间戳(外部接口使用) */ + @JsonProperty("updateTime") + private String updateTimeTimestamp; + + /** 店铺类型:0=拼多多, 1=孔夫子,2=淘宝, 3=闲鱼 */ + private Integer shopType; + + /** 是否驳回商品:0=不限, 1=驳回商品 */ + private Integer is_return; + + /** 是否违规商品:0=不限, 1=违规商品 */ + private Integer is_filter; + + private String page_count; + + private String word_count; + + private String kongfz_categories; + + private Integer kongfz_include; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookNumberRageBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookNumberRageBo.java new file mode 100644 index 0000000..90f70c7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookNumberRageBo.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.Data; + +@Data +public class BookNumberRageBo { + private String min1; + + private String max1; + + private String min2; + + private String max2; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookUpdateInfoBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookUpdateInfoBo.java new file mode 100644 index 0000000..da41824 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/BookUpdateInfoBo.java @@ -0,0 +1,71 @@ +package org.dromara.zhishu.domain.bo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +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.BookBaseInfo; +import org.dromara.zhishu.domain.vo.BookPic; + +import java.util.Date; +import java.util.List; + +/** + * 基础信息业务对象 book_base_info + * + * @author + * @date 2025-03-08 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = BookBaseInfo.class, reverseConvertGenerate = false) +public class BookUpdateInfoBo extends BaseEntity { + + /** id */ + @NotBlank(message = "id不能为空", groups = { EditGroup.class }) + private String id; + + /** 书名 */ + private String bookName; + + /** ISBN */ + private String isbn; + + /** 作者 */ + private String author; + + /** 装帧 */ + private String bindingLayout; + + /** 出版社 */ + private String publisher; + + /** 出版时间 */ + private String publicationTime; + + /** 定价 */ + private String fixPbook_picrice; + + /** 分类 */ + private String category; + + /** 是否套装 1是 0否 */ + private Integer isSuit; // 改 Integer + + /** 书图片 */ + private BookPic bookPic; + private String isBookPic; + private String isBookPicS; + + /** 小图(外部接口需要) */ + private BookPic bookPicS; // 新增 + private String bookPicB; // 新增 + private String bookPicW; // 新增 + + /** 更新时间戳(外部接口使用) */ + @JsonProperty("updateTime") + private String updateTimeTimestamp; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/CourierLogBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/CourierLogBo.java new file mode 100644 index 0000000..05294cb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/CourierLogBo.java @@ -0,0 +1,80 @@ +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.*; +import java.math.BigDecimal; + +/** + * 快递日志业务对象 + * + * @author yxy + * @date 2026-03-18 + */ +@Data +public class CourierLogBo { + + /** + * 主键ID + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + 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 updateBy; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EditBookInfoBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EditBookInfoBo.java new file mode 100644 index 0000000..ff5bfad --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EditBookInfoBo.java @@ -0,0 +1,167 @@ +package org.dromara.zhishu.domain.bo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +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.vo.BookPic; + +@EqualsAndHashCode(callSuper = true) +@Data +public class EditBookInfoBo extends BaseEntity { + + /** id */ + @NotBlank(message = "id不能为空", groups = { EditGroup.class }) + private String id; + + /** 书名 */ + private String bookName; + /** ISBN */ + private String isbn; + /** 作者 */ + private String author; + /** 装帧 */ + private String bindingLayout; + /** 出版社 */ + private String publisher; + /** 出版时间 */ + private String publicationTime; + /** 定价 */ + private String fixPrice; + /** 分类 */ + private String category; + /** 是否套装 1是 0否 */ + private Integer isSuit; // 改 Integer + /** 书图片 */ + private BookPic bookPic; + private String isBookPic; + private String isBookPicS; + /** 更新时间戳(外部接口使用) */ + @JsonProperty("updateTime") + private String updateTimeTimestamp; +// /** 小图(外部接口需要) */ +// private BookPic bookPicS; // 新增 +// private String bookPicB; // 新增 +// private String bookPicW; // 新增 +// /** 编辑 */ +// private String editor; +// /** 版次 */ +// private String edition; +// /** 开本 */ +// private String format; +// /** 语种 */ +// private String languages; +// /** 印刷时间 */ +// private String printTime; +// /** 纸张 */ +// private String paper; +// /** 页数 */ +// private String pages; +// /** 字数 */ +// private String wordage; +// /** 已售 */ +// @JsonProperty("buy_count") +// private String buyCount; +// /** 在售 */ +// @JsonProperty("sell_count") +// private String sellCount; +// /** 内容简介 */ +// private String content; +// /** 备注 */ +// private String remark; +// /** 叶子类目 id */ +// private Long catId; +// /** 已售数量(外部接口字段 buy_counts) */ +// private String buy_counts; // 改为String类型以支持范围值如"5,99999" +// /** 在售数量(外部接口字段 sell_counts) */ +// private String sell_counts; // 改为String类型以支持范围值 +// /** 出版时间(另一格式) */ +// private String publicationTimes; +// /** 违规书号 0正常 1违规 */ +// private Integer vioBook; +// /** 套装书 0正常 1违规 */ +// private Integer bookSet; +// /** 一号多书 0正常 1违规 */ +// private Integer onenumMbooks; +// /** 违规出版社 */ +// private Integer illPublisher; +// /** 违规作者 */ +// private Integer illAuthor; +// /** 店铺 ids */ +// private List shopIds; +// /** 数据总数 */ +// private Integer total; +// /** 店铺名称 */ +// private List shopNames; +// /** 是否核价 0/1 */ +// private Boolean ispricing; +// /** 核价数量 */ +// private Integer numbers; +// /** 销量选择 */ +// private Integer saleSelect; +// /** 图片类型 官图-1 实图-0 */ +// private String picType; +// /** ISBN 分类 9787-1 非9787-0 */ +// private String categoryType; +// /** 销量范围 */ +// private String totalSale_range; +// /* ------------------------- +// * 以下为外部接口新增字段 +// * ------------------------- */ +// +// /** day_sale_7 */ +// private Integer daySale7; +// +// /** day_sale_15 */ +// private Integer daySale15; +// +// /** day_sale_30 */ +// private Integer daySale30; +// +// /** day_sale_60 */ +// private Integer daySale60; +// +// /** day_sale_90 */ +// private Integer daySale90; +// +// /** day_sale_180 */ +// private Integer daySale180; +// +// /** day_sale_365 */ +// private Integer daySale365; +// +// /** this_year_sale */ +// private Integer thisYearSale; +// +// /** last_year_sale */ +// private Integer lastYearSale; +// +// /** total_sale */ +// private Integer totalSale; + +// /** 外部接口:book_pic_obj.small */ +// private String picSmall; +// +// /** 外部接口:book_pic_obj.large */ +// private String picLarge; +// +// /** 外部接口:book_pic_obj_s.small */ +// private String picSmallS; +// +// /** 外部接口:book_pic_obj_s.large */ +// private String picLargeS; + + + +// /** 店铺类型:0=拼多多, 1=孔夫子,2=淘宝, 3=闲鱼 */ +// private Integer shopType; + +// /** 是否驳回商品:0=不限, 1=驳回商品 */ +// private Integer is_return; +// +// /** 是否违规商品:0=不限, 1=违规商品 */ +// private Integer is_filter; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EncryptionDataSingelBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EncryptionDataSingelBo.java new file mode 100644 index 0000000..909b4a1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/EncryptionDataSingelBo.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class EncryptionDataSingelBo { + private Long dataUrl; + private Integer shopPrice; + private Integer minPrice; + private Integer maxPrice; + private Long shopId; + private String shopType; + private Long totalCount; + private String shopToken; + /** + * 查询条件 + */ + private String isOnSale; + private String isbn; + private String priceDown; + private String priceUp; + private String startDate; + private String endDate; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/FastMailBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/FastMailBo.java new file mode 100644 index 0000000..392b0fa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/FastMailBo.java @@ -0,0 +1,60 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.FastMail; +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_fast_mail + * + * @author yxy + * @date 2025-06-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = FastMail.class, reverseConvertGenerate = false) +public class FastMailBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 类型 1 韵达 + */ + private String type; + + /** + * 账号 + */ + private String partnerId; + + /** + * 联调密码 + */ + private String secret; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 面单类型 1 网点面单 2 拼多多面单 + */ + private String fastMailType; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/GoodsAutoFailBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/GoodsAutoFailBo.java new file mode 100644 index 0000000..ebb2e96 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/GoodsAutoFailBo.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.GoodsAutoFail; +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_goods_auto_fail + * + * @author yxy + * @date 2025-09-29 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = GoodsAutoFail.class, reverseConvertGenerate = false) +public class GoodsAutoFailBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + private String shopName; + + /** + * 商品id + */ + private Long goodsId; + + private String goodsName; + + /** + * 商品isbn + */ + private String isbn; + + /** + * 货号 + */ + private String artNo; + + /** + * 日志 + */ + private String callBackData; + + + private Integer pageNum; + + private Integer pageSize; + + private Long userId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/IllBaseInfoBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/IllBaseInfoBo.java new file mode 100644 index 0000000..c3afd1e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/IllBaseInfoBo.java @@ -0,0 +1,20 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class IllBaseInfoBo implements Serializable { + private List ids; + private Integer vioBook; + private Integer bookSet; + private Integer onenumMbooks; + private Integer illPublisher; + private Integer illAuthor; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/NewUserBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/NewUserBo.java new file mode 100644 index 0000000..e5cb764 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/NewUserBo.java @@ -0,0 +1,99 @@ +package org.dromara.zhishu.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.Email; +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.BookBaseInfo; +import org.dromara.zhishu.domain.NewUserInfo; + + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = NewUserInfo.class, reverseConvertGenerate = false) +public class NewUserBo extends BaseEntity { + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 企业类型 + */ + private String companyType ; + + /** + * 联系人名 + */ + private String contactPerson; + + /** + * 联系方式 + */ + private String contactPhone;; + + /** + * 邮箱 + */ + private String email; + /** + * 身份证图片 + */ + private String cardIdentity; + + + /** + * 营业执照名称 + */ + private String licenseName; + + /** + * 营业执照编号 + */ + private String licenseNumber; + + /** + * 营业执照 + */ + private String license; + + /** + * 备注 + */ + 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/bo/NoticeBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/NoticeBo.java new file mode 100644 index 0000000..a138f8c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/NoticeBo.java @@ -0,0 +1,51 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.Notice; +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_notice + * + * @author yxy + * @date 2025-05-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = Notice.class, reverseConvertGenerate = false) +public class NoticeBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long id; + + /** + * 发件人 + */ + private String sender; + + /** + * 收件人 + */ + private String recipient; + + /** + * 消息 + */ + private String content; + + /** + * 状态 0 未读 1 已读 + */ + private String status; + + + private String tenantId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PriceTemplateBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PriceTemplateBo.java new file mode 100644 index 0000000..f5f2d0a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PriceTemplateBo.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.PriceTemplate; +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; + +/** + * 价格模板业务对象 t_price_template + * + * @author yxy + * @date 2025-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = PriceTemplate.class, reverseConvertGenerate = false) +public class PriceTemplateBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 价格模板名称 + */ + private String templateName; + + /** + * 价格类型 0 书价 1 总价(书价+运费) + */ + private String priceType; + + /** + * 增加比例 + */ + private BigDecimal proportion; + + /** + * 增加金额 + */ + private BigDecimal addAmount; + + /** + * 价格模板状态(0正常 1停用) + */ + private String status; + + /** + * 价格区间最大值 + */ + private Integer highPrice; + /** + * 价格区间最小值 + */ + private Integer lowPrice; + + /** + * 价格参数 + */ + private String rangePrice; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PrintTemplateBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PrintTemplateBo.java new file mode 100644 index 0000000..ce22ad2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PrintTemplateBo.java @@ -0,0 +1,48 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.PrintTemplate; +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_print_template + * + * @author yxy + * @date 2026-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = PrintTemplate.class, reverseConvertGenerate = false) +public class PrintTemplateBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 快递类型 + */ + private String expressType; + + /** + * 模板名称 + */ + private String printTemplateName; + + /** + * 0正常 1停用 + */ + private String status; + + /** + * 包裹信息json字符串 + */ + private String parcelInformation; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PrinterBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PrinterBo.java new file mode 100644 index 0000000..4de7872 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/PrinterBo.java @@ -0,0 +1,71 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.Printer; +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_printer + * + * @author yxy + * @date 2026-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = Printer.class, reverseConvertGenerate = false) +public class PrinterBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + + /** + * 打印机类型 1 本地打印机 2 拼多多云打印机 + */ + private String printType; + + /** + * 拼多多云打印机共享码 + */ + private String shareCode; + + /** + * 打印机 + */ + private String printer; + + /** + * 打印机名称 + */ + private String printerName; + + /** + * 是否启用全程打印 + */ + private String isRemotePrinting; + + /** + * 0正常 1停用 + */ + private String status; + + /** + * 验证码 + */ + private String captcha; + + /** + * 拼多多打印机绑定店铺token + */ + private String accessToken; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/RunningLogFileBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/RunningLogFileBo.java new file mode 100644 index 0000000..392d0b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/RunningLogFileBo.java @@ -0,0 +1,55 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.RunningLogFile; +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_running_log_file + * + * @author yxy + * @date 2025-06-12 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = RunningLogFile.class, reverseConvertGenerate = false) +public class RunningLogFileBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 文件名称 + */ + private String fileName; + + /** + * 文件顺序 + */ + private String fileOrder; + + /** + * 文件类型 + */ + private String fileType; + + /** + * 文件大小 + */ + private String fileSize; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/RunningTaskBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/RunningTaskBo.java new file mode 100644 index 0000000..273bf4a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/RunningTaskBo.java @@ -0,0 +1,60 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.RunningTask; +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_running_task + * + * @author yxy + * @date 2025-07-23 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = RunningTask.class, reverseConvertGenerate = false) +public class RunningTaskBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 任务id + */ + private Long taskId; + + /** + * 任务名称 + */ + private String taskName; + + /** + * 优先级 + */ + private Long priority; + + /** + * 内容json字符串 + */ + private String data; + + /** + * 状态 0 未执行 1 执行中 2 执行完成 + */ + private String status; + + /** + * 任务执行完返回的数据 + */ + private String callBackData; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopBo.java new file mode 100644 index 0000000..3bac82e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopBo.java @@ -0,0 +1,150 @@ +package org.dromara.zhishu.domain.bo; + +import com.alibaba.excel.annotation.ExcelProperty; +import org.dromara.zhishu.domain.Shop; +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 java.util.Date; + +/** + * 店铺主表业务对象 t_shop + * + * @author yxy + * @date 2025-03-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = Shop.class, reverseConvertGenerate = false) +public class ShopBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 三方店铺id + */ + private Long mallId; + + /** + * 店铺类型 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; + + + /** + * 租户编码 + */ + private String tenant_id; + + /** + * 第三方平台账号 + */ + 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; + + /** + * 订购时间 (月份) + */ + private String payMonth; + + /** + * 拼多多试用版是否无上限 1 否 2 是 + */ + private String deregulation; + + /** + * 使用次数 + */ + private Long usageCount; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopContextBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopContextBo.java new file mode 100644 index 0000000..f67d64f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopContextBo.java @@ -0,0 +1,45 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.ShopContext; +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_shop_context + * + * @author yxy + * @date 2025-09-30 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ShopContext.class, reverseConvertGenerate = false) +public class ShopContextBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 商品描述 + */ + private String context; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopGoodsPublishedBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopGoodsPublishedBo.java new file mode 100644 index 0000000..b7618d7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopGoodsPublishedBo.java @@ -0,0 +1,91 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.ShopGoodsPublished; +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.Date; + +/** + * 记录发布数据业务对象 t_shop_goods_published + * + * @author yxy + * @date 2025-04-11 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ShopGoodsPublished.class, reverseConvertGenerate = false) +public class ShopGoodsPublishedBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 图书主键 + */ + private String shopGoodsId; + + /** + * 发布的店铺ids + */ + private String shopId; + + /** + * 平台商品id + */ + private String platformId; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 品相 + */ + private String conditionCode; + + /** + * 货区id + */ + private Long depotId; + + /** + * isbn + */ + private String isbn; + + /** + * 用户id + */ + private Long userId;; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 修改时间 + */ + private Date updateTime; + + /** + * 商品编码 + */ + private String itemNumber; + + /** + * 货号 + */ + private String artNo; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopImgBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopImgBo.java new file mode 100644 index 0000000..39d5265 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopImgBo.java @@ -0,0 +1,60 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.ShopImg; +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_shop_img + * + * @author yxy + * @date 2025-03-17 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ShopImg.class, reverseConvertGenerate = false) +public class ShopImgBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + 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; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopWarehouseBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopWarehouseBo.java new file mode 100644 index 0000000..f853b2e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ShopWarehouseBo.java @@ -0,0 +1,41 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.ShopWarehouse; +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_shop_warehouse + * + * @author yxy + * @date 2025-12-28 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ShopWarehouse.class, reverseConvertGenerate = false) +public class ShopWarehouseBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 用户id(仓库id) + */ + @NotNull(message = "用户id(仓库id)不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long userId; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SinglePrintBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SinglePrintBo.java new file mode 100644 index 0000000..e594774 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/SinglePrintBo.java @@ -0,0 +1,58 @@ +package org.dromara.zhishu.domain.bo; + +import lombok.Data; + +/** + * 单票打印查询条件对象 + * + * @author yxy + * @date 2026-03-27 + */ +@Data +public class SinglePrintBo { + + /** + * 主键ID + */ + private Long id; + + /** + * 快递单号 + */ + private String mailNo; + + /** + * 发件人名称 + */ + private String senderName; + + /** + * 发件人联系方式 + */ + private String senderPhone; + + /** + * 收件人名称 + */ + private String receiverName; + + /** + * 收件人联系方式 + */ + private String receiverPhone; + + /** + * 物品名称 + */ + private String itemName; + + /** + * 打单账号id + */ + private Long fastMailId; + + /** + * 创建人id + */ + private Long createBy; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TAuditBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TAuditBo.java new file mode 100644 index 0000000..7b8b487 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TAuditBo.java @@ -0,0 +1,77 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.TAudit; +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_audit + * + * @author Lion Li + * @date 2025-04-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TAudit.class, reverseConvertGenerate = false) +public class TAuditBo extends BaseEntity { + /** + * id + */ + private Long id; + /** + * 用户ID + */ + private Long userId; + + /** + * 管理员ID + */ + private Long adminId; + + /** + * 审核状态(0通过 1未通过 2待审核) + */ + private String status; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 企业类型 + */ + private String companyType ; + + /** + * 联系人名 + */ + private String contactPerson; + + /** + * 联系方式 + */ + private String contactPhone;; + + /** + * 邮箱 + */ + private String email; + + /** + * 营业执照 + */ + private String license; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TDepotBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TDepotBo.java new file mode 100644 index 0000000..a12e7c5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TDepotBo.java @@ -0,0 +1,76 @@ +package org.dromara.zhishu.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.zhishu.domain.TDepot; + +/** + * 仓库信息设置业务对象 t_depot + * + * @author Lion Li + * @date 2025-03-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TDepot.class, reverseConvertGenerate = false) +public class TDepotBo extends BaseEntity { + + /** + * 仓库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 String templateId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TFreightBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TFreightBo.java new file mode 100644 index 0000000..d75a574 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TFreightBo.java @@ -0,0 +1,74 @@ +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.TFreight; + +/** + * 三级货区管理业务对象 t_freight + * + * @author Lion Li + * @date 2025-04-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TFreight.class, reverseConvertGenerate = false) +public class TFreightBo extends BaseEntity { + + /** + * 货位id + */ +// @NotNull(message = "货位id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 货架id + */ +// @NotNull(message = "货架id不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long shelvesId; + + /** + * 货位编码 + */ + private String code; + + /** + * 货位名称 + */ + private String name; + + /** + * 货位单位 + */ + private String unit; + + /** + * 货位容量 + */ + private Long capMax; + + /** + * 货号 + */ + private String artNo; + + /** + * 仓库状态(0正常 1停用) + */ + private String status; + + /** + * userId + */ + private Long userId; + + /** + * 是否开启分销 0否 1是 + */ + private String allowDistribution; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TInviteRelationsBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TInviteRelationsBo.java new file mode 100644 index 0000000..3266975 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TInviteRelationsBo.java @@ -0,0 +1,56 @@ +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 java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.zhishu.domain.TInviteRelations; + +/** + * 【请填写功能名称】业务对象 t_invite_relations + * + * @author Lion Li + * @date 2025-12-16 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TInviteRelations.class, reverseConvertGenerate = false) +public class TInviteRelationsBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 邀请人ID + */ + @NotNull(message = "邀请人ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long inviterId; + + /** + * 被邀请人ID + */ + @NotNull(message = "被邀请人ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long inviteeId; + + /** + * 使用的邀请码 + */ + @NotBlank(message = "使用的邀请码不能为空", groups = { AddGroup.class, EditGroup.class }) + private String inviteCode; + + /** + * 邀请时间 + */ + @NotNull(message = "邀请时间不能为空", groups = { AddGroup.class, EditGroup.class }) + private Date inviteTime; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShelvesBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShelvesBo.java new file mode 100644 index 0000000..7495f36 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShelvesBo.java @@ -0,0 +1,73 @@ +package org.dromara.zhishu.domain.bo; + +import com.baomidou.mybatisplus.annotation.TableField; +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.TShelves; + +/** + * 货架信息业务对象 t_shelves + * + * @author Lion Li + * @date 2025-03-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TShelves.class, reverseConvertGenerate = false) +public class TShelvesBo extends BaseEntity { + + /** + * 货架id + */ + @NotNull(message = "货架id不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 货架名称 + */ + private String name; + + /** + * 货架容量 + */ + private Long sheCapMax; + + + /** + * 货架单位 + */ + private String unit; + + /** + * 仓库id + */ + private Long depotId; + + /** + * 货架状态(0正常 1停用) + */ + private String status; + + /** + * 货架编码 + */ + private String code; + + /** + * 仓库名称 + */ + private String depotName; + + /** + * userId + */ + @TableField(exist = false) + private Long userId; + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopOrderDetailBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopOrderDetailBo.java new file mode 100644 index 0000000..36e182a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/TShopOrderDetailBo.java @@ -0,0 +1,107 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.TShopOrderDetail; +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_shop_order_detail + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = TShopOrderDetail.class, reverseConvertGenerate = false) +public class TShopOrderDetailBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 店铺id + */ + @NotBlank(message = "店铺id不能为空", groups = { AddGroup.class, EditGroup.class }) + private String shopId; + + /** + * 店铺名称 + */ + @NotBlank(message = "店铺名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String shopName; + + /** + * 订单id + */ + @NotBlank(message = "订单id不能为空", groups = { AddGroup.class, EditGroup.class }) + private String orderId; + + /** + * 商品数量 + */ + @NotNull(message = "商品数量不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long goodsCount; + + /** + * 商品编码 + */ + @NotBlank(message = "商品编码不能为空", groups = { AddGroup.class, EditGroup.class }) + private String goodsId; + + /** + * 商品图片 + */ + @NotBlank(message = "商品图片不能为空", groups = { AddGroup.class, EditGroup.class }) + private String goodsImg; + + /** + * 商品名称 + */ + @NotBlank(message = "商品名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String goodsName; + + /** + * 商品单件 单价:元 + */ + @NotBlank(message = "商品单件 单价:元不能为空", groups = { AddGroup.class, EditGroup.class }) + private String goodsPrice; + + /** + * 商品规格 + */ + @NotBlank(message = "商品规格不能为空", groups = { AddGroup.class, EditGroup.class }) + private String goodsSpec; + + /** + * 商品维度外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息 + */ + @NotBlank(message = "商品维度外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息不能为空", groups = { AddGroup.class, EditGroup.class }) + private String outerGoodsId; + + /** + * sku维度商家外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息 + */ + @NotBlank(message = "sku维度商家外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息不能为空", groups = { AddGroup.class, EditGroup.class }) + private String outerId; + + /** + * 商品sku编码 + */ + @NotBlank(message = "商品sku编码不能为空", groups = { AddGroup.class, EditGroup.class }) + private String skuId; + + /** + * 店铺状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserAccountBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserAccountBo.java new file mode 100644 index 0000000..a4dd7a9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserAccountBo.java @@ -0,0 +1,60 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.UserAccount; +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_user_account + * + * @author yxy + * @date 2026-02-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = UserAccount.class, reverseConvertGenerate = false) +public class UserAccountBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 出入帐账户类型 0 出账 1 入账 + */ + private String type; + + /** + * 账号类型 + */ + private String accountType; + + /** + * 账号名称 + */ + private String accountName; + + /** + * 账号 + */ + private String account; + + /** + * 是否默认账号 0 否 1 是 + */ + private String isDefault; + + /** + * 店铺状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserTAuditBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserTAuditBo.java new file mode 100644 index 0000000..2103d54 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/UserTAuditBo.java @@ -0,0 +1,115 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.UserTAudit; +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_audit + * + * @author Lion Li + * @date 2025-04-02 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = UserTAudit.class, reverseConvertGenerate = false) +public class UserTAuditBo extends BaseEntity { + + /** + * id + */ + private Long id; + /** + * 用户ID + */ + private Long userId; + + /** + * 管理员ID + */ + private Long adminId; + + /** + * 审核状态(0通过 1未通过 2待审核) + */ + private String status; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 企业类型 + */ + private String companyType ; + + /** + * 联系人名 + */ + private String contactPerson; + + /** + * 联系方式 + */ + private String contactPhone;; + + /** + * 邮箱 + */ + private String email; + + /** + * 身份证图片 + */ + private String cardIdentity; + + + /** + * 营业执照名称 + */ + private String licenseName; + + /** + * 营业执照编号 + */ + private String licenseNumber; + + /** + * 营业执照 + */ + private String license; + + /** + * 备注 + */ + 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/bo/ViolationBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ViolationBo.java new file mode 100644 index 0000000..a9a1982 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ViolationBo.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.Violation; +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_violation + * + * @author yxy + * @date 2025-06-23 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = Violation.class, reverseConvertGenerate = false) +public class ViolationBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 类型 0 isbn 1 书名 2 作者 3 出版社 + */ + private String type; + + /** + * 违规原因 + */ + private String content; + + /** + * 发起人 + */ + private Long userid; + + /** + * 是否审核 0 未审核 1 已审核 + */ + private String review; + + /** + * 状态(0正常 1停用) + */ + private String status; + + /** + * 审核意见 + */ + private String remark; + + /** + * 违规内容 + */ + private String name; + + /** + * 分类 + */ + private String sort; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WarehouseSettingsBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WarehouseSettingsBo.java new file mode 100644 index 0000000..de10ad8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WarehouseSettingsBo.java @@ -0,0 +1,91 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.UserSettingsAttribute; +import org.dromara.zhishu.domain.WarehouseSettings; +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 java.math.BigDecimal; +import java.util.List; + +/** + * 设置业务对象 warehouse_settings + * + * @author yxy + * @date 2025-12-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = WarehouseSettings.class, reverseConvertGenerate = false) +public class WarehouseSettingsBo extends BaseEntity { + + /** + * + */ + @NotNull(message = "不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 设置模板名称 + */ + private String settingName; + + /** + * 库存同步形式 0 下单减库存 1 支付减库存 + */ + private Long stockSynchronizeType; + + /** + * 是否自动下发 0 否 1 是 + */ + private Long autoIssue; + + /** + * 是否开启亏损保护 0 否 1 是 + */ + private Long lossProtection; + + /** + * 利润下限 + */ + private BigDecimal profitFloor; + + /** + * 是否启用 0 否 1 是 + */ + private Long status; + + /** + * 是否删除 0 否 1 是 + */ + private Long delFlag; + + /** + * 退款后是否自动回退库存 0否 1是 + */ + private Long stockRollback; + + /** + * 创建时间时间戳 + */ + private Long createAt; + + /** + * 修改时间时间戳 + */ + private Long updateAt; + + /** + * 店铺id + */ + private String shopIds; + + /** + * 规则数据 + */ + private String userSettingsAttributeListStr; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WaveDetailBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WaveDetailBo.java new file mode 100644 index 0000000..147d5d2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WaveDetailBo.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.WaveDetail; +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.dto.WaveDetailInsertDto; + +/** + * 波次信息业务对象 wave_detail + * + * @author Lion Li + * @date 2026-01-22 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = WaveDetail.class, reverseConvertGenerate = false) +public class WaveDetailBo extends BaseEntity { + + /** + * 主键ID + */ + @NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 波次ID + */ + private Long waveId; + + /** + * ISBN + */ + private String isbn; + + /** + * 仓储ID + */ + private Long stockId; + + /** + * 仓储编号 + */ + private String stockNum; + + /** + * 创建时间 + */ + private Long createdTime; + + /** + * 更新时间 + */ + private Long updatedTime; + + /** + * 是否已删除 + */ + private Long isDel; + + /** + * 前台传递对象 + */ + private WaveDetailInsertDto requestData; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WhiteListBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WhiteListBo.java new file mode 100644 index 0000000..6e1d3cf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/WhiteListBo.java @@ -0,0 +1,40 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.WhiteList; +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_white_list + * + * @author yxy + * @date 2025-06-25 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = WhiteList.class, reverseConvertGenerate = false) +public class WhiteListBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * ip + */ + private String ip; + + /** + * 状态(0正常 1停用) + */ + private String status; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/XyBindBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/XyBindBo.java new file mode 100644 index 0000000..776b221 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/XyBindBo.java @@ -0,0 +1,40 @@ +package org.dromara.zhishu.domain.bo; + +import com.baomidou.mybatisplus.annotation.TableLogic; +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; + + +@Data +@EqualsAndHashCode(callSuper = true) +public class XyBindBo extends BaseEntity { + /** + * + */ + @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/bo/XyCategoryBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/XyCategoryBo.java new file mode 100644 index 0000000..6dea11f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/XyCategoryBo.java @@ -0,0 +1,27 @@ +package org.dromara.zhishu.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.zhishu.domain.XyCategory; + +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = XyCategory.class, reverseConvertGenerate = false) +public class XyCategoryBo extends BaseEntity { + /** + * 行业 + */ + private String industry; + + /** + * 类目 + */ + private String category; + + /** + * id + */ + private String id; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopGoodsBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopGoodsBo.java new file mode 100644 index 0000000..2b4dd1d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopGoodsBo.java @@ -0,0 +1,290 @@ +package org.dromara.zhishu.domain.bo; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +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.ZhishuShopGoods; + +import java.util.List; + +/** + * 商品信息业务对象 zhishu_shop_goods + * + * @author Lion Li + * @date 2025-03-07 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ZhishuShopGoods.class, reverseConvertGenerate = false) +public class ZhishuShopGoodsBo extends BaseEntity { + + /** + * id + */ + @NotBlank(message = "id不能为空", groups = {EditGroup.class}) + private String id; + + /** + * 是否查寻全部商品:1-否 2-是 + */ + private Integer isQueryAllGoods; + + /** + * 是否加入分销:0-否 1-是 + */ + private Integer isJoinDistribution; + + /** + * 用户id + */ + private Long userId; + + /** + * 产品编码 + */ + private String productId; + + /** + * 仓库Id + */ + private Long depotId; + + /** + * 仓库名称 + */ + private String depotName; + + /** + * 地址 + */ + private String address; + + /** + * 物流模板Id + */ + private Long templateId; + + /** + * 物流模板名称 + */ + private String templateName; + + /** + * 商品名称 + */ + private String goodsName; + + /** + * isbn + */ + private String isbn; + + /** + * 货号 + */ + private String artNo; + + /** + * 原始货号 + */ + private String originalArtNo; + + /** + * 期初库存 + */ + private Long stock; + + /** + * 标准售价 + */ + private Long price; + + /** + * 运算符 + */ + private String minprice; + + /** + * 最高标准价格 + */ + private String maxprice; + + /** + * 品相 + */ + private String conditionCode; + + /** + * 备注 + */ + private String remark; + + /** + * 商品编号 + */ + private String itemNumber; + + /** + * 商品定价 + */ + private Long fixPrice; + + /** + * 库存 + */ + private Long inventory; + + /** + * 运算符 + */ + private String mininventory; + + /** + * 最高库存 + */ + private Long maxinventory; + + /** + * 是否已进行货号转换:0-否,1-是 + */ + private Integer isArtNoConversion; + + /** + * 图片是否为空:1-是,0-否 + */ + private Integer IsBookPicNull; + + /** + * 图片 + */ + private String bookPic; + + /** + * 单位 + */ + private String unit; + + /** + * 包册数 + */ + private Long booksNumber; + + /** + * 页数 + */ + private Long pages; + + /** + * 是否是套餐(0套餐 1非套餐) + */ + private Long isPackage; + + /** + * 出版社名称 + */ + private String publicationName; + + /** + * 出版时间 + */ + private String publicationTime; + + /** + * 作者 + */ + private String author; + + /** + * 出版社 + */ + private String publisher; + + /** + * 出版时间 + */ + private String publisherTime; + + /** + * 开本 + */ + private String format; + /** + * 开本 + */ + private String wordage; + /** + * 统一书号 + */ + private String unifiedIsbn; + + /** + * 地区 + */ + private String region; + + /** + * 译者 + */ + private String translator; + + /** + * 编者 + */ + private String editor; + + /** + * 书籍开本 + */ + private String booklets; + + /** + * 字数 + */ + private Long wordCount; + + /** + * 装帧类型 + */ + private String bindType; + + /** + * 包装方式(0礼盒装 1普通包装) + */ + private Long packing; + + /** + * 货区Id列表 + */ + private List cargoAreaIds; + + /** + * 是否存在isbn:0-否,1-是 + */ + private Integer isExistIsbn; + + /** + * 任务id + */ + private Long taskId; + + + /** + * 开始时间 + */ + private String startTime; + + /** + * 结束时间 + */ + private String endTime; + + /** + * 仓库的用户id + */ + private String warehouseUserId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopGoodsDetailBo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopGoodsDetailBo.java new file mode 100644 index 0000000..749f28b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/bo/ZhishuShopGoodsDetailBo.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.domain.bo; + +import org.dromara.zhishu.domain.ZhishuShopGoodsDetail; +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.*; + +/** + * 商品信息补全表业务对象 zhishu_shop_goods_detail + * + * @author yxy + * @date 2025-06-13 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = ZhishuShopGoodsDetail.class, reverseConvertGenerate = false) +public class ZhishuShopGoodsDetailBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = { EditGroup.class }) + 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; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BookBaseInfoDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BookBaseInfoDto.java new file mode 100644 index 0000000..a34192f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BookBaseInfoDto.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.domain.dto; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.dromara.zhishu.domain.bo.BookBaseInfoBo; + +@Data +public class BookBaseInfoDto extends BookBaseInfoBo { + + + private String publicationStartTime; + + private String publicationEndTime; + + @JsonProperty("totalSale_range") + private String totalSale_range; + /** 已售数量(外部接口字段 buy_counts) */ + private String buy_counts; // 改为String类型以支持范围值如"5,99999" + + /** 在售数量(外部接口字段 sell_counts) */ + private String sell_counts; // 改为String类型以支持范围值 + + private String page_count; + + private String word_count; + + private String kongfz_categories; + + private Integer kongfz_include; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BookPriceInfoDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BookPriceInfoDto.java new file mode 100644 index 0000000..eb4cf42 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/BookPriceInfoDto.java @@ -0,0 +1,43 @@ +package org.dromara.zhishu.domain.dto; + +import com.opencsv.bean.CsvBindByName; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BookPriceInfoDto { + + @CsvBindByName(column = "ISBN", required = true) + private String isbn; + + @CsvBindByName(column = "书名") + private String bookName; + + // 单位分 + @CsvBindByName(column = "原始价格") + private String originalPrice; + + // 单位分 + @CsvBindByName(column = "核价价格") + private String corePrice; + + // 单位分 + @CsvBindByName(column = "改价价格") + private String modifiedPrice; + + @CsvBindByName(column = "平台ID") + private String platformId; + + @CsvBindByName(column = "SkuID") + private String skuId; + + @CsvBindByName(column = "在售数量") + private String saleQuantity; + + @CsvBindByName(column = "原因") + private String reason; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/ErpGoodsDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/ErpGoodsDto.java new file mode 100644 index 0000000..9c20c60 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/ErpGoodsDto.java @@ -0,0 +1,33 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * erp店铺商品dro + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ErpGoodsDto { + + private String tableName; + + private String shopId; + + private String trilateralId; + + private String isOnSale; + + private String isbn; + + private String priceDown; + + private String priceUp; + + private String startDate; + + private String endDate; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/KongfzRequestDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/KongfzRequestDto.java new file mode 100644 index 0000000..ecc1171 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/KongfzRequestDto.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.domain.dto; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +@Data +public class KongfzRequestDto { + //商品编号 + private Long itemId; + //商品审核状态,上架商品时,商品审核状态会修改为待审核,需要重新审核通过后才可以出售 + private String certifyStatus; + //上架时间戳 + private String beginSaleTime; + //更新时间 + private String updateTime; + //下架时间戳。系统默认的一个很大的时间戳 + private String endSaleTime; + //上下架状态。1:上架;0:下架 + private String isOnSale; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/KongfzShopDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/KongfzShopDto.java new file mode 100644 index 0000000..334e950 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/KongfzShopDto.java @@ -0,0 +1,28 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.springframework.beans.BeanUtils; + +@Data +public class KongfzShopDto { + //商品编号 + private Long itemId; + //商品审核状态,上架商品时,商品审核状态会修改为待审核,需要重新审核通过后才可以出售 + private String certifyStatus; + //上架时间戳 + private String beginSaleTime; + //更新时间 + private String updateTime; + //下架时间戳。系统默认的一个很大的时间戳 + private String endSaleTime; + //上下架状态。1:上架;0:下架 + private Integer isOnSale; + // 转换方法 + public static KongfzShopDto fromEntity(ZhishuShopGoods zs) { + KongfzShopDto dto = new KongfzShopDto(); + BeanUtils.copyProperties(zs, dto); + dto.setIsOnSale(1); // 默认上架状态 + return dto; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/OrderExternalGoodsDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/OrderExternalGoodsDto.java new file mode 100644 index 0000000..aecc256 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/OrderExternalGoodsDto.java @@ -0,0 +1,347 @@ +package org.dromara.zhishu.domain.dto; + +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class OrderExternalGoodsDto extends BaseEntity { + + /** + * + */ + private Long id; + + /** + * 订单类型 1 内部订单 2 外部订单 + */ + private Long type; + + /** + * 订单id + */ + private Long orderId; + + /** + * erp自营商品id + */ + private Long goodsId; + + /** + * 店家支付金额(不包含手续费) + */ + private Long payPrice; + + /** + * 手续费 + */ + private Long serviceCharge; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 创建时间时间戳 + */ + private Long createdAt; + + /** + * 是否完成分销 0否 1是 + */ + private String isDistribution; + + /** + * 仓库的创建人 + */ + private Long deptUseId; + + + /** + * 是否出库 0 未出库 1 出库 + */ + private Long whetherOutbound; + + /** + * erp订单id + */ + private Long erpOrderId; + + /** + * 订单编号 + */ + private String orderSn; + + /** + * 平台店铺id + */ + private String shopId; + + /** + * erp店铺id + */ + private Long shopErpId; + + /** + * 店铺名称 + */ + private String shopErpName; + + /** + * 店铺类型 + */ + private Long shopType; + + /** + * 商品一级id + */ + private Long catId1; + + /** + * 商品二级id + */ + private Long catId2; + + /** + * 商品三级id + */ + private Long catId3; + + /** + * 商品四级id + */ + private Long catId4; + + /** + * 订单中商品sku列表json字符富川 + */ + private String itemList; + + /** + * 订单金额 单位:分 + */ + private Long orderTotal; + + /** + * 商品金额(以分为单位)商品金额=商品销售价格*商品数量-订单改价折扣金额 + */ + private Long goodsAmount; + + /** + * 订单改价折扣金额(以分为单位) + */ + private Long orderChangeAmount; + + /** + * 支付金额 (以分为单位) 支付金额=商品金额-折扣金额+邮费+服务费 + */ + private Long payAmount; + + /** + * 创建时间 时间戳 + */ + private Long erpOrderCreatedAt; + + /** + * 成交状态 + */ + private Long confirmStatus; + + /** + * 成交时间 时间戳 + */ + private Long confirmAt; + + /** + * 支付单号 + */ + private String payNo; + + /** + * 支付时间 时间戳 + */ + private Long payAt; + + /** + * 支付方式 + */ + private Long payType; + + /** + * 平台优惠金额 (以分为单位) + */ + private Long platformDiscount; + + /** + * 买家留言信息 + */ + private String buyerMemo; + + /** + * 发货状态 1: 待付款 2:待发货,3:已发货待签收,4:交易成功 5: 已退款 6 :交易关闭 + */ + private Long orderStatus; + + /** + * 修改用,修改前的订单状态 + */ + private Long oldOrderStatus; + + /** + * 物流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首字母(大写)用于分区 + */ + private String shopMd5Prefix; + + /** + * 是否下发订单 0 否 1 是 + */ + private Long isIssue; + + /** + * erp的订单售后状态 0 无售后 1 待仓库处理 2 待仓库收货 3 售后完成 4 拒绝 5 延后处理 + */ + private Long erpAfterSalesStatus; + + /** + * erp订单售后发起时间 + */ + private Long erpAssCreateAt; + + /** + * 售后原因 + */ + private String erpAssReason; + + /** + * 拒绝原因 + */ + private String erpAssRemark; + + /** + * 退货地址 + */ + private String erpAssAddress; + + /** + * 分页查询属性 + */ + //第几页 + private Integer pageNum; + //一页多少条 + private Integer pageSize; + + private Long startTime; + private Long endTime; + // 货号 + private String artNo; + // 原始货号 + private String originalArtNo; + // 是否查寻全部商品:1-否 2-是 + private Integer isQueryAllGoods; + // isbn + private String isbn; + + /** + * 收件人名称 + */ + private String receiverName; + + /** + * 收件人电话 + */ + private String mobile; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/PddOrderQueryDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/PddOrderQueryDto.java new file mode 100644 index 0000000..b3fd690 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/PddOrderQueryDto.java @@ -0,0 +1,35 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; + +@Data +public class PddOrderQueryDto { + + + + private Integer order_status; // 1:待发货,2:已发货待签收,3:已签收 5:全部 + + private Integer page; + + private Integer page_size; + + private Integer refund_status; //售后状态 1:无售后或售后关闭,2:售后处理中,3:退款中,4: 退款成功 5:全部 + + private Long start_confirm_at; //时间戳 + + private Long end_confirm_at; //时间戳 + + + private String startTime; + + private String endTime; + + + private Integer trade_type; // 0-普通订单 ,1- 定金订单 + + private boolean use_has_next; + + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/SuccessDataItemDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/SuccessDataItemDto.java new file mode 100644 index 0000000..cd48792 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/SuccessDataItemDto.java @@ -0,0 +1,154 @@ +package org.dromara.zhishu.domain.dto; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.zhishu.annotation.EnableExcelComment; +import org.dromara.zhishu.converter.PriceDivideBy100Converter; +import org.springframework.util.StringUtils; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@AutoMapper(target = SuccessDataItemDto.class) // 添加注解 +@EnableExcelComment +@HeadRowHeight(30) // 设置表头行高为30磅 +public class SuccessDataItemDto { + + /** + * 拉取商品表主键 + */ + @ExcelIgnore + private String id; + + /** + * ISBN + */ + @ExcelProperty(value = "ISBN") + @ColumnWidth(15) + private String isbn; + + /** + * 三方平台商品Id + */ + @ExcelProperty(value = "商品id") + @ColumnWidth(15) + private String trilateralId; + + /** + * 商品编码 + */ + @ExcelProperty(value = "商品编码") + @ColumnWidth(15) + private String goodsCode; + /** + * 图片 + */ + @ExcelIgnore + private Object img; + + /** + * 书名 + */ + @ExcelProperty(value = "商品名称") + @ColumnWidth(15) + private String title; + + /** + * 库存 + */ + @ExcelProperty(value = "库存数量") + @ColumnWidth(15) + private String stock; + + /** + * 完成时间 + */ + @ExcelProperty(value = "创建时间") + @ColumnWidth(15) + private String finishTime; + + /** + * 价格 + */ + @ExcelProperty(value = "价格", converter = PriceDivideBy100Converter.class) + @ColumnWidth(15) + private String totalPrice; + + /** + * sku编码 + */ + @ExcelProperty(value = "规格编码/货号") + @ColumnWidth(15) + private String skuCode; + + /** + * skuId + */ + @ExcelIgnore + private String skuId; + + /** + * 是否在售 + */ + @ExcelProperty(value = "是否在架上", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=下架,1=上架") + @ColumnWidth(15) + private String isOnSale; + + /** + * 图片选择 + */ + @ExcelIgnore + private String imageSelect; + + /** + * 权重 + */ + @ExcelIgnore + private String priority; + + /** + * 图片 + */ + @ExcelProperty(value = "商品图片") + @ColumnWidth(15) + private String imageBigUrl; + + /** + * quality + */ + @ExcelIgnore + private String quality; + + /** + * 店铺类型 + */ + @ExcelIgnore + private String shopType; + + + /** + * 判断数据是否有效(至少有一个业务字段有值) + * + * @return true: 有效数据, false: 无效数据(提示行产生的空对象) + */ + public boolean isValidData() { + return StringUtils.hasText(isbn) + || StringUtils.hasText(trilateralId) + || StringUtils.hasText(goodsCode) + || StringUtils.hasText(title) + || StringUtils.hasText(stock) + || StringUtils.hasText(totalPrice) + || StringUtils.hasText(skuCode) + || StringUtils.hasText(isOnSale) + || StringUtils.hasText(imageBigUrl); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/SuccessDataKfz.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/SuccessDataKfz.java new file mode 100644 index 0000000..aeda531 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/SuccessDataKfz.java @@ -0,0 +1,136 @@ +package org.dromara.zhishu.domain.dto; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.zhishu.annotation.EnableExcelComment; +import org.dromara.zhishu.converter.PriceDivideBy100Converter; +import org.dromara.zhishu.converter.QualityConverter; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@AutoMapper(target = SuccessDataKfz.class) // 添加注解 +@HeadRowHeight(30) // 设置表头行高为30磅 +public class SuccessDataKfz { + + /** + * 商品编码 + */ + @ExcelProperty(value = "商品编号") + @ColumnWidth(15) + private String goodsCode; + + + /** + * 书名 + */ + @ExcelProperty(value = "商品名称") + @ColumnWidth(15) + private String title; + + /** + * sku编码 + */ + @ExcelProperty(value = "货号") + @ColumnWidth(15) + private String artNo; + + + /** + * ISBN + */ + @ExcelProperty(value = "ISBN") + @ColumnWidth(15) + private String isbn; + + /** + * 作者 + */ + @ExcelProperty(value = "作者") + @ColumnWidth(15) + private String author; + + /** + * 出版社 + */ + @ExcelProperty(value = "出版社") + @ColumnWidth(15) + private String publisher; + + /** + * 定价 + */ + @ExcelProperty(value = "商品定价", converter = PriceDivideBy100Converter.class) + @ColumnWidth(15) + private String pricing; + + + /** + * 售价 + */ + @ExcelProperty(value = "商品售价", converter = PriceDivideBy100Converter.class) + @ColumnWidth(15) + private String totalPrice; + + + /** + * 商品分类 + */ + @ExcelProperty(value = "商品分类") + @ColumnWidth(15) + private String goodsClassification; + + /** + * 本店分类 + */ + @ExcelProperty(value = "本店分类") + @ColumnWidth(15) + private String shopClassification; + + /** + * 品相 + */ + @ExcelProperty(value = "品相", converter = QualityConverter.class) + @ColumnWidth(15) + private String quality; + + /** + * 库存 + */ + @ExcelProperty(value = "库存") + @ColumnWidth(15) + private String stock; + + /** + * 完成时间 + */ + @ExcelProperty(value = "上书时间") + @ColumnWidth(15) + private String finishTime; + + /** + * 三方平台商品Id + */ + @ExcelProperty(value = "商品ID") + @ColumnWidth(15) + private String trilateralId; + + /** + * 商品ID + */ + @ExcelProperty(value = "店铺ID") + @ColumnWidth(15) + private String shopId; + + /** + * 图片 + */ + @ExcelProperty(value = "商品图片") + @ColumnWidth(15) + private String img; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/TShopGoodsPublishedDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/TShopGoodsPublishedDto.java new file mode 100644 index 0000000..3216a1a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/TShopGoodsPublishedDto.java @@ -0,0 +1,62 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; + +/** + * 已发布商品信息DTO + */ +@Data +public class TShopGoodsPublishedDto { + + /** + * 主键ID + */ + private Long id; + + /** + * erp店铺id + */ + private Long erpShopId; + + /** + * 平台店铺名称 + */ + private String shopName; + + /** + * 店铺名称 + */ + private String erpShopName; + + /** + * 新商品id + */ + private Long productId; + + /** + * 新仓库id + */ + private Long warehouseId; + + /** + * 平台店铺id + */ + private Long shopId; + + /** + * 平台商品id + */ + private Long trilateralId; + + // ==================== 分页参数 ==================== + + /** + * 页码 + */ + 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/WaveDetailInsertDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/WaveDetailInsertDto.java new file mode 100644 index 0000000..2472a87 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/WaveDetailInsertDto.java @@ -0,0 +1,39 @@ +package org.dromara.zhishu.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +import java.util.Date; + +@Data +@Schema(description = "波次明细插入DTO") +public class WaveDetailInsertDto { + /** + * ISBN 号码 + * 示例: "9787111636628" + */ + @NotBlank(message = "ISBN不能为空") + @Schema(description = "ISBN号码", example = "9787111636628") + private String isbn; + + /** + * 扫描时间字符串 + * 格式: "yyyy/MM/dd HH:mm" + * 示例: "2024/01/15 14:30" + */ + @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; + + /** + * 转换后的时间对象 + * (可选,根据业务需要) + */ + @Schema(description = "转换后的扫描时间对象") + private Date scanTime; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/parcelInformationDto.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/parcelInformationDto.java new file mode 100644 index 0000000..593d0db --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/parcelInformationDto.java @@ -0,0 +1,30 @@ +package org.dromara.zhishu.domain.dto; + +import lombok.Data; + +/** + * 包裹信息 + */ +@Data +public class parcelInformationDto { + + /** + * 类型 + */ + private String type; + + /** + * 信息名称 + */ + private String name; + + /** + * 是否启用 0 否 1 是 + */ + private String isBol; + + /** + * 排序 + */ + private String sort; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/CalculatePriceByTemplateRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/CalculatePriceByTemplateRequest.java new file mode 100644 index 0000000..84ec249 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/CalculatePriceByTemplateRequest.java @@ -0,0 +1,22 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CalculatePriceByTemplateRequest { + + /** + * 平台商品Id + */ + private String platformId; + + /** + * 计算前价格 + */ + private Long price; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/DeleteSaleOutGoodsBatchRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/DeleteSaleOutGoodsBatchRequest.java new file mode 100644 index 0000000..ffd89d5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/DeleteSaleOutGoodsBatchRequest.java @@ -0,0 +1,22 @@ +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 java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeleteSaleOutGoodsBatchRequest { + + @NotBlank(message = "token不能为空") + private String token; + + @NotEmpty(message = "goodsIds不能为空") + private List goodsIds; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpBaseShopPageGetRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpBaseShopPageGetRequest.java new file mode 100644 index 0000000..060dbd6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpBaseShopPageGetRequest.java @@ -0,0 +1,45 @@ +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 ErpBaseShopPageGetRequest { + + // 每页大小,最大50 + private Integer limit = 1; + + // 当前页码,从1开始 + private Integer page = 20; + + // 店铺昵称 + @JsonProperty("shop_nick") + private String shopNick; + + // 店铺类型 + @JsonProperty("shop_type") + private Integer shopType; + + // 扩展查询条件 + @JsonProperty("shop_ext") + private ShopExt shopExt; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ShopExt { + + // 修改时间 + @JsonProperty("modify_time") + private String modifyTime; + + // 店铺状态 0 禁用; 1 启用 + private Integer status; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpGoodsUpdateItemRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpGoodsUpdateItemRequest.java new file mode 100644 index 0000000..d98c78f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ErpGoodsUpdateItemRequest.java @@ -0,0 +1,38 @@ +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 ErpGoodsUpdateItemRequest { + + // 商品编码(不能为空) + @JsonProperty("item_code") + private String itemCode; + + // 商品名称(不能为空) + @JsonProperty("item_name") + private String itemName; + + // expiration必须在1-10000之间(不能为空) + private String expiration; + + // 规格集 + private Sku skus; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Sku { + + // 规格编码(不能为空) + @JsonProperty("spec_code") + private String specCode; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsComparisonRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsComparisonRequest.java new file mode 100644 index 0000000..099261e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/GoodsComparisonRequest.java @@ -0,0 +1,22 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GoodsComparisonRequest { + + private Long shopId; + + private Long userId; + + private String currentDateTime; + + private List zhishuShopGoodsRequestList; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ImageProcessingRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ImageProcessingRequest.java new file mode 100644 index 0000000..ab860f2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/ImageProcessingRequest.java @@ -0,0 +1,14 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.Data; + +@Data +public class ImageProcessingRequest { + private String imageUrl; + private String goodsName; + private String isbn; + private String isKW; + private String autoUpload; + private String imageData; // Base64编码的图片数据 + private String fileName; // 文件名 +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OperatingSoldOutRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OperatingSoldOutRequest.java new file mode 100644 index 0000000..7e23e61 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OperatingSoldOutRequest.java @@ -0,0 +1,61 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.zhishu.domain.vo.OperatingInventoryVo; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OperatingSoldOutRequest { + + /** + * 平台类型:1 拼多多 2-孔夫子 + */ + private Integer platformType; + + /** + * 日志类型:1-上架 2-下架 + */ + private Integer logType; + + /** + * 操作类型:1-发布任务 2-订单 + */ + private Integer operationType; + + /** + * 三方平台订单编号 + */ + private String orderSn; + + /** + * 平台店铺Id + */ + private Long mallId; + + /** + * 商品信息列表 + */ + private List goodsItems; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class GoodsItem { + + /** + * 平台商品Id + */ + private String platformId; + + /** + * 商品数量 + */ + private Integer count; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryKWRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryKWRequest.java new file mode 100644 index 0000000..6a897b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderDeliveryKWRequest.java @@ -0,0 +1,33 @@ +package org.dromara.zhishu.domain.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrderDeliveryKWRequest { + + // 店铺ID + private Long shopId; + + // 订单ID + private Long orderId; + + // 配送方式ID + private String shippingId; + + // 配送公司 + private String shippingCom; + + // 运单号 + private String shipmentNum; + + // 自定义 + private String userDefined; + + // 多个运单号 + private String moreShipmentNum; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderListByShopIdRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderListByShopIdRequest.java new file mode 100644 index 0000000..ab07b26 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/OrderListByShopIdRequest.java @@ -0,0 +1,19 @@ +package org.dromara.zhishu.domain.dto.request; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrderListByShopIdRequest { + + private Long shopId; + + private List orderSnList; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/SoldOutRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/SoldOutRequest.java new file mode 100644 index 0000000..327db40 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/SoldOutRequest.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 SoldOutRequest { + + private String token; + + private String itemId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateArtNoRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateArtNoRequest.java new file mode 100644 index 0000000..59809f0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateArtNoRequest.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.domain.dto.request; + + +public class UpdateArtNoRequest { + + // 店铺Id + private Long shopId; + + // 商品编号 + private Long productId; + + // 货号 + private String artNo; + + public Long getShopId() { + return shopId; + } + + public void setShopId(Long shopId) { + this.shopId = shopId; + } + + public Long getProductId() { + return productId; + } + + public void setProductId(Long productId) { + this.productId = productId; + } + + public String getArtNo() { + return artNo; + } + + public void setArtNo(String artNo) { + this.artNo = artNo; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateShopGoodsDataPriceCSVRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateShopGoodsDataPriceCSVRequest.java new file mode 100644 index 0000000..66bf1e8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateShopGoodsDataPriceCSVRequest.java @@ -0,0 +1,59 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +public class UpdateShopGoodsDataPriceCSVRequest { + + /** + * 平台店铺id + */ + @NotNull(message = "平台店铺id不能为空") + private Long mallId; + + /** + * 上架状态 + */ + private Integer isOnSale; + + /** + * 商品信息 + */ + @NotEmpty(message = "商品信息不能为空") + private List skuItemList; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class SkuItem{ + + /** + * 平台商品id + */ + @NotNull(message = "平台商品id不能为空") + private Long platformId; + + /** + * skuId + */ + private Long skuId; + + /** + * 单品价格 + */ + private Long singlePrice; + + /** + * 团购价格 + */ + private Long groupPrice; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateShopGoodsPriceRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateShopGoodsPriceRequest.java new file mode 100644 index 0000000..2a7e681 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateShopGoodsPriceRequest.java @@ -0,0 +1,52 @@ +package org.dromara.zhishu.domain.dto.request; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UpdateShopGoodsPriceRequest { + + /** + * 操作类型 0-下架 1.改价 + */ + private Integer type; + + /** + * 店铺ID + */ + private Long shopId; + + /** + * 商品信息 + */ + private List items; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Item { + + /** + * 平台商品id + */ + private Long platformId; + + /** + * 平台商品skuId + */ + private Long skuId; + + /** + * 价格(分) + */ + private String price; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateTokenRequest.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateTokenRequest.java new file mode 100644 index 0000000..09a15c7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/request/UpdateTokenRequest.java @@ -0,0 +1,56 @@ +package org.dromara.zhishu.domain.dto.request; + +import java.util.Date; + +public class UpdateTokenRequest { + + private Long shopId; + + private String shopType; + + private String accessToken; + + private String refreshToken; + + private Date expirationTime; + + public Long getShopId() { + return shopId; + } + + public void setShopId(Long shopId) { + this.shopId = shopId; + } + + public String getShopType() { + return shopType; + } + + public void setShopType(String shopType) { + this.shopType = shopType; + } + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public String getRefreshToken() { + return refreshToken; + } + + public void setRefreshToken(String refreshToken) { + this.refreshToken = refreshToken; + } + + public Date getExpirationTime() { + return expirationTime; + } + + public void setExpirationTime(Date expirationTime) { + this.expirationTime = expirationTime; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/AddTaskLogResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/AddTaskLogResponse.java new file mode 100644 index 0000000..ca4c647 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/AddTaskLogResponse.java @@ -0,0 +1,18 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AddTaskLogResponse { + + private String elapsed; + + private String status; + + private String taskId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/CalculatePriceByTemplateResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/CalculatePriceByTemplateResponse.java new file mode 100644 index 0000000..1c7d3e1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/CalculatePriceByTemplateResponse.java @@ -0,0 +1,34 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CalculatePriceByTemplateResponse { + + /** + * 平台商品Id + */ + private String platformId; + + /** + * 计算前价格 + */ + private Long price; + + /** + * 计算后单品价格 + */ + private Long singlePrice; + + /** + * 计算后团购价格 + */ + private Long groupPrice; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ErpBaseShopPageGetResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ErpBaseShopPageGetResponse.java new file mode 100644 index 0000000..e830192 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ErpBaseShopPageGetResponse.java @@ -0,0 +1,42 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ErpBaseShopPageGetResponse { + + // 手机号 + private String cellphone; + + // 万里牛公司ID + private String comUid; + + // 联系人 + private String contacts; + + // 修改时间, 13位时间戳 + private String modifyTime; + + // 电话 + private String phone; + + // 万里牛店铺名称 + private String shopName; + + // 万里牛系统ID + private String shopNick; + + // 店铺类型 详情见接口(/base/shop/list/shopTypes) + private Integer shopType; + + // 万里牛系统UID + private String shopUid; + + // 店铺状态 0 停用 1 启用 + private Integer status; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ErpGoodsQueryOlnGoodsResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ErpGoodsQueryOlnGoodsResponse.java new file mode 100644 index 0000000..23a6d0e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/ErpGoodsQueryOlnGoodsResponse.java @@ -0,0 +1,81 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ErpGoodsQueryOlnGoodsResponse { + + // 总数 + private Integer total; + + // 是否存在下一页 + private Boolean next; + + // 分页号 + private Integer pageNo; + + // 分页大小 + private Integer pageSize; + + private List elements; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Element { + + // 线上商品ID + private String itemId; + + // 宝贝标题 + private String title; + + // 商家编码 + private String outerId; + + // 修改时间,13位时间戳 + private String modified; + + // 图片 + private String pic; + + // 链接地址 + private String url; + + // 宝贝状态 1:在售 0:已下架 + private Integer status; + + // 规格信息 + private List skus; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Sku { + + // 线上商品ID + private String itemId; + + // 规格名称 + private String name; + + // 商家规格编码 + private String outerId; + + // 图片 + private String pic; + + // 线上规格ID + private String skuId; + + } + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetBookByISBNResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetBookByISBNResponse.java new file mode 100644 index 0000000..bbb8e67 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetBookByISBNResponse.java @@ -0,0 +1,106 @@ +package org.dromara.zhishu.domain.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GetBookByISBNResponse { + + /** + * 错误信息 + */ + private String error; + + /** + * 数据 + */ + private BookItem data; + + /** + * 源 + */ + private String source; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class BookItem { + + /** + * 作者 + */ + private String author; + + /** + * 书名 + */ + @JsonProperty("book_name") + private String bookName; + + /** + * 官图 + */ + @JsonProperty("book_pic") + private String bookPic; + + /** + * 实拍图 + */ + @JsonProperty("book_pic_s") + private String bookPicS; + + /** + * bookSet + */ + @JsonProperty("book_set") + private Integer bookSet; + + /** + * buyCount + */ + @JsonProperty("buy_count") + private String buyCount; + + /** + * buyCounts + */ + @JsonProperty("buy_counts") + private Integer buyCounts; + + /** + * catId + */ + @JsonProperty("cat_id") + private Integer catId; + + /** + * 分类 + */ + @JsonProperty("category") + private String category; + + /** + * 内容 + */ + @JsonProperty("content") + private String content; + + /** + * 创建人 + */ + @JsonProperty("create_by") + private Long createBy; + + /** + * 创建时间(秒级) + */ + @JsonProperty("create_time") + private Long createTime; + + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetShopGoodsListResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetShopGoodsListResponse.java new file mode 100644 index 0000000..6bcf217 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetShopGoodsListResponse.java @@ -0,0 +1,437 @@ +package org.dromara.zhishu.domain.dto.response; + +import java.util.List; + +public class GetShopGoodsListResponse { + + private List list; + + // 每页最大条数 + private Integer pageSize; + + // 当前页码 + private Integer pageNum; + + // 总记录数 + private Integer total; + + // 总页数 + private Integer pages; + + // 当前页记录数 + private Integer size; + + public static class ShopGoods { + + // 商品添加时间戳 + private Long addTime; + + // 是否草稿。0:不是草稿;1:是草稿 + private Integer isDraft; + + // 折扣。取值10~100,50表示:5折,75表示:75折 + private Integer discount; + + // 年代对应编号 + private Long years; + + // 库存 + private Integer number; + + // 商品名称 + private String itemName; + + // 商品所在地对应编号 + private Long productArea; + + // 商品价格 + private Long price; + + // 店铺分类编号 + private Long myCatId; + + // 出版社 + private String press; + + // 出运费方。buyer:买家承担运费;seller:卖家包邮 + private String bearShipping; + + // 作者 + private String author; + + // 商品重量 + private Double weight; + + // 出版时间 + private String pubDate; + + // 品相。95表示:九五品 + private Integer quality; + + // 商品编号 + private Long itemId; + + // 分类编号 + private Long catId; + + // 店铺类型。1:书店;2:书摊 + private Integer bizType; + + // 审核状态。notCertified:待审核;certified:审核通过;frozen:冻结;failed:驳回;waitApproved:等待复审 + private String certifyStatus; + + // ISBN书号 + private String isbn; + + // 标准本数量 + private Integer weightPiece; + + // 运费模板编号 + private Long mouldId; + + // 关联图书库编号 + private Long booklibId; + + // 上下架状态 + private Integer isOnSale; + + // 删除状态 + private Integer isDelete; + + // 商品更新时间 + private String updateTime; + + // 商品下架时间戳 + private Long endSaleTime; + + // 卖家用户编号 + private Long userId; + + // 商品图片路径 + private String imgUrl; + + // 商品原价 + private Long oriPrice; + + // 商品货号 + private String itemSn; + + // 商品上架时间戳 + private Long beginSaleTime; + + // 是否全新图书 + private Integer isNewBook; + + public Long getAddTime() { + return addTime; + } + + public void setAddTime(Long addTime) { + this.addTime = addTime; + } + + public Integer getIsDraft() { + return isDraft; + } + + public void setIsDraft(Integer isDraft) { + this.isDraft = isDraft; + } + + public Integer getDiscount() { + return discount; + } + + public void setDiscount(Integer discount) { + this.discount = discount; + } + + public Long getYears() { + return years; + } + + public void setYears(Long years) { + this.years = years; + } + + public Integer getNumber() { + return number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public String getItemName() { + return itemName; + } + + public void setItemName(String itemName) { + this.itemName = itemName; + } + + public Long getProductArea() { + return productArea; + } + + public void setProductArea(Long productArea) { + this.productArea = productArea; + } + + public Long getPrice() { + return price; + } + + public void setPrice(Long price) { + this.price = price; + } + + public Long getMyCatId() { + return myCatId; + } + + public void setMyCatId(Long myCatId) { + this.myCatId = myCatId; + } + + public String getPress() { + return press; + } + + public void setPress(String press) { + this.press = press; + } + + public String getBearShipping() { + return bearShipping; + } + + public void setBearShipping(String bearShipping) { + this.bearShipping = bearShipping; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Double getWeight() { + return weight; + } + + public void setWeight(Double weight) { + this.weight = weight; + } + + public String getPubDate() { + return pubDate; + } + + public void setPubDate(String pubDate) { + this.pubDate = pubDate; + } + + public Integer getQuality() { + return quality; + } + + public void setQuality(Integer quality) { + this.quality = quality; + } + + public Long getItemId() { + return itemId; + } + + public void setItemId(Long itemId) { + this.itemId = itemId; + } + + public Long getCatId() { + return catId; + } + + public void setCatId(Long catId) { + this.catId = catId; + } + + public Integer getBizType() { + return bizType; + } + + public void setBizType(Integer bizType) { + this.bizType = bizType; + } + + public String getCertifyStatus() { + return certifyStatus; + } + + public void setCertifyStatus(String certifyStatus) { + this.certifyStatus = certifyStatus; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public Integer getWeightPiece() { + return weightPiece; + } + + public void setWeightPiece(Integer weightPiece) { + this.weightPiece = weightPiece; + } + + public Long getMouldId() { + return mouldId; + } + + public void setMouldId(Long mouldId) { + this.mouldId = mouldId; + } + + public Long getBooklibId() { + return booklibId; + } + + public void setBooklibId(Long booklibId) { + this.booklibId = booklibId; + } + + public Integer getIsOnSale() { + return isOnSale; + } + + public void setIsOnSale(Integer isOnSale) { + this.isOnSale = isOnSale; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public Long getEndSaleTime() { + return endSaleTime; + } + + public void setEndSaleTime(Long endSaleTime) { + this.endSaleTime = endSaleTime; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getImgUrl() { + return imgUrl; + } + + public void setImgUrl(String imgUrl) { + this.imgUrl = imgUrl; + } + + public Long getOriPrice() { + return oriPrice; + } + + public void setOriPrice(Long oriPrice) { + this.oriPrice = oriPrice; + } + + public String getItemSn() { + return itemSn; + } + + public void setItemSn(String itemSn) { + this.itemSn = itemSn; + } + + public Long getBeginSaleTime() { + return beginSaleTime; + } + + public void setBeginSaleTime(Long beginSaleTime) { + this.beginSaleTime = beginSaleTime; + } + + public Integer getIsNewBook() { + return isNewBook; + } + + public void setIsNewBook(Integer isNewBook) { + this.isNewBook = isNewBook; + } + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public Integer getPageSize() { + return pageSize; + } + + public void setPageSize(Integer pageSize) { + this.pageSize = pageSize; + } + + public Integer getPageNum() { + return pageNum; + } + + public void setPageNum(Integer pageNum) { + this.pageNum = pageNum; + } + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public Integer getPages() { + return pages; + } + + public void setPages(Integer pages) { + this.pages = pages; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetWlnShopListResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetWlnShopListResponse.java new file mode 100644 index 0000000..3bb7e5d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/GetWlnShopListResponse.java @@ -0,0 +1,19 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GetWlnShopListResponse { + + // 万里牛店铺名称 + public String shopName; + + + // 万里牛系统ID + public String shopNick; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/LogisticsMethodResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/LogisticsMethodResponse.java new file mode 100644 index 0000000..3f03053 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/LogisticsMethodResponse.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 物流方式 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class LogisticsMethodResponse { + + // 物流方式Id + private String methodId; + + // 物流方式名称 + private String methodName; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/PddTokenResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/PddTokenResponse.java new file mode 100644 index 0000000..590ae92 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/PddTokenResponse.java @@ -0,0 +1,13 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.Data; + +@Data +public class PddTokenResponse { + private String accessToken; + private String pddMallId; + private String pddMallName; + private String skuSpec; + private String msg; + private String code; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/UpdateSkuPriceResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/UpdateSkuPriceResponse.java new file mode 100644 index 0000000..18e21dd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/UpdateSkuPriceResponse.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 UpdateSkuPriceResponse { + + /** + * 平台商品Id + */ + private Long platformId; + + /** + * 信息 + */ + private String msg; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/WlnBaseResponse.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/WlnBaseResponse.java new file mode 100644 index 0000000..0331cb8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/dto/response/WlnBaseResponse.java @@ -0,0 +1,18 @@ +package org.dromara.zhishu.domain.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WlnBaseResponse { + + private Integer code; + + private T data; + + private String message; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/AuthorPressVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/AuthorPressVo.java new file mode 100644 index 0000000..e5a3309 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/AuthorPressVo.java @@ -0,0 +1,9 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; + +@Data +public class AuthorPressVo { + private String author; // 作者 + private String press; // 出版社 +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BaseInfoPricingVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BaseInfoPricingVo.java new file mode 100644 index 0000000..1c96154 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BaseInfoPricingVo.java @@ -0,0 +1,37 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BaseInfoPricingVo implements Serializable { + /** + * 书名 + */ + private String bookName; + /** + * isbn + */ + private String isbn; + /** + * 价格 + */ + private String originalPrice; + /** + * 是否套装书 + */ + private Integer IsBookSet; + /** + * 出版社 + */ + private String publisher; + /** + * 作者 + */ + private String author; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditPriceVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditPriceVo.java new file mode 100644 index 0000000..62fdf90 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditPriceVo.java @@ -0,0 +1,36 @@ +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 jakarta.persistence.ColumnResult; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BookEditPriceVo.class) +public class BookEditPriceVo 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 = "价格(必填)") + @ColumnWidth(25) + private String price; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditStockVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditStockVo.java new file mode 100644 index 0000000..fa6b180 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookEditStockVo.java @@ -0,0 +1,34 @@ +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 java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BookEditStockVo.class) +public class BookEditStockVo 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 = "库存(必填)") + private String stock; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookPic.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookPic.java new file mode 100644 index 0000000..0450b09 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookPic.java @@ -0,0 +1,29 @@ +package org.dromara.zhishu.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 书籍图片对象 + */ +@Data +public class BookPic { + + /** + * 本地路径 + */ + @JsonProperty("localPath") + private String localPath; + + /** + * 拼多多路径 + */ + @JsonProperty("pddPath") + private String pddPath; + + /** + * 拼多多响应路径 + */ + @JsonProperty("pddResponse") + private String pddResponse; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookVo.java new file mode 100644 index 0000000..f068076 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/BookVo.java @@ -0,0 +1,42 @@ +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.BookBaseInfo; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = BookVo.class) +public class BookVo 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/DepotOrderVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DepotOrderVo.java new file mode 100644 index 0000000..dd78ba6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DepotOrderVo.java @@ -0,0 +1,448 @@ +package org.dromara.zhishu.domain.vo; + +import com.baomidou.mybatisplus.annotation.TableLogic; +import org.dromara.zhishu.domain.DepotOrder; +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_depot_order + * + * @author yxy + * @date 2025-06-03 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = DepotOrder.class) +public class DepotOrderVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 店铺订单id + */ + @ExcelProperty(value = "店铺订单id") + private String shopOrderId; + + /** + * 处理人 + */ + @ExcelProperty(value = "处理人") + private Long userId; + + private String userName; + + /** + * 商品信息 + */ + @ExcelProperty(value = "商品信息") + private String itemList; + + /** + * 仓库订单状态 0 待发货 1 已发货 2 无库存 3 转发任务 + */ + @ExcelProperty(value = "仓库订单状态 0 待发货 1 已发货 2 无库存 3 转发任务") + private String status; + + /** + * 创建者 + */ + @ExcelProperty(value = "创建者") + private Long createBy; + + private String createName; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 查询总数 + */ + private String total; + + + /** + * 订单相关信息内容-------------------------- + */ + + /** + * 三方平台订单编号 + */ + 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代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 租户编码 + */ + @TableLogic + private String tenantId; + + + /** + * 商品列表 + */ + private List orderItemList; + + /** + * 额外附属信息 + */ + private String extraInfo; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DistrictsVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DistrictsVo.java new file mode 100644 index 0000000..3cbac29 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/DistrictsVo.java @@ -0,0 +1,42 @@ +package org.dromara.zhishu.domain.vo; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 地区响应体 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DistrictsVo { + + /** + * label:区划名称 + */ + private String label; + + /** + * value:区划名称 + */ + private String value; + + /** + * 区划ID + */ + private String id; + + /** + * 下级区划信息 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + private List children; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/EmployeeInfoVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/EmployeeInfoVo.java new file mode 100644 index 0000000..aa5737b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/EmployeeInfoVo.java @@ -0,0 +1,78 @@ +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; + +/** + * 员工信息视图对象 employeeInfo + * + * @author Lion Li + * @date 2026-03-04 + */ +@Data +@ExcelIgnoreUnannotated +public class EmployeeInfoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 表主键 + */ + @ExcelProperty(value = "员工ID") + private Long id; + + /** + * 员工ID + */ + @ExcelProperty(value = "员工ID") + private String employeeId; + + /** + * 员工姓名 + */ + @ExcelProperty(value = "员工姓名") + private String name; + + /** + * 所属用户id + */ + @ExcelProperty(value = "所属用户id") + private Long userId; + + /** + * 工作波次 + */ + @ExcelProperty(value = "工作波次") + private String wave; + + /** + * 波次内工作数量 + */ + @ExcelProperty(value = "波次内工作数量") + private Integer count; + + /** + * 创建时间(秒级时间戳) + */ + @ExcelProperty(value = "创建时间") + private Long createdTime; + + /** + * 更新时间(秒级时间戳) + */ + @ExcelProperty(value = "更新时间") + private Long updatedTime; + + /** + * 删除标志 + */ + @ExcelProperty(value = "删除标志") + private Integer delFlag; + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/EmployeeVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/EmployeeVo.java new file mode 100644 index 0000000..99a472b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/EmployeeVo.java @@ -0,0 +1,53 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.zhishu.domain.Employee; +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Employee.class) +public class EmployeeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 表主键(员工ID) + */ + private String id; + + /** + * 员工姓名 + */ + private String name; + + /** + * 所属用户id + */ + private Long userId; + + /** + * 创建时间 + */ + private Long creatTime; + + /** + * 更新时间 + */ + private Long updateTime; + + /** + * 删除标志 + */ + private Integer delFlag; + + /** + * 用户昵称 + */ + private String nickName; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ExcelTaskVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ExcelTaskVo.java new file mode 100644 index 0000000..4e2a056 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ExcelTaskVo.java @@ -0,0 +1,90 @@ +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.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.zhishu.domain.ExcelTask; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + +/** + * 任务列表视图对象 t_task_list + * + * @author yxy + * @date 2025-03-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ExcelTask.class) +public class ExcelTaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 任务类型 1 发布商品 + */ + @ExcelProperty(value = "任务类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_task_type") + private String taskType; + + /** + * 店铺id 字符串 + */ + @ExcelProperty(value = "仓库id") + private String depotIds; + + /** + * 文件名称 + */ + @ExcelProperty(value = "文件名称") + private String fileName; + + /** + * 执行数据条数 + */ + @ExcelProperty(value = "执行数据条数") + private Long dataNum; + + /** + * 任务状态 + */ + @ExcelProperty(value = "任务状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_task_status") + private String taskStatus; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 线程id + */ + private Long threadId; + + /** + * 用户id + */ + private Long userId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FastMailVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FastMailVo.java new file mode 100644 index 0000000..d48909f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FastMailVo.java @@ -0,0 +1,98 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.FastMail; +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_fast_mail + * + * @author yxy + * @date 2025-06-06 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FastMail.class) +public class FastMailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 类型 1 韵达 + */ + @ExcelProperty(value = "类型 1 韵达", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_device_type") + private String type; + + /** + * 账号 + */ + @ExcelProperty(value = "账号") + private String partnerId; + + /** + * 联调密码 + */ + @ExcelProperty(value = "联调密码") + private String secret; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 普通快递余额 + */ + private String commonRemainNum; + + /** + * 代付快递余额 + */ + private String codRemainNum; + + /** + * 面单类型 1 网点面单 2 拼多多面单 + */ + private String fastMailType; + + /** + * 备注 + */ + private String remark; + + private String createBy; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilesVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilesVo.java new file mode 100644 index 0000000..f012518 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilesVo.java @@ -0,0 +1,11 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; + +@Data +public class FilesVo { + private String bookName; + private String originalUrl; + private String url; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilterSetVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilterSetVo.java new file mode 100644 index 0000000..e6b5f3b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/FilterSetVo.java @@ -0,0 +1,84 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.FilterSet; +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_filter_set + * + * @author yxy + * @date 2025-04-14 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = FilterSet.class) +public class FilterSetVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 过滤类型 + */ + @ExcelProperty(value = "过滤类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_filter_type") + private String filterType; + + /** + * 限制类型 + */ + @ExcelProperty(value = "限制类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_shop_set_up") + private String limitationType; + + /** + * 添加方式 + */ + @ExcelProperty(value = "添加方式", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_add_way") + private String addWay; + + /** + * 内容文件 + */ + @ExcelProperty(value = "内容文件") + private String addTxt; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + + /** + * 分类 + */ + private String sort; + + private Date createTime; + + /** + * 加入原因 + */ + private String reason; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsAutoFailVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsAutoFailVo.java new file mode 100644 index 0000000..856cef8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsAutoFailVo.java @@ -0,0 +1,90 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.GoodsAutoFail; +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_goods_auto_fail + * + * @author yxy + * @date 2025-09-29 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = GoodsAutoFail.class) +public class GoodsAutoFailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + private String shopName; + + /** + * 商品id + */ + private Long goodsId; + + private String goodsName; + + /** + * 商品isbn + */ + private String isbn; + + /** + * 货号 + */ + private String artNo; + + /** + * 日志 + */ + private String callBackData; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 价格 单位分 + */ + private Long price; + + /** + * 库存 + */ + private String inventory; + + /** + * 品相 + */ + private String conditionCode; + + /** + * 首费 单位元 + */ + private String firPrice; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemKfzVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemKfzVo.java new file mode 100644 index 0000000..884d31d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/GoodsItemKfzVo.java @@ -0,0 +1,42 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GoodsItemKfzVo { + + private Long itemId; // 商品编号 + + private String itemSn; // 商品货号 + + private Integer number; // 购买数量 + + private String itemName; // 商品名称 + + private String img; // 商品图片URL + + private Boolean isCancel; // 是否被取消 + + private Long orderId; // 所属订单编号 + + private String price; // 商品价格 + + private String favorableAmount; // 商品总优惠金额 + + private String setFavAmount; // 卖家设置优惠金额 + + private String couponFavAmount; // 优惠券优惠金额 + + private String realAmount; // 商品实付金额 + + private String cancelMan; // 取消者:unkown/seller/buyer + + private String quality; // 商品品相 + + private String isbn; // 图书ISBN + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/InviteCodeVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/InviteCodeVo.java new file mode 100644 index 0000000..3775daa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/InviteCodeVo.java @@ -0,0 +1,54 @@ +package org.dromara.zhishu.domain.vo; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.io.Serializable; +import java.util.Date; + +/** + * 邀请码视图对象 + */ +@Data +@NoArgsConstructor +@TableName("t_invite_codes") +public class InviteCodeVo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 邀请人ID + */ + private Long userId; + + /** + * 邀请码 + */ + private String code; + + /** + * 邀请链接 + */ + private String inviteUrl; + + /** + * 过期时间 + */ + private Date expireTime; + + /** + * 是否已使用 + */ + private Boolean used; + + /** + * 创建时间 + */ + 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/vo/ItemListVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ItemListVo.java new file mode 100644 index 0000000..e43a69f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ItemListVo.java @@ -0,0 +1,29 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ItemListVo { + + private List orderItems; + + private List itemList; + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ExceptionItem { + + private String orderExceptionType; + + private List orderItemIds; + + } + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/KongfzVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/KongfzVo.java new file mode 100644 index 0000000..a955c6a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/KongfzVo.java @@ -0,0 +1,29 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; + +import java.math.BigDecimal; +@Data +public class KongfzVo extends ZhishuShopGoodsBo { + private static final long serialVersionUID = 1L; + private String id; + private String name; + private String barcode; + private Long price;//价格 + private String priceText; + private Long stock;//库存 + private String conditionCode;//品相 + private String warehouseCode; + private String imgUrl; + private String author; + private String press; + private String isbn; + private String shopName; + private String imgBigUrl; + private BigDecimal shippingFee; + //快递费 + private String shippingFeeText; + //品相 + private String qualityText; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/LogisticsVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/LogisticsVo.java new file mode 100644 index 0000000..80def45 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/LogisticsVo.java @@ -0,0 +1,111 @@ +package org.dromara.zhishu.domain.vo; + + +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; + +/** + * 物流模板对象 t_logistics + * + * @author ruoyi + * @date 2023-07-04 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("t_logistics") +public class LogisticsVo extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + *id + */ + @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 Double firWbv; + + /** + * 首费 单位:元 + */ + private Double firPrice; + + /** + * 续重 续本 续件 + */ + private Double continueWbv; + + /** + * 续费 单位:元 + */ + private Double continuePrice; + + /** + * 模板状态(0正常 1停用) + */ + private String status; + + /** + * 租户编码 + */ + private String tenantId; + + /** + * 运送范围 + */ + private String shippingRange; + + /** + * 仓库ID + */ + private Long warehouseId; + /** + * 配送说明 + */ + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/NewUserVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/NewUserVo.java new file mode 100644 index 0000000..f0bb34f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/NewUserVo.java @@ -0,0 +1,66 @@ +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.NewUserInfo; + + +import java.io.Serial; +import java.io.Serializable; + + + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = NewUserInfo.class) +public class NewUserVo{ + /** + * + */ + private Long id; + + /** + * 企业名称 + */ + @ExcelProperty(value = "仓库id") + private String companyName; + + /** + * 企业类型 + */ + @ExcelProperty(value = "仓库id") + private String companyType ; + + /** + * 联系人名 + */ + @ExcelProperty(value = "仓库id") + private String contactPerson; + + /** + * 联系方式 + */ + @ExcelProperty(value = "仓库id") + private String contactPhone;; + + /** + * 邮箱 + */ + @ExcelProperty(value = "仓库id") + private String email; + + /** + * 营业执照 + */ + @ExcelProperty(value = "仓库id") + private String license; + + /** + * 备注 + */ + @ExcelProperty(value = "仓库id") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/OperatingInventoryVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/OperatingInventoryVo.java new file mode 100644 index 0000000..d163cd9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/OperatingInventoryVo.java @@ -0,0 +1,103 @@ +package org.dromara.zhishu.domain.vo; + +import java.util.List; + +/** + * 库存操作Vo + */ +public class OperatingInventoryVo { + + /** + * 操作类型 1:增加库存 2:减少库存 + */ + private Integer operationType; + + /** + * 店铺类型 1:拼多多 2:孔夫子 + */ + private Integer shopType; + + /** + * 三方平台订单编号 + */ + private String orderSn; + + /** + * 平台店铺Id + */ + private Long mallId; + + /** + * 商品信息列表 + */ + private List goodsItems; + + public static class GoodsItem { + + /** + * 平台商品Id + */ + private String platformId; + + /** + * 商品数量 + */ + private Integer count; + + public String getPlatformId() { + return platformId; + } + + public void setPlatformId(String platformId) { + this.platformId = platformId; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + } + + public Integer getOperationType() { + return operationType; + } + + public void setOperationType(Integer operationType) { + this.operationType = operationType; + } + + public Integer getShopType() { + return shopType; + } + + public void setShopType(Integer shopType) { + this.shopType = shopType; + } + + public Long getMallId() { + return mallId; + } + + public void setMallId(Long mallId) { + this.mallId = mallId; + } + + public List getGoodsItems() { + return goodsItems; + } + + public void setGoodsItems(List goodsItems) { + this.goodsItems = goodsItems; + } + + public String getOrderSn() { + return orderSn; + } + + public void setOrderSn(String orderSn) { + this.orderSn = orderSn; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/OrderItemVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/OrderItemVo.java new file mode 100644 index 0000000..54f488a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/OrderItemVo.java @@ -0,0 +1,37 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrderItemVo { + + /** + * 商品名称 + */ + private String goodsName; + + /** + * 商品图片 + */ + private String goodsImg; + + /** + * 商品价格(元) + */ + private String goodsPrice; + + /** + * 商品数量 + */ + private String goodsCount; + + /** + * 货号 + */ + private String artNo; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PlatformIdUpdateVO.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PlatformIdUpdateVO.java new file mode 100644 index 0000000..28fe469 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PlatformIdUpdateVO.java @@ -0,0 +1,13 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class PlatformIdUpdateVO { + private String oldPlatformId; + private String newPlatformId; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PriceTemplateVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PriceTemplateVo.java new file mode 100644 index 0000000..e450744 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PriceTemplateVo.java @@ -0,0 +1,84 @@ +package org.dromara.zhishu.domain.vo; + +import java.math.BigDecimal; +import org.dromara.zhishu.domain.PriceTemplate; +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_price_template + * + * @author yxy + * @date 2025-03-17 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = PriceTemplate.class) +public class PriceTemplateVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 价格模板名称 + */ + @ExcelProperty(value = "价格模板名称") + private String templateName; + + /** + * 价格类型 0 书价 1 总价(书价+运费) + */ + private String priceType; + + /** + * 增加比例 + */ + @ExcelProperty(value = "增加比例") + private BigDecimal proportion; + + /** + * 增加金额 + */ + @ExcelProperty(value = "增加金额") + private BigDecimal addAmount; + + /** + * 价格模板状态(0正常 1停用) + */ + @ExcelProperty(value = "价格模板状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 价格区间最大值 + */ + private Integer highPrice; + /** + * 价格区间最小值 + */ + private Integer lowPrice; + + /** + * 价格参数 + */ + private String rangePrice; + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PrintTemplateVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PrintTemplateVo.java new file mode 100644 index 0000000..a590854 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PrintTemplateVo.java @@ -0,0 +1,69 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.PrintTemplate; +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_print_template + * + * @author yxy + * @date 2026-03-07 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = PrintTemplate.class) +public class PrintTemplateVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 快递类型 + */ + private String expressType; + + /** + * 模板名称 + */ + @ExcelProperty(value = "模板名称") + private String printTemplateName; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + + /** + * 0正常 1停用 + */ + @ExcelProperty(value = "0正常 1停用") + private String status; + + /** + * 包裹信息json字符串 + */ + private String parcelInformation; + + /** + * 创建人 + */ + private String createBy; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PrinterVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PrinterVo.java new file mode 100644 index 0000000..3cdd64f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/PrinterVo.java @@ -0,0 +1,76 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.Printer; +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_printer + * + * @author yxy + * @date 2026-03-06 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Printer.class) +public class PrinterVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 打印机类型 1 本地打印机 2 拼多多云打印机 + */ + private String printType; + + /** + * 拼多多云打印机共享码 + */ + private String shareCode; + + /** + * 打印机/云打印机编号 + */ + @ExcelProperty(value = "打印机") + private String printer; + + /** + * 打印机名称 + */ + @ExcelProperty(value = "打印机名称") + private String printerName; + + /** + * 是否启用全程打印 + */ + @ExcelProperty(value = "是否启用全程打印") + private String isRemotePrinting; + + /** + * 0正常 1停用 + */ + @ExcelProperty(value = "0正常 1停用") + private String status; + + /** + * 验证码 + */ + private String captcha; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductForm.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductForm.java new file mode 100644 index 0000000..d4309ea --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductForm.java @@ -0,0 +1,137 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; + +import java.io.File; +import java.io.Serial; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.file.Files; +import java.util.List; + + +/** + * 商品信息视图对象 zhishu_shop_goods + * + * @author Lion Li + * @date 2025-03-07 + */ +@Data +public class ProductForm implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + //商品名称 + private String name; + // ISBN + private String barcode; + // 货号 + private String warehouseCode; + //商品定价 + private Long price; + //期初库存 + private Long stock; + //品相 + private String conditionCode; + //货号 + private String artNo; + //库存 + private Long inventory; + //仓库 + private String depotName; + //货架 + private String shelvesName; + //货位 + private String freightName; + //用户Id + private String userName; + //用户密码 + private String passWord; + // 出版时间 + private String publishTime; + /** + * 商品编号 + */ + private String itemNumber; + //租户ID + /** + * 图片 + */ + private List files; + /** + * 手机号 + */ + private String phoneNumber; + /** + * 固定价格 + */ + private Long fixPrice; + /** + * 备注 + */ + private String remark; + /** + * 货号最后一位 A B C D + */ + private String Series; + /** + * 图片 + */ + private String image; + /** + * 数量 + */ + private Long count; + /** + * 模板类型 + */ + private String templateType; + /** + * 作者 + */ + private String author; + /** + * 出版社 + */ + private String publisher; + /** + * 纸张 + */ + private String format; + /** + * 打印时间 + */ + private String printTime; + /** + * 字数 + */ + private String wordage; + /** + * 统一书号 + */ + private String goodUnifyIsbn; + + /** + * 操作人id + */ + private Long userId; + /** + * 分类ID + */ + private Long categoryId; + /** + * 在售数量 + */ + private Long sellCount; + /** + * 已售数量 + */ + private Long buyCount; + /** + * 孔网官图 + */ + private String kfzBookPic; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductSubmitResultVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductSubmitResultVo.java new file mode 100644 index 0000000..9cb5e19 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductSubmitResultVo.java @@ -0,0 +1,50 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 商品提交结果视图对象 + * + * @author system + * @date 2025-01-17 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ProductSubmitResultVo { + + + /** + * 商品ID + */ + private String goodsId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 仓库ID + */ + private Long depotId; + + /** + * 货架ID + */ + private Long shelvesId; + + /** + * 运费模板ID + */ + private Long freightId; + + /** + * 货号 + */ + private String artNo; +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductVo.java new file mode 100644 index 0000000..603487d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ProductVo.java @@ -0,0 +1,34 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 商品信息视图对象 zhishu_shop_goods + * + * @author Lion Li + * @date 2025-03-07 + */ +@Data +public class ProductVo extends ZhishuShopGoodsBo { + + @Serial + private static final long serialVersionUID = 1L; + private String id; + private String name; + private String barcode; + private Long price;//价格 + private Long stock;//库存 + private String conditionCode;//品相 + private String warehouseCode; + private String imgUrl; + private String author; + private String press; + private String imgBigUrl; + //快递费 + private Long shippingFeeText; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningLogFileVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningLogFileVo.java new file mode 100644 index 0000000..0688d06 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningLogFileVo.java @@ -0,0 +1,69 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.RunningLogFile; +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_log_file + * + * @author yxy + * @date 2025-06-12 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = RunningLogFile.class) +public class RunningLogFileVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 文件名称 + */ + @ExcelProperty(value = "文件名称") + private String fileName; + + /** + * 文件顺序 + */ + @ExcelProperty(value = "文件顺序") + private String fileOrder; + + /** + * 文件类型 + */ + @ExcelProperty(value = "文件类型") + private String fileType; + + /** + * 文件大小 + */ + @ExcelProperty(value = "文件大小") + private String fileSize; + + /** + * 状态(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/RunningTaskNumVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningTaskNumVo.java new file mode 100644 index 0000000..eea477d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/RunningTaskNumVo.java @@ -0,0 +1,31 @@ +package org.dromara.zhishu.domain.vo; + + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +public class RunningTaskNumVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + + private Long taskId; + + private Long shopId; + + private String shopName; + + private Integer allNum; + + private String status; + + private String msg; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopDetailVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopDetailVo.java new file mode 100644 index 0000000..0fe4d81 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopDetailVo.java @@ -0,0 +1,361 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.ShopDetail; +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_detail + * + * @author yxy + * @date 2025-03-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ShopDetail.class) +public class ShopDetailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 店铺id + */ + @ExcelProperty(value = "店铺id") + private Long shopId; + + /** + * 物流运费模板id + */ + @ExcelProperty(value = "物流运费模板id") + private Long templateId; + + /** + * 高价 + */ + @ExcelProperty(value = "高价") + private Long highPrice; + + /** + * 低价 + */ + @ExcelProperty(value = "低价") + private Long lowPrice; + + /** + * 销售模板id + */ + @ExcelProperty(value = "销售模板id") + private Long saleTemplateId; + + /** + * 是否开启7天无理由 0关闭 1开启 + */ + @ExcelProperty(value = "是否开启7天无理由 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String sevenDays; + + /** + * 是否开始二手 0关闭 1开启 + */ + @ExcelProperty(value = "是否开始二手 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String isSecondHand; + + /** + * 轮播数量开启 0关闭 1开启 + */ + @ExcelProperty(value = "轮播数量开启 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String carouselNum; + + /** + * 是否开启详情图 0关闭 1开启 + */ + @ExcelProperty(value = "是否开启详情图 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String isDetailsImg; + + /** + * 是否开启目录详情 0关闭 1开启 + */ + @ExcelProperty(value = "是否开启目录详情 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String isCatalogueDetails; + + /** + * 是否开启信息图片 0关闭 1开启 + */ + @ExcelProperty(value = "是否开启信息图片 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String isInformationImg; + + /** + * 标题前缀 + */ + @ExcelProperty(value = "标题前缀") + private String titlePrefix; + + /** + * 标题后缀 + */ + @ExcelProperty(value = "标题后缀") + private String titleSuffix; + + /** + * 标题过滤 + */ + @ExcelProperty(value = "标题过滤") + private String titleFilter; + + /** + * 货号前缀 + */ + @ExcelProperty(value = "货号前缀") + private String itemNumberPrefix; + + /** + * 标题组成 + */ + @ExcelProperty(value = "标题组成") + private String titleConsistOf; + + /** + * 间隔字符 0无间隔 1空格 + */ + @ExcelProperty(value = "间隔字符 0无间隔 1空格", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_space_character") + private String spaceCharacter; + + /** + * 是否开启自动截断 0关闭 1开启 + */ + @ExcelProperty(value = "是否开启自动截断 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String autoTruncation; + + /** + * 我的设置 + */ + @ExcelProperty(value = "我的设置") + private String mySetUp; + + /** + * 系统设置 + */ + @ExcelProperty(value = "系统设置") + private String systemSetUp; + + /** + * 过滤套装 0否 1是 + */ + @ExcelProperty(value = "过滤套装 0否 1是", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_yes_no") + private String filterSuit; + + /** + * 删除保护 0关闭 1开启 + */ + @ExcelProperty(value = "删除保护 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String isDelProtect; + + /** + * 下架保护 0关闭 1开启 + */ + @ExcelProperty(value = "下架保护 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String isRemoveProtect; + + /** + * 图书定价 0关闭 1开启 + */ + @ExcelProperty(value = "图书定价 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String bootPrice; + + /** + * 自有图片 0关闭 1开启 + */ + @ExcelProperty(value = "自有图片 0关闭 1开启", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_open_or_close") + private String ownPictures; + + /** + * 默认库存 + */ + @ExcelProperty(value = "默认库存") + private Long stockDeff; + + /** + * 两件折扣 + */ + @ExcelProperty(value = "两件折扣") + private Long twoDiscount; + + /** + * 是否预售 0非预售 1定时预售 2 时段预售 + */ + @ExcelProperty(value = "是否预售 0非预售 1定时预售 2 时段预售") + private String presale; + + /** + * 假一赔十 0 关闭 1开启 + */ + @ExcelProperty(value = "假一赔十 0 关闭 1开启") + private String fake; + + /** + * 发货时间 0 24小时 1 48小时 + */ + @ExcelProperty(value = "发货时间 0 24小时 1 48小时") + private String deliveryTime; + + /** + * 白底图 0关闭 1开启 + */ + @ExcelProperty(value = "白底图 0关闭 1开启") + private String whitePicture; + + /** + * 水印位置 0全部 1第一张 + */ + @ExcelProperty(value = "水印位置 0全部 1第一张") + private String watermarkPosition; + + /** + * 无图过滤 0关闭 1开启 + */ + @ExcelProperty(value = "无图过滤 0关闭 1开启") + private String filtering; + + /** + * 最低价定价 0关闭 1开启 + */ + @ExcelProperty(value = "最低价定价 0关闭 1开启") + private String lowerPrice; + + /** + * 最低定价折扣 + */ + @ExcelProperty(value = "最低定价折扣") + private String lowerPriceDiscount; + + /** + * 拼单模板id + */ + @ExcelProperty(value = "拼单模板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/vo/ShopGoodIsbnVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopGoodIsbnVo.java new file mode 100644 index 0000000..e8ea32f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopGoodIsbnVo.java @@ -0,0 +1,11 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; + +@Data +public class ShopGoodIsbnVo { + private Long id; + private String shopGoodsId; + private String goodIsbn; + private String goodUnifyIsbn; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopVo.java new file mode 100644 index 0000000..78854eb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopVo.java @@ -0,0 +1,200 @@ +package org.dromara.zhishu.domain.vo; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.zhishu.domain.Shop; +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 + * + * @author yxy + * @date 2025-03-10 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Shop.class) +public class ShopVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 三方店铺id + */ + @ExcelProperty(value = "三方店铺id") + private Long mallId; + + /** + * 万里牛系统ID + */ + @ExcelProperty(value = "万里牛系统ID") + private String shopNike; + + /** + * 店铺类型 1 拼多多 + */ + @ExcelProperty(value = "店铺类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_shop_type") + private String shopType; + + /** + * 分组 + */ + @ExcelProperty(value = "分组") + private String shopGroup; + + /** + * 店铺名称 + */ + @ExcelProperty(value = "店铺名称") + private String shopName; + + /** + * 店铺名称(对应平台的店铺名称) + */ + @ExcelProperty(value = "三方名称") + private String shopAliasName; + + /** + * 是否授权 0未授权 1已授权 2已过期 + */ + @ExcelProperty(value = "是否授权", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_shop_authorize") + private String shopAuthorize; + + /** + * 到期时间 + */ + @ExcelProperty(value = "到期时间") + private Date expirationTime; + + /** + * 添加时间 + */ + @ExcelProperty(value = "添加时间") + private Date addTime; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + + /** + * 店铺key + */ + @ExcelProperty(value = "店铺key") + private String shopKey; + + /** + * token + */ + @ExcelProperty(value = "token") + private String token; + + /** + * 刷新token 的token + */ + @ExcelProperty(value = "refreshToken") + private String refreshToken; + + + /** + * 店铺状态(0正常 1停用) + */ + @ExcelProperty(value = "店铺状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 租户编码 + */ + @ExcelProperty(value = "租户编码") + private String tenant_id; + + /** + * 上次订单同步时间 + */ + @ExcelIgnore + private Long startUpdatedAt; + + /** + * 创建人 + */ + @ExcelIgnore + private Long createBy; + + /** + * 第三方平台账号 + */ + @ExcelProperty(value = "第三方平台账号") + private String account; + + /** + * 第三方平台密码 + */ + @ExcelProperty(value = "第三方平台密码") + private String password; + + /** + * 是否存在待同步商品文件 + */ + @ExcelIgnore + private Boolean hasSyncFile; + + private String autoAdd; + + /** + * 是否开启同步订单:默认0-否 1-是 + */ + private Integer isSynOrder; + + /** + * 服务版本 + */ + private String skuSpec; + + /** + * erp到期时间 + */ + private Date shopExpirationTime; + + /** + * erp是否到期 + */ + private String isExpiration; + + /** + * 咸鱼用的应用ID + */ + private String code; + + /** + * 拼多多试用版是否无上限 1 否 2 是 + */ + private String deregulation; + + /** + * 使用次数 + */ + private Long usageCount; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopWarehouseVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopWarehouseVo.java new file mode 100644 index 0000000..df76122 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ShopWarehouseVo.java @@ -0,0 +1,51 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.ShopWarehouse; +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_warehouse + * + * @author yxy + * @date 2025-12-28 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ShopWarehouse.class) +public class ShopWarehouseVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 店铺id + */ + @ExcelProperty(value = "店铺id") + private Long shopId; + + /** + * 用户id(仓库id) + */ + @ExcelProperty(value = "用户id", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "仓=库id") + private Long userId; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SpecVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SpecVo.java new file mode 100644 index 0000000..a5b9add --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SpecVo.java @@ -0,0 +1,111 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.Spec; +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_spec + * + * @author yxy + * @date 2025-03-27 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Spec.class) +public class SpecVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 店铺id + */ + @ExcelProperty(value = "店铺id") + private Long shopId; + + /** + * 规格类型id + */ + @ExcelProperty(value = "规格类型id") + private String specTypeId; + + /** + * 规格类型名称 + */ + @ExcelProperty(value = "规格类型名称") + private String specTypeName; + + /** + * 规格组成 0 自定义 1 ISBN 2 书名 3货号 + */ + @ExcelProperty(value = "规格组成 0 自定义 1 ISBN 2 书名 3货号") + private String specCompose; + + /** + * 自定义规格名称 + */ + @ExcelProperty(value = "自定义规格名称") + private String specName; + + /** + * 自定义规格前缀 + */ + @ExcelProperty(value = "自定义规格前缀") + private String specPrefix; + + /** + * 自定义规格后缀 + */ + @ExcelProperty(value = "自定义规格后缀") + private String specSuffix; + + /** + * 规格编码组成 0 自定义 1 ISBN 2 书名 3货号 + */ + @ExcelProperty(value = "规格编码组成 0 自定义 1 ISBN 2 书名 3货号") + private String specCodeCompose; + + /** + * 自定义规格编码前缀 + */ + @ExcelProperty(value = "自定义规格编码前缀") + private String specCodePrefix; + + /** + * 自定义规格编码后缀 + */ + @ExcelProperty(value = "自定义规格编码后缀") + private String specCodeSuffix; + + /** + * SKU水印图片路径 + */ + @ExcelProperty(value = "SKU水印图片路径") + private String specSyUrl; + + /** + * 状态(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/StatisticVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/StatisticVo.java new file mode 100644 index 0000000..dba5628 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/StatisticVo.java @@ -0,0 +1,58 @@ +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 lombok.EqualsAndHashCode; +import org.dromara.common.tenant.core.TenantEntity; +import org.dromara.zhishu.domain.Spec; +import org.dromara.zhishu.domain.Statistic; + +import java.io.Serializable; + +/** + * 统计类 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Statistic.class) +public class StatisticVo implements Serializable { + + /** + * 库房数量 + */ + @ExcelProperty(value = "库房总数") + private Long warehousesNum; + + /** + * 货架数量 + */ + @ExcelProperty(value = "货架总数") + private Long shelvesNum; + + /** + * 仓库名称 + */ + @ExcelProperty(value = "仓库名称") + private String warehousesName; + + /** + * 入库量 + */ + @ExcelProperty(value = "入库数量") + private Long inQuantity; + + /** + * 出库量 + */ + @ExcelProperty(value = "出库数量") + private Long outQuantity; + + /** + * 书籍种类 + */ + @ExcelProperty(value = "书籍分类") + private String bookCategory; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/StockChangeLogVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/StockChangeLogVo.java new file mode 100644 index 0000000..5e9f639 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/StockChangeLogVo.java @@ -0,0 +1,61 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 库存变更记录 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class StockChangeLogVo { + + /** + * 库存变更记录id + */ + private Long id; + + /** + * 商品id + */ + private Long shopGoodsId; + + /** + * 操作类型 类型 0-预留 1-手动修改 2-订单减扣 3-退单添加 4-小程序上书 + */ + private Integer type; + + /** + * 变更前库存 + */ + private Long beforeInv; + + /** + * 变更后库存 + */ + private Long afterInv; + + /** + * 相关id + */ + private String aboutId; + + /** + * 创建人 + */ + private Long createBy; + + + /** + * 用户名 + */ + private String userName; + + /** + * 创建时间 + */ + private String createTime; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SynchronizationShopLogVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SynchronizationShopLogVo.java new file mode 100644 index 0000000..253ce16 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/SynchronizationShopLogVo.java @@ -0,0 +1,98 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; + +/** + * 同步店铺商品库存日志视图对象 + * + * @author yxy + * @date 2026-04-14 + */ +@Data +public class SynchronizationShopLogVo { + + /** + * 主键ID + */ + 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 createAt; + + /** + * 创建人 + */ + private Long createBy; + + /** + * 修改人 + */ + 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/TAuditVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TAuditVo.java new file mode 100644 index 0000000..8552c64 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TAuditVo.java @@ -0,0 +1,145 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.TAudit; +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-01 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TAudit.class) +public class TAuditVo 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; + + private Long auditId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TDepotVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TDepotVo.java new file mode 100644 index 0000000..f259f1a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TDepotVo.java @@ -0,0 +1,138 @@ +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.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.zhishu.domain.TDepot; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 仓库信息设置视图对象 t_depot + * + * @author Lion Li + * @date 2025-03-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TDepot.class) +public class TDepotVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 仓库id + */ + @ExcelProperty(value = "一级货区id") + private Long id; + + /** + * 仓库编号 + */ + @ExcelProperty(value = "货区编号") + private String code; + + /** + * 仓库名称 + */ + @ExcelProperty(value = "一级货区名称") + private String name; + + /** + *单位 + */ +// @ExcelProperty(value = "货区单位") + private String unit; + + /** + * 仓库地址 + */ + @ExcelProperty(value = "货区地址") + private String address; + + /** + * 仓库管理员 + */ + @ExcelProperty(value = "货区管理员") + private String manager; + + + /** + * 仓库状态(0正常 1停用) + */ + @ExcelProperty(value = "货区状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 货架数量 + */ + @ExcelProperty(value = "二级货区数量") + private Long sheQuantityMax; + + + /** + * 已用数量 + */ + @ExcelProperty(value = "已用数量") + private Long sheNumber; + + /** + * 用户姓名 + */ + @ExcelProperty(value = "用户姓名") + private String userName; + + /** + * 用户id + */ +// @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 是否有下一级 + */ + private Boolean hasChildren; + + private Integer level; + + + /** + * 物流模版Id + */ + private Long templateId; + + /** + * 物流模版名称 + */ + private String templateName; + + /** + * 书品库存 + */ + private Long inventory; + + /** + * 书品类型数量 + */ + private Long categoryNumber; + /** + * userId + */ + private Long createBy; + + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TDistrictVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TDistrictVo.java new file mode 100644 index 0000000..dc4908b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TDistrictVo.java @@ -0,0 +1,63 @@ +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.TDistrict; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TDistrict.class) +public class TDistrictVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 区划信息id + */ + @ExcelProperty(value = "区划信息id") + private Long id; + + /** + * 父级挂接id + */ + @ExcelProperty(value = "父级挂接id") + private Long pid; + + /** + * 区划编码 + */ + @ExcelProperty(value = "区划编码") + private String code; + + /** + * 区划名称 + */ + @ExcelProperty(value = "区划名称") + private String name; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 状态 0 正常 -2 删除 -1 停用 + */ + @ExcelProperty(value = "状态 0 正常 -2 删除 -1 停用") + private Long status; + + /** + * 级次id 0:省/自治区/直辖市 1:市级 2:县级 + */ + @ExcelProperty(value = "级次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/vo/TInviteRelationsVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TInviteRelationsVo.java new file mode 100644 index 0000000..c8c2a10 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TInviteRelationsVo.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.domain.vo; + +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +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.TInviteRelations; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 【请填写功能名称】视图对象 t_invite_relations + * + * @author Lion Li + * @date 2025-12-16 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TInviteRelations.class) +public class TInviteRelationsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 邀请人ID + */ + @ExcelProperty(value = "邀请人ID") + private Long inviterId; + + /** + * 被邀请人ID + */ + @ExcelProperty(value = "被邀请人ID") + private Long inviteeId; + + /** + * 使用的邀请码 + */ + @ExcelProperty(value = "使用的邀请码") + private String inviteCode; + + /** + * 邀请时间 + */ + @ExcelProperty(value = "邀请时间") + private Date inviteTime; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TLogisticsVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TLogisticsVo.java new file mode 100644 index 0000000..2fed5b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TLogisticsVo.java @@ -0,0 +1,141 @@ +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.TLogistics; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Date; + + + +/** + * 物流管理视图对象 t_logistics + * + * @author Lion Li + * @date 2025-04-22 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TLogistics.class) +public class TLogisticsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 物流模板名称 + */ + @ExcelProperty(value = "物流模板名称") + private String templateName; + + /** + * 发货地-省 + */ +// @ExcelProperty(value = "发货地-省") + private String deliveryProvince; + + /** + * 发货地-市 + */ +// @ExcelProperty(value = "发货地-市") + private String deliveryCity; + + /** + * 发货地-区 + */ +// @ExcelProperty(value = "发货地-区") + private String deliveryArea; + + /** + * 详细地址 + */ + @ExcelProperty(value = "详细地址") + private String deliveryAddress; + + /** + * 计价方式(0按重量 1按标准本数(图书专用) 2按件数 3单独设置运费) + */ + @ExcelProperty(value = "计价方式", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=按重量,1=按标准本数(图书专用),2=按件数,3=单独设置运费") + private String pricingMethod; + + /** + * 运送方式(0快递 物流) + */ + @ExcelProperty(value = "运送方式", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=快递,1=物流") + private String shipping; + + /** + * 首重 首本 首件 + */ +// @ExcelProperty(value = "首重 首本 首件") + private Long firWbv; + + /** + * 首费 单位:元 + */ +// @ExcelProperty(value = "首费 单位:元") + private Long firPrice; + + /** + * 续重 续本 续件 + */ +// @ExcelProperty(value = "续重 续本 续件") + private Long continueWbv; + + /** + * 续费 单位:元 + */ +// @ExcelProperty(value = "续费 单位:元") + private Long continuePrice; + + /** + * 模板状态(0正常 1停用) + */ + @ExcelProperty(value = "模板状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 运送范围 + */ +// @ExcelProperty(value = "运送范围") + private String shippingRange; + + /** + * 仓库ID + */ +// @ExcelProperty(value = "仓库ID") + private Long warehouseId; + + /** + * 仓库名称 + */ + @ExcelProperty(value = "仓库名称") + private String warehouseName; + /** + * 联系人 + */ + private String contact; + + /** + * 联系电话 + */ + private String phoneNumber; + /** + * 详细地址 + */ + private String fullAddress; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShelvesVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShelvesVo.java new file mode 100644 index 0000000..1d1394b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShelvesVo.java @@ -0,0 +1,101 @@ +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.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.zhishu.domain.TShelves; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 货架信息视图对象 t_shelves + * + * @author Lion Li + * @date 2025-03-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TShelves.class) +public class TShelvesVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 货架id + */ + @ExcelProperty(value = "二级货区id") + private Long id; + + /** + * 货架名称 + */ + @ExcelProperty(value = "货区名称") + private String name; + + /** + * 货架单位 + */ +// @ExcelProperty(value = "货区单位") + private String unit; + + + /** + * 货架层数 + */ +// @ExcelProperty(value = "货架层数") + private Long sheCapMax; + + /** + * 货架状态(0正常 1停用) + */ + @ExcelProperty(value = "货区状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 货架编码 + */ + @ExcelProperty(value = "货区编码") + private String code; + + /** + * 仓库名称 + */ + @ExcelProperty(value = "一级货区名称") + private String depotName; + + private String depotId; + + /** + * 已用数量 + */ + private Long sheNumber; + + /** + * 一级+二级货区编号 + */ + private String twosCode; + + /** + * 是否有下一级 + */ + private Boolean hasChildren; + + private Integer level; + + /** + * 书品库存总数 + */ + private Long inventory; + /** + * 书品分类数量 + */ + private Long categoryNumber; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopDepotAotuVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopDepotAotuVo.java new file mode 100644 index 0000000..c3438bd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopDepotAotuVo.java @@ -0,0 +1,41 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +/** + * 店铺自动发布仓库关联视图对象 + */ +@Data +public class TShopDepotAotuVo { + + /** + * 主键 + */ + private Long id; + + /** + * 店铺id + */ + private Long shopId; + + /** + * 仓库id + */ + private Long depotId; + + /** + * 状态(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/vo/TShopMessageSubscribeVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopMessageSubscribeVo.java new file mode 100644 index 0000000..7bb9400 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopMessageSubscribeVo.java @@ -0,0 +1,55 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Data; + +import java.util.Date; + +@Data +public class TShopMessageSubscribeVo { + + /** + * 主键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代表删除) + */ + private String delFlag; + + /** + * 租户编号 + */ + private String tenantId; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopOrderDetailVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopOrderDetailVo.java new file mode 100644 index 0000000..f598bf2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TShopOrderDetailVo.java @@ -0,0 +1,117 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.TShopOrderDetail; +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_order_detail + * + * @author Lion Li + * @date 2025-03-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = TShopOrderDetail.class) +public class TShopOrderDetailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 店铺id + */ + @ExcelProperty(value = "店铺id") + private String shopId; + + /** + * 店铺名称 + */ + @ExcelProperty(value = "店铺名称") + private String shopName; + + /** + * 订单id + */ + @ExcelProperty(value = "订单id") + private String orderId; + + /** + * 商品数量 + */ + @ExcelProperty(value = "商品数量") + private Long goodsCount; + + /** + * 商品编码 + */ + @ExcelProperty(value = "商品编码") + private String goodsId; + + /** + * 商品图片 + */ + @ExcelProperty(value = "商品图片") + private String goodsImg; + + /** + * 商品名称 + */ + @ExcelProperty(value = "商品名称") + private String goodsName; + + /** + * 商品单件 单价:元 + */ + @ExcelProperty(value = "商品单件 单价:元") + private String goodsPrice; + + /** + * 商品规格 + */ + @ExcelProperty(value = "商品规格") + private String goodsSpec; + + /** + * 商品维度外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息 + */ + @ExcelProperty(value = "商品维度外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息") + private String outerGoodsId; + + /** + * sku维度商家外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息 + */ + @ExcelProperty(value = "sku维度商家外部编码,注意:编辑商品后必须等待商品审核通过后方可生效,订单中商品信息为交易快照的商品信息") + private String outerId; + + /** + * 商品sku编码 + */ + @ExcelProperty(value = "商品sku编码") + private String skuId; + + /** + * 店铺状态(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/TaskUrlVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TaskUrlVo.java new file mode 100644 index 0000000..35569af --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TaskUrlVo.java @@ -0,0 +1,37 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * 解密返回的数据 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TaskUrlVo { + /** + * 任务id + */ + private String taskid; + /** + * 解密后的链接 + */ + private String qureyApiUrl; + + /** + * 数据总数 + */ + private String total; + + + /** + * 店铺列表json字符串 + */ + private List shopListJson; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TaskVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TaskVo.java new file mode 100644 index 0000000..5e5b0bf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/TaskVo.java @@ -0,0 +1,114 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnore; +import org.dromara.zhishu.domain.Task; +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_task + * + * @author yxy + * @date 2025-03-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Task.class) +public class TaskVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long id; + + /** + * 任务类型 1 发布商品;SYNC_GOODS_KFZ 同步商品-孔夫子;UPDATE_GOODS_PRICE改价商品任务; + * GET_SHOP_GOODS 拉取商品任务;EDIT_ISONSALE_GOODS 上下架商品任务; + * EDIT_STOCK_GOODS 更新库存任务;DELETE_SHOP_GOODS 定时删除商品任务; + */ + @ExcelProperty(value = "任务类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_task_type") + private String taskType; + + /** + * 店铺id 字符串 + */ + @ExcelProperty(value = "店铺id") + private String shopIds; + + @ExcelProperty(value = "店铺名称") + private String shopNames; + + /** + * 文件名称 + */ + @ExcelProperty(value = "文件名称") + private String fileName; + + /** + * 执行数据条数 + */ + @ExcelProperty(value = "执行数据条数") + private Long dataNum; + + /** + * 任务状态 + */ + @ExcelProperty(value = "任务状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_task_status") + private String taskStatus; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 线程id + */ + private String threadId; + + /** + * 是否存在待同步商品文件 + */ + @ExcelIgnore + private Boolean hasSyncFile; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 消息 + */ + private String msg; + + private int successCount; + + private int waitCount; + + private int pauseCount; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserRechargeVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserRechargeVo.java new file mode 100644 index 0000000..b6ed057 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/UserRechargeVo.java @@ -0,0 +1,110 @@ +package org.dromara.zhishu.domain.vo; + +import java.math.BigDecimal; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import org.dromara.zhishu.domain.UserRecharge; +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_recharge + * + * @author yxy + * @date 2025-04-26 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = UserRecharge.class) +public class UserRechargeVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 充值类型 1 微信支付 2 支付宝支付 ... + */ + @ExcelProperty(value = "充值类型 1 微信支付 2 支付宝支付 ...") + private String rechargType; + + /** + * 充值金额 单位分 + */ + @ExcelProperty(value = "充值金额 单位分") + private Long rechargPrice; + + /** + * 支付成功时间 + */ + @ExcelProperty(value = "支付成功时间") + private Date successTime; + + /** + * 支付成功后回调方法中数据字符串 + */ + @ExcelProperty(value = "支付成功后回调方法中数据字符串") + private String allDataStr; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=正常,1=停用") + private String status; + + + /** + * 手续费 + */ + @ExcelProperty(value = "手续费") + private BigDecimal commission; + + /** + * 是否充值到余额中 + */ + private String isBalance; + + private Date createTime; + /** + * 创建人 + */ + private String createBy; + + /** + * 日志备注 + */ + private String logTxt; + + + /** + * 原始金额 + */ + private BigDecimal originalPrice; + + /** + * 更新金额 + */ + private BigDecimal updatePrice; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ViolationVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ViolationVo.java new file mode 100644 index 0000000..cf89c8e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ViolationVo.java @@ -0,0 +1,83 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.Violation; +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_violation + * + * @author yxy + * @date 2025-06-23 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Violation.class) +public class ViolationVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 类型 0 isbn 1 书名 2 作者 3 出版社 + */ + @ExcelProperty(value = "类型 0 isbn 1 书名 2 作者 3 出版社", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "t_violation_type") + private String type; + + /** + * 违规原因 + */ + @ExcelProperty(value = "违规原因") + private String content; + + /** + * 发起人 + */ + @ExcelProperty(value = "发起人") + private Long userid; + + /** + * 是否审核 0 未审核 1 已审核 + */ + @ExcelProperty(value = "是否审核 0 未审核 1 已审核") + private String review; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 审核意见 + */ + private String remark; + + /** + * 违规内容 + */ + private String name; + + /** + * 分类 + */ + private String sort; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WaveDetailVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WaveDetailVo.java new file mode 100644 index 0000000..3897d7a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WaveDetailVo.java @@ -0,0 +1,80 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.WaveDetail; +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; + + + +/** + * 波次信息视图对象 wave_detail + * + * @author Lion Li + * @date 2026-01-22 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = WaveDetail.class) +public class WaveDetailVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 波次ID + */ + @ExcelProperty(value = "波次ID") + private Long waveId; + + /** + * ISBN + */ + @ExcelProperty(value = "ISBN") + private String isbn; + + /** + * 仓储ID + */ + @ExcelProperty(value = "仓储ID") + private Long stockId; + + /** + * 仓储编号 + */ + @ExcelProperty(value = "仓储编号") + private String stockNum; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Long createdTime; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Long updatedTime; + + /** + * 是否已删除 + */ + @ExcelProperty(value = "是否已删除") + private Long isDel; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WaveVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WaveVo.java new file mode 100644 index 0000000..0da70bb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WaveVo.java @@ -0,0 +1,80 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.Wave; +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; + + + +/** + * 波次视图对象 wave + * + * @author Lion Li + * @date 2026-01-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = Wave.class) +public class WaveVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private String id; + + /** + * 人员ID + */ + @ExcelProperty(value = "人员ID") + private String staffId; + + /** + * 人员姓名 + */ + @ExcelProperty(value = "人员姓名") + private String staffName; + + /** + * 数量 + */ + @ExcelProperty(value = "数量") + private Long count; + + /** + * 是否支付 + */ + @ExcelProperty(value = "是否支付") + private Long isPay; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Long createdTime; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Long updatedTime; + + /** + * 是否删除 + */ + @ExcelProperty(value = "是否删除") + private Long isDel; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WhiteListVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WhiteListVo.java new file mode 100644 index 0000000..2e390aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/WhiteListVo.java @@ -0,0 +1,51 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.WhiteList; +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_white_list + * + * @author yxy + * @date 2025-06-25 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = WhiteList.class) +public class WhiteListVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * ip + */ + @ExcelProperty(value = "ip") + private String ip; + + /** + * 状态(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/XyCategoryVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/XyCategoryVo.java new file mode 100644 index 0000000..0086f1d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/XyCategoryVo.java @@ -0,0 +1,32 @@ +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.XyCategory; + +import java.io.Serializable; + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = XyCategory.class) +public class XyCategoryVo implements Serializable { + /** + * 行业 + */ + @ExcelProperty(value = "行业") + private String industry; + + /** + * 类目 + */ + @ExcelProperty(value = "类目") + private String category; + + /** + * id + */ + @ExcelProperty(value = "id") + private String id; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopGoodsDetailVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopGoodsDetailVo.java new file mode 100644 index 0000000..8d5ec43 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopGoodsDetailVo.java @@ -0,0 +1,87 @@ +package org.dromara.zhishu.domain.vo; + +import org.dromara.zhishu.domain.ZhishuShopGoodsDetail; +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; + + + +/** + * 商品信息补全表视图对象 zhishu_shop_goods_detail + * + * @author yxy + * @date 2025-06-13 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ZhishuShopGoodsDetail.class) +public class ZhishuShopGoodsDetailVo 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 author; + + /** + * 出版社 + */ + @ExcelProperty(value = "出版社") + private String publisher; + + /** + * 出版时间 + */ + @ExcelProperty(value = "出版时间") + private String publishertime; + + /** + * 开本 + */ + @ExcelProperty(value = "开本") + private String format; + + /** + * 字数 + */ + @ExcelProperty(value = "字数") + private String wordage; + + /** + * 统一书号 + */ + @ExcelProperty(value = "统一书号") + private String unifiedisbn; + + /** + * 状态(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/ZhishuShopGoodsVo.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopGoodsVo.java new file mode 100644 index 0000000..3e8a4f6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/ZhishuShopGoodsVo.java @@ -0,0 +1,224 @@ +package org.dromara.zhishu.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnore; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.persistence.Column; +import lombok.Data; +import org.dromara.zhishu.domain.ZhishuShopGoods; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + + +/** + * 商品信息视图对象 zhishu_shop_goods + * + * @author Lion Li + * @date 2025-03-07 + */ + +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = ZhishuShopGoods.class) +public class ZhishuShopGoodsVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private String id; + + /** + * 是否加入分销:1-否 2-是 + */ + @ExcelProperty(value = "isJoinDistribution") + private Integer isJoinDistribution; + + /** + * 用户Id + */ + @ExcelIgnore + private Long userId; + + /** + * 用户电话号码(打码) + */ + @ExcelIgnore + private String phoneNumberMark; + + /** + * 仓库编号 + */ + @ExcelIgnore + private Long depotId; + + /** + * 仓库名称 + */ + @ExcelIgnore + private String depotName; + + /** + * 物流模板Id + */ + @ExcelIgnore + private Long templateId; + + /** + * 物流模板名称 + */ + @ExcelIgnore + private String templateName; + + /** + * 物流模板详细地址 + */ + @ExcelIgnore + private String deliveryAddress; + + /** + * 寄件方式 + */ + @ExcelIgnore + private String pricingMethod; + + /** + * 模板最优惠价格 + */ + @ExcelIgnore + private BigDecimal templateMinPrice; + + /** + * 商品定价 + */ + @ExcelIgnore + private Long fixPrice; + + /** + * 商品名称 + */ + @ExcelProperty(value = "商品名称") + private String goodsName; + + /** + * 商品编码 + */ + @ExcelProperty(value = "产品编码") + private String productId; + /** + * 商品编码 + */ + @ExcelProperty(value = "商品编号") + private String itemNumber; + /** + * isbn + */ + @ExcelProperty(value = "isbn") + private String isbn; + + /** + * 货号 + */ + @ExcelProperty(value = "货号") + private String artNo; + + /** + * 原始货号 + */ + @ExcelProperty(value = "原始货号") + private String originalArtNo; + + /** + * 期初库存 + */ + @ExcelIgnore + private Long stock; + + /** + * 标准售价 + */ + @ExcelProperty(value = "标准售价") + private BigDecimal price; + + /** + * 品相 + */ + @ExcelProperty(value = "品相") + private String conditionCode; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 状态 + */ + + @ExcelProperty(value = "库存") + private String inventory; + + /** + * 扣减库存 + */ + private String updateInventory; + /** + * 是否已进行货号转换:0-否,1-是 + */ + @ExcelIgnore + private Integer isArtNoConversion; + + /** + * 图片 + */ + @ExcelIgnore + private String bookPic; + /** + * 图片路径 + */ + @ExcelIgnore + private String path; + + /** + * 入库时间 + */ + private Date createTime; + + /** + * 拼多多发布状态(0未发布,1已发布) + */ + private Long pddPublishedStatus; + + /** + * 孔夫子发布状态(0未发布,1已发布) + */ + private Long kfzPublishedStatus; + /** + * 闲鱼发布状态(0未发布,1已发布) + */ + private Long xyPublishedStatus; + + /** + * 开始时间 + */ + private String startTime; + + /** + * 结束时间 + */ + private String endTime; + + /** + * 自营书品仓库名称 + */ + private String warehouseName; +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/updateOcrResult.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/updateOcrResult.java new file mode 100644 index 0000000..562f6e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/domain/vo/updateOcrResult.java @@ -0,0 +1,26 @@ +package org.dromara.zhishu.domain.vo; + +import lombok.Builder; +import lombok.Data; + +/** + * 图片上传返回体 + * + * @author Lion Li + */ +@Data +public class updateOcrResult { + +// 文件路径 + private String url; +// 提示信息 + private String message; +// 营业执照名称 + private String name; +// 营业执照注册号 + private String regNum; +// 过期时间 + private String period; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/IsJoinDistributionEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/IsJoinDistributionEnum.java new file mode 100644 index 0000000..4fa3af8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/IsJoinDistributionEnum.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 IsJoinDistributionEnum { + + YES(1, "是"), + + NO(0, "否"); + + /** + * code + */ + private final Integer code; + + /** + * message + */ + private final String msg; + + public static List getIsJoinDistributionEnumList() { + List isJoinDistributionEnumList = new ArrayList<>(); + for (IsJoinDistributionEnum item : values()) { + isJoinDistributionEnumList.add(item.getCode()); + } + return isJoinDistributionEnumList; + } + + public static IsJoinDistributionEnum valueOfCode(Integer code) { + for (IsJoinDistributionEnum 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/OperationInventoryTypeEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OperationInventoryTypeEnum.java new file mode 100644 index 0000000..1a8571b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OperationInventoryTypeEnum.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 OperationInventoryTypeEnum { + + INCREASE_INVENTORY(1, "增加库存"), + + REDUCE_INVENTORY(2, "减少库存"); + + /** + * code + */ + private final Integer code; + + /** + * message + */ + private final String msg; + + public static List getOperationInventoryTypeEnumList() { + List operationInventoryTypeEnumList = new ArrayList<>(); + for (OperationInventoryTypeEnum item : values()) { + operationInventoryTypeEnumList.add(item.getCode()); + } + return operationInventoryTypeEnumList; + } + + public static OperationInventoryTypeEnum valueOfCode(int code) { + for (OperationInventoryTypeEnum type : values()) { + if (type.getCode() == code) { + return type; + } + } + throw new ServiceException("未知操作库存类型code: " + code); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OrderSourceTypeEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OrderSourceTypeEnum.java new file mode 100644 index 0000000..7dd126c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/OrderSourceTypeEnum.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 OrderSourceTypeEnum { + + PDD(1, "拼多多"), + + KFZ(2, "孔夫子"); + + /** + * code + */ + private final Integer code; + + /** + * message + */ + private final String msg; + + public static List getOrderSourceTypeEnumList() { + List orderSourceTypeEnumList = new ArrayList<>(); + for (OrderSourceTypeEnum item : values()) { + orderSourceTypeEnumList.add(item.getCode()); + } + return orderSourceTypeEnumList; + } + + public static OrderSourceTypeEnum valueOfCode(Integer code) { + for (OrderSourceTypeEnum 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/PddOrderDetailEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddOrderDetailEnum.java new file mode 100644 index 0000000..4e5b8c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddOrderDetailEnum.java @@ -0,0 +1,26 @@ +package org.dromara.zhishu.enums; + + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum PddOrderDetailEnum { + + GOODS_COUNT("goods_count", "商品数量"), + GOODS_IMG("goods_img", "商品图片"), + GOODS_NAME("goods_name", "商品名称"), + GOODS_PRICE("goods_price", "价格"), + GOODS_SPEC("goods_spec", "商品规格"), + OUTER_GOODS_ID("outer_goods_id", "预约配送时段"), + OUTER_ID("outer_id", "商品维度外部编码"), + SKU_ID("sku_id", "sku维度商家外部编码"), + GOODS_ID("goods_id", "商品编码"); + + + + private final String code; + private final String name; + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddOrderEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddOrderEnum.java new file mode 100644 index 0000000..a4f9447 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/PddOrderEnum.java @@ -0,0 +1,100 @@ +package org.dromara.zhishu.enums; + + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/* + 拼多多订单装换枚举 + */ + +@Getter +@AllArgsConstructor + +public enum PddOrderEnum { + + ADDRESS("address", "详细地址"), + ADDRESS_MASK("address_mask", "详细地址"), + AFTER_SALES_STATUS("after_sales_status", "售后状态"), + BONDED_WAREHOUSE("bonded_warehouse", "保税仓名称"), + BUYER_MEMO("buyer_memo", "买家留言信息"), + CITY("city", "城市"), + CONFIRM_STATUS("confirm_status", "成交状态"), + CONFIRM_TIME("confirm_time", "成交时间"), + CONSOLIDATE_INFO("consolidate_info", "集运信息"), + COUNTRY("country", "国家"), + COUNTRY_ID("country_id", "国家或地区编码"), + CREATED_TIME("created_time", "订单创建时间"), + DELIVERY_HOME_VALUE("delivery_home_value", "详细地址"), + DELIVERY_INSTALL_VALUE("delivery_install_value", "送货入户并安装费用"), + DELIVERY_ONE_DAY("delivery_one_day", "是否当日发货"), + DISCOUNT_AMOUNT("discount_amount", "折扣金额"), + DUO_DUO_PAY_REDUCTION("duo_duo_pay_reduction", "多多支付立减金额"), + DUODUO_WHOLESALE("duoduo_wholesale", "是否多多批发"), + EXTRA_DELIVERY_LIST("extra_delivery_list", "快递信息"), + GOODS_AMOUNT("goods_amount", "商品金额"), + INNER_TRANSACTION_ID("inner_transaction_id", "支付申报订单号"), + ITEM_LIST("item_list", "订单商品列表"), + LAST_SHIP_TIME("last_ship_time", "订单承诺发货时间"), + LOGISTICS_ID("logistics_id", "快递公司在拼多多的代码"), + MKT_BIZ_TYPE("mkt_biz_type", "市场业务类型"), + ONLY_SUPPORT_REPLACE("only_support_replace", "只换不修"), + OPEN_ADDRESS_ID("open_address_id", "合单ID"), + ORDER_CHANGE_AMOUNT("order_change_amount", "订单改价折扣金额,单位元"), + ORDER_DEPOT_INFO("order_depot_info", "仓库信息"), + DEPOT_CODE("depot_code", "仓库编码"), + DEPOT_ID("depot_id", "仓库id"), + DEPOT_NAME("depot_name", "仓库名称"), + DEPOT_TYPE("depot_type", "仓库类型"), + WARE_ID("ware_id", "货品id"), + WARE_NAME("ware_name", "货品名称"), + WARE_SN("ware_sn", "货品编码"), + WARE_TYPE("ware_type", "货品类型(0:普通货品:1:组合货品)"), + ORDER_SN("order_sn", "订单编号"), + ORDER_STATUS("order_status", "订单状态"), + PAY_AMOUNT("pay_amount", "支付金额"), + PAY_NO("pay_no", "支付单号"), + PAY_TIME("pay_time", "支付时间"), + PAY_TYPE("pay_type", "支付方式"), + PLATFORM_DISCOUNT("platform_discount", "平台优惠金额"), + POSTAGE("postage", "邮费"), + PRE_SALE_TIME("pre_sale_time", "预售时间"), + PROMISE_DELIVERY_TIME("promise_delivery_time", "承诺送达时间"), + PROVINCE_ID("province_id", "省份编码"), + PROVINCE("province", "省份编码"), + RECEIVE_TIME("receive_time", "确认收货时间"), + RECEIVER_ADDRESS("receiver_address", "收件人地址"), + RECEIVER_ADDRESS_MASK("receiver_address_mask", "收件人地址"), + RECEIVER_NAME("receiver_name", "收件人姓名"), + RECEIVER_NAME_MASK("receiver_name_mask", "收件人姓名"), + RECEIVER_PHONE("receiver_phone", "收件人手机号"), + RECEIVER_PHONE_MASK("receiver_phone_mask", "收件人手机号(打码)"), + REFUND_STATUS("refund_status", "售后状态"), + REMARK("remark", "订单备注"), + REMARK_TAG("remark_tag", "订单备注标记"), + REMARK_TAG_NAME("remark_tag_name", "订单备注标记名称"), + RESEND_DELIVERY_LIST("resend_delivery_list", "补寄额外运单列表"), + RETURN_FREIGHT_PAYER("return_freight_payer", "退货包运费"), + RISK_CONTROL_STATUS("risk_control_status", "订单审核状态"), + SELF_CONTAINED("self_contained", "是否门店自提"), + SELLER_DISCOUNT("seller_discount", "商家优惠金额"), + SERVICE_FEE_DETAIL("service_fee_detail", "服务费明细列表"), + STOCK_OUT_HANDLE_STATUS("stock_out_handle_status", "缺货处理状态"), + SUPPORT_NATIONWIDE_WARRANTY("support_nationwide_warranty", "全国联保"), + TOWN("town", "区,乡镇"), + TOWN_ID("town_id", "区县编码"), + TRACKING_NUMBER("tracking_number", "快递单号"), + TRADE_IN_NATIONAL_SUBSIDY_AMOUNT("trade_in_national_subsidy_amount", "以旧换新国家补贴金额,单位:元"), + TRADE_TYPE("trade_type", "订单类型"), + UPDATED_AT("updated_at", "订单的更新时间"), + URGE_SHIPPING_TIME("urge_shipping_time", "催发货时间"), + YYPS_DATE("yyps_date", "预约配送日期"), + YYPS_TIME("yyps_time", "预约配送时段"), + OPEN_ADDRESS_ID_2("open_address_id_2", "合单ID2"); + + + private final String code; + private final String name; + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/TaskStatusTypeEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/TaskStatusTypeEnum.java new file mode 100644 index 0000000..c91b1fb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/TaskStatusTypeEnum.java @@ -0,0 +1,52 @@ +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 TaskStatusTypeEnum { + + NOT_EXECUTE("0", "未执行"), + + EXECUTING("1", "执行中"), + + EXECUTE_PAUSE_STOP("2", "暂停/停止"), + + EXECUTED("3", "已完成"); + + /** + * code + */ + private final String code; + + /** + * message + */ + private final String msg; + + public static List getTaskStatusTypeEnumList() { + List taskStatusTypeEnumList = new ArrayList<>(); + for (TaskStatusTypeEnum item : values()) { + taskStatusTypeEnumList.add(item.getCode()); + } + return taskStatusTypeEnumList; + } + + public static TaskStatusTypeEnum valueOfCode(String code) { + for (TaskStatusTypeEnum 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/TaskTypeEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/TaskTypeEnum.java new file mode 100644 index 0000000..5423c5e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/enums/TaskTypeEnum.java @@ -0,0 +1,47 @@ +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 TaskTypeEnum { + + PUBLISH_GOODS("1", "发布商品"), + + SYNC_GOODS_KFZ("SYNC_GOODS_KFZ", "孔夫子"), + + SYNC_GOODS_WLN("SYNC_GOODS_WLN", "万里牛"); + + /** + * code + */ + private final String code; + + /** + * message + */ + private final String msg; + + public static List getTaskTypeEnumList() { + List taskTypeEnumList = new ArrayList<>(); + for (TaskTypeEnum item : values()) { + taskTypeEnumList.add(item.getCode()); + } + return taskTypeEnumList; + } + + public static TaskTypeEnum valueOfCode(String code) { + for (TaskTypeEnum 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/listener/StartupListener.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/listener/StartupListener.java new file mode 100644 index 0000000..d493acf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/listener/StartupListener.java @@ -0,0 +1,65 @@ +package org.dromara.zhishu.listener; + +import com.alibaba.excel.EasyExcel; +import org.dromara.zhishu.domain.dto.request.ZhishuShopGoodsRequest; +import org.dromara.zhishu.domain.vo.SaveGoodsVo; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.dromara.zhishu.util.ExcelFileHandlerUtil; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.nio.file.Paths; +import java.util.*; + +@Component +public class StartupListener implements CommandLineRunner { + + @Autowired + private IZhishuShopGoodsService zhishuShopGoodsService; + + @Override + public void run(String... args) throws Exception { + String baseDir = UrlUtil.getUrl(); + Collection types = Arrays.asList("New", "Changed"); + + Map>> groupedData = + ExcelFileHandlerUtil.readExcelByTypeAndShopId(baseDir, types, ZhishuShopGoodsRequest.class); + + // 打印结果 + groupedData.forEach((type, shopMap) -> { +// System.out.println("Type: " + type); + shopMap.forEach((shopId, list) -> { +// System.out.println(" Shop ID: " + shopId + ", 记录数: " + list.size()); + // 指定读取需要的商品Excel文件路径 + String baseUrl = UrlUtil.getUrl(); + String goodsExcelPath = Paths.get(baseUrl, type + "_" + shopId + "_0.xlsx").toString(); + try { +// System.out.println("尝试读取数据:path-" + goodsExcelPath); + // 尝试读取新增的数据 + List dataList = EasyExcel.read(goodsExcelPath) + .head(ZhishuShopGoodsRequest.class) + .sheet("New_" + shopId + "_0") + .doReadSync(); + // 将list中所有productId取出 + List productIdList = list.stream().map(ZhishuShopGoodsRequest::getProductId).distinct().toList(); + // 将dataList中productId存在与list中的数据移除 + List exportDataList = dataList.stream().filter(zhishuShopGoodsRequest -> !productIdList.contains(zhishuShopGoodsRequest.getProductId())).toList(); + // 将剩余的dataList数据覆盖到原excel中 + ExcelFileHandlerUtil.handleExport(exportDataList, baseUrl, type, shopId.toString(), ZhishuShopGoodsRequest.class); + // 调用方法重新执行这些数据 + SaveGoodsVo saveGoodsVo = new SaveGoodsVo(null, 1, shopId, null); + zhishuShopGoodsService.saveShopGoodsInDb(saveGoodsVo); + // 数据处理完毕删除异常文件 + ExcelFileHandlerUtil.deleteFilesByPrefix(UrlUtil.getUrl(), "Error_" + type + "_" + shopId); + } catch (Exception e) { + // 读取不到说明没有对应需要处理的数据,不做处理,仅记录日志以防其他未知原因导致,不抛出异常 +// System.out.println("未能读取新增数据文件: " + goodsExcelPath + "原因:{}" + e.getMessage()); + } + }); + + + }); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/manager/TaskExecutorManager.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/manager/TaskExecutorManager.java new file mode 100644 index 0000000..c14720d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/manager/TaskExecutorManager.java @@ -0,0 +1,37 @@ +package org.dromara.zhishu.manager; + +import jakarta.annotation.PreDestroy; +import org.springframework.stereotype.Component; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +@Component +public class TaskExecutorManager { + + private final ExecutorService executor; + + public TaskExecutorManager() { + // 使用有界队列和合理的线程数 + this.executor = new ThreadPoolExecutor( + 4, // 核心线程数 + 8, // 最大线程数 + 60L, TimeUnit.SECONDS, // 空闲线程存活时间 + new ArrayBlockingQueue<>(20), // 有界队列,防止无限堆积 + new ThreadPoolExecutor.CallerRunsPolicy() // 重要:拒绝策略 + ); + } + + public ExecutorService getExecutor() { + return executor; + } + + @PreDestroy + public void shutdown() { + if (executor != null && !executor.isShutdown()) { + executor.shutdown(); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/BookBaseInfoMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/BookBaseInfoMapper.java new file mode 100644 index 0000000..309bbd5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/BookBaseInfoMapper.java @@ -0,0 +1,53 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.BookBaseInfo; +import org.dromara.zhishu.domain.bo.BookBaseInfoBo; +import org.dromara.zhishu.domain.bo.IllBaseInfoBo; +import org.dromara.zhishu.domain.vo.BookBaseInfoVo; + +import java.util.List; + +/** + * 基础信息Mapper接口 + * + * @author Lion Li + * @date 2025-03-08 + */ +@Mapper +public interface BookBaseInfoMapper extends BaseMapperPlus { + + + + @Select("select * from book_base_info") + List getList1(); + + + @Select("select * from book_base_info") + @InterceptorIgnore(tenantLine = "true", dataPermission = "false") + List getList2(); + + @Select("select * from book_base_info") + BookBaseInfoVo selectVoByIsdn(QueryWrapper queryWrapper); + + @Select("select * from book_base_info where isbn = #{isbn}") + BookBaseInfoVo selectIsbnList(String isbn); + + BookBaseInfoVo selectByIsbn(String isbn); + + int updateByIsbn(BookBaseInfoBo bo); + + @Select("select * from book_base_info where book_name LIKE CONCAT(#{bookName}, '%')") + List selectByBookName(String bookName); + + List selectBookPic(); + + int delectByIsbn(String isbn); + + int updateByIllge(IllBaseInfoBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/CountMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/CountMapper.java new file mode 100644 index 0000000..2a49c87 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/CountMapper.java @@ -0,0 +1,18 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.Statistic; +import org.dromara.zhishu.domain.vo.StatisticVo; + +import java.util.List; + +@Mapper +public interface CountMapper extends BaseMapperPlus { + + List selectDepotId(Long userId); + + Long selectW(Long userId); + + Long selectS(List depotId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/DepotOrderMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/DepotOrderMapper.java new file mode 100644 index 0000000..0634245 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/DepotOrderMapper.java @@ -0,0 +1,26 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.DepotOrder; +import org.dromara.zhishu.domain.bo.DepotOrderBo; +import org.dromara.zhishu.domain.vo.DepotOrderVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.springframework.data.repository.query.Param; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.List; + +/** + * 仓库订单信息Mapper接口 + * + * @author yxy + * @date 2025-06-03 + */ +public interface DepotOrderMapper extends BaseMapperPlus { + + + List selectListPage(DepotOrderBo depotOrderBo); + + DepotOrderVo selectDepotOrderById(String id); + + Long selectTotal(DepotOrderBo depotOrderBo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ExcelTaskMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ExcelTaskMapper.java new file mode 100644 index 0000000..abd23ff --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ExcelTaskMapper.java @@ -0,0 +1,26 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.ExcelTask; +import org.dromara.zhishu.domain.bo.ExcelTaskBo; +import org.dromara.zhishu.domain.vo.ExcelTaskVo; +import org.springframework.data.repository.query.Param; + +import java.util.Collection; + + +/** + * 任务列表Mapper接口 + * + * @author yxy + * @date 2025-03-21 + */ +@Mapper +public interface ExcelTaskMapper extends BaseMapperPlus { + + Page selectVo(@Param("build") Page build, @Param("bo") ExcelTaskBo bo); + + void deleteExcelTask(Collection ids); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/FastMailMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/FastMailMapper.java new file mode 100644 index 0000000..bf6eb32 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/FastMailMapper.java @@ -0,0 +1,25 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.FastMail; +import org.dromara.zhishu.domain.vo.FastMailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 快递打单账号管理Mapper接口 + * + * @author yxy + * @date 2025-06-06 + */ +public interface FastMailMapper extends BaseMapperPlus { + + + FastMailVo selectByUserIdAndType(@Param("userId") String userId,@Param("type") String type); + + /** + * 根据面单类型删除数据 + * @param fastMailType + * @return + */ + int deleteByFastMailType(@Param("userId") Long userId,@Param("fastMailType") String fastMailType); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/FilterSetMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/FilterSetMapper.java new file mode 100644 index 0000000..c88dc00 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/FilterSetMapper.java @@ -0,0 +1,35 @@ +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.FilterSet; +import org.dromara.zhishu.domain.bo.FilterSetBo; +import org.dromara.zhishu.domain.vo.FilterSetVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 过滤设置Mapper接口 + * + * @author yxy + * @date 2025-04-14 + */ +@Mapper +public interface FilterSetMapper extends BaseMapperPlus { + + @Override + @DataPermission({ + @DataColumn(key = "userName", value = "create_by") + }) + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + List selectVoListByBo(FilterSetBo bo); + + int deleteTrueById(Long id); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/GoodsAutoFailMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/GoodsAutoFailMapper.java new file mode 100644 index 0000000..9e41707 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/GoodsAutoFailMapper.java @@ -0,0 +1,24 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.GoodsAutoFail; +import org.dromara.zhishu.domain.bo.GoodsAutoFailBo; +import org.dromara.zhishu.domain.vo.GoodsAutoFailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 自动发布失败Mapper接口 + * + * @author yxy + * @date 2025-09-29 + */ +public interface GoodsAutoFailMapper extends BaseMapperPlus { + + Long selectAllNum(GoodsAutoFailBo bo); + + @InterceptorIgnore(tenantLine = "true") + List selectList(GoodsAutoFailBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/LogisticsMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/LogisticsMapper.java new file mode 100644 index 0000000..76d30c8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/LogisticsMapper.java @@ -0,0 +1,30 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.Logistics; +import org.dromara.zhishu.domain.bo.LogisticsBo; +import org.dromara.zhishu.domain.vo.LogisticsVo; + +import java.util.List; + +@Mapper +public interface LogisticsMapper extends BaseMapperPlus { + + + String selectByArea(Integer deliveryArea, Integer deliveryCity); + + String selectByProvince(Integer deliveryProvince); + + String selectByCity(Integer deliveryCity, Integer deliveryProvince); + + int insert(Logistics add); + + List selectLogistice(String warehouseId); + + Logistics selectByWareId(Long id); + + Long selectByid(String proName,String cityName,String areaName,Long proId, Long cityId); + + Integer updateByBo(Logistics bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/NewUserBoMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/NewUserBoMapper.java new file mode 100644 index 0000000..dc9c314 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/NewUserBoMapper.java @@ -0,0 +1,24 @@ +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.NewUserInfo; +import org.dromara.zhishu.domain.vo.NewUserVo; + +@Mapper +public interface NewUserBoMapper extends BaseMapperPlus { + + + void insertAudit(@Param("userId") Long userId); + + Integer selectAudit(Long userId); + + Long selectId(Long userId); + + void updatePhone(String email, String contactPhone, Long userId); + + Integer insertAuditInfo(NewUserInfo add); + + Integer selectByPhone(String contactPhone); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/NoticeMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/NoticeMapper.java new file mode 100644 index 0000000..7ae8364 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/NoticeMapper.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.Notice; +import org.dromara.zhishu.domain.vo.NoticeVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 消息通知Mapper接口 + * + * @author yxy + * @date 2025-05-17 + */ +public interface NoticeMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PrintTemplateMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PrintTemplateMapper.java new file mode 100644 index 0000000..c892ca9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/PrintTemplateMapper.java @@ -0,0 +1,30 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.PrintTemplate; +import org.dromara.zhishu.domain.bo.PrintTemplateBo; +import org.dromara.zhishu.domain.vo.PrintTemplateVo; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 打印模板Mapper接口 + * + * @author yxy + * @date 2026-03-07 + */ +public interface PrintTemplateMapper extends BaseMapperPlus { + + /** + * 分页查询打印模板列表(自定义) + */ + Page selectPrintTemplatePage(Page page, @Param("bo") PrintTemplateBo bo); + + /** + * 查询打印模板列表(自定义,无分页) + */ + List selectPrintTemplateList(@Param("bo") PrintTemplateBo bo); + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningLogFileMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningLogFileMapper.java new file mode 100644 index 0000000..2194d73 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningLogFileMapper.java @@ -0,0 +1,18 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.RunningLogFile; +import org.dromara.zhishu.domain.vo.RunningLogFileVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 程序运行日志表Mapper接口 + * + * @author yxy + * @date 2025-06-12 + */ +public interface RunningLogFileMapper extends BaseMapperPlus { + + + String selectMaxFileOrderByFileTypeAndCreateBy(@Param("fileType") String fileType,@Param("userId") String userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningTaskByShopMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningTaskByShopMapper.java new file mode 100644 index 0000000..d4f3d2d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningTaskByShopMapper.java @@ -0,0 +1,234 @@ +package org.dromara.zhishu.mapper; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.dto.ErpGoodsDto; +import org.dromara.zhishu.domain.dto.RunningTaskShopGoodsDto; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.dto.SuccessDataKfz; +import org.dromara.zhishu.domain.vo.RunningTaskNumVo; + +import java.util.List; +import java.util.Map; + +/** + * 执行的任务Mapper接口 + * + * @author yxy + * @date 2025-08-05 + */ +public interface RunningTaskByShopMapper { + + /** + * 分页查询列表 + * @param tableName + * @param pageNum + * @param pageSize + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List selectGetShopGoodsList(@Param("tableName") String tableName,@Param("isOnsale") String isOnsale, + @Param("isbn") String isbn,@Param("priceDown") Long priceDown,@Param("priceUp") Long priceUp, + @Param("startDate") String startDate,@Param("endDate") String endDate, + @Param("pageNum") Long pageNum, @Param("pageSize") Long pageSize, + @Param("goodsName") String goodsName,@Param("stockDown") String stockDown, + @Param("stockUp") String stockUp,@Param("trilateralId") String trilateralId, + @Param("goodsCode") String goodsCode,@Param("skuCode") String skuCode); + + /** + * 查询列表总数 + * @param tableName + * @return + */ + @InterceptorIgnore(tenantLine = "true") + int selectGetShopGoodsListCount(@Param("tableName") String tableName,@Param("isOnsale") String isOnsale, + @Param("isbn") String isbn,@Param("priceDown") Long priceDown,@Param("priceUp") Long priceUp, + @Param("startDate") String startDate,@Param("endDate") String endDate, + @Param("goodsName") String goodsName,@Param("stockDown") String stockDown, + @Param("stockUp") String stockUp,@Param("trilateralId") String trilateralId, + @Param("goodsCode") String goodsCode,@Param("skuCode") String skuCode); + + /** + * 根据DTO查询列表 + * @param runningTaskShopGoodsDto + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List selectGetShopGoodsListByDto(RunningTaskShopGoodsDto runningTaskShopGoodsDto); + + @InterceptorIgnore(tenantLine = "true") + int selectNumByIsbn(@Param("tableName") String tableName,@Param("isbn") String isbn); + /** + * 查询数据表中数据的总数 + * @param tableName + * @return + */ + @InterceptorIgnore(tenantLine = "true") + int selectGetShopGoodsNum(@Param("tableName") String tableName,@Param("isOnSale") String isOnSale, + @Param("isbn") String isbn,@Param("priceDown") Long priceDown,@Param("priceUp") Long priceUp, + @Param("startDate") String startDate,@Param("endDate") String endDate, + @Param("goodsName") String goodsName,@Param("stockDown") String stockDown, + @Param("stockUp") String stockUp,@Param("trilateralId") String trilateralId, + @Param("goodsCode") String goodsCode,@Param("skuCode") String skuCode); + + /** + * 删除店铺商品 + */ + @InterceptorIgnore(tenantLine = "true") + int delShopGoods(@Param("tableName") String tableName,@Param("isOnSale") String isOnSale, + @Param("isbn") String isbn,@Param("priceDown") Long priceDown,@Param("priceUp") Long priceUp, + @Param("startDate") String startDate,@Param("endDate") String endDate); + + /** + * 根据三方平台id查询数据是否存在 + * @param tableName + * @param trilateralId + * @return + */ + @InterceptorIgnore(tenantLine = "true") + int selectByTrilateralId(@Param("tableName") String tableName,@Param("trilateralId") String trilateralId); + + @InterceptorIgnore(tenantLine = "true") + RunningTask selectVoByTrilateralId(@Param("tableName") String tableName,@Param("trilateralId") String trilateralId); + + /** + * 查询店铺最后一次 + * @param tableName + * @return + */ + @InterceptorIgnore(tenantLine = "true") + String selectLastFinishTime(String tableName); + + /** + * 根据isbn查询商品信息 + * @param tableName + * @param isbn + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List selectByIsbn(@Param("tableName") String tableName,@Param("isbn") String isbn); + + /** + * 查询电偶的日志 + * @param tableName + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List selectTaskShopNum(@Param("tableName") String tableName, @Param("taskId") Long taskId); + + /** + * 查询是否是最新任务拉取的数据 + * @param tableName + * @param taskId + * @return + */ + @InterceptorIgnore(tenantLine = "true") + int selectGetShopGoodsNumByTasKId(@Param("tableName") String tableName, @Param("taskId") String taskId); + + /** + * 查询任务是在执行中还是已完成 + * @param tableName + * @return + */ + @InterceptorIgnore(tenantLine = "true") + String selectStatus(String tableName); + + @InterceptorIgnore(tenantLine = "true") + List selectShopGoodsList(ErpGoodsDto erpGoodsDto); + + /** + * kfz专用导出店铺商品数据 + * @param erpGoodsDto + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List selectKfzShopGoodsList(ErpGoodsDto erpGoodsDto); + + + /** + * 根据isbn查询重复数据 + * @param tableName + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List selectRepeat(@Param("tableName") String tableName); + + // 检查表是否存在 + @InterceptorIgnore(tenantLine = "true") + int checkTableExists(@Param("tableName") String tableName); + + // 创建表 + @InterceptorIgnore(tenantLine = "true") + void createTable(@Param("tableName") String tableName); + + // 插入数据 + @InterceptorIgnore(tenantLine = "true") + void insert(@Param("tableName") String tableName, @Param("task") RunningTask task); + + //修改数据 + @InterceptorIgnore(tenantLine = "true") + void update(@Param("tableName") String tableName, @Param("task") RunningTask task); + + // 批量插入数据 + @InterceptorIgnore(tenantLine = "true") + void batchInsert(@Param("tableName") String tableName, @Param("list") List list); + + @InterceptorIgnore(tenantLine = "true") + void updateStatus(String tableName); + + @InterceptorIgnore(tenantLine = "true") + void deleteAll(String tableName); + + @InterceptorIgnore(tenantLine = "true") + void deleteByStatus(@Param("tableName") String tableName,@Param("status") String status); + + @InterceptorIgnore(tenantLine = "true") + void deleteByTaskId(@Param("tableName") String tableName,@Param("taskId") String taskId); + + + @InterceptorIgnore(tenantLine = "true") + List selectOnSaleGoodsId(String tableName); + + @InterceptorIgnore(tenantLine = "true") + List selectByGoodsId(String tableName, String trilateralId); + + @InterceptorIgnore(tenantLine = "true") + void updateSuccessDataById(@Param("tableName") String tableName,@Param("id") String id,@Param("successDataJsonStr") String successDataJsonStr); + + + @InterceptorIgnore(tenantLine = "true") + void deleteByGoodsId(@Param("tableName") String tableName,@Param("goodsId") String goodsId); + + @InterceptorIgnore(tenantLine = "true") + List getShopGoodsList(@Param("tableName") String tableName); + + @InterceptorIgnore(tenantLine = "true") + Integer getShopGoodsTotalNum(@Param("tableName")String tableName); + + @InterceptorIgnore(tenantLine = "true") + Integer getShopGoodsTotalNumByTaskId(@Param("tableName") String tableName,@Param("taskId") Long taskId); + + + @InterceptorIgnore(tenantLine = "true") + List> batchCheckExists(String tableName, List batch); + + @InterceptorIgnore(tenantLine = "true") + Map selectTodayGoods(@Param("tableName") String tableName, @Param("todayStart") String todayStart, @Param("todayEnd") String todayEnd); + + List selectGetShopGoodsListAll(String tableName, String isOnsale, Long pageNum, Long pageSize); + + @InterceptorIgnore(tenantLine = "true") + Integer countAll(@Param("tableName")String tableName); + + /** + * 批量查询goods_id是否存在,返回存在的goods_id列表 + * @param tableName + * @param goodsIds + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List batchSelectExistsByGoodsIds(@Param("tableName") String tableName, @Param("goodsIds") List goodsIds); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningTaskMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningTaskMapper.java new file mode 100644 index 0000000..dd6b70e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/RunningTaskMapper.java @@ -0,0 +1,89 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.vo.RunningTaskNumVo; +import org.dromara.zhishu.domain.vo.RunningTaskVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; +import java.util.Map; + +/** + * 执行的任务Mapper接口 + * + * @author yxy + * @date 2025-07-23 + */ +public interface RunningTaskMapper { + + RunningTask selectById(Long id); + + /** + * 查看任务日志 + * @param taskId + * @return + */ + @InterceptorIgnore(tenantLine = "true") + List> selectLogByTaskId(Long taskId); + + + @InterceptorIgnore(tenantLine = "true") + List selectGetShopGoodsList(@Param("shopId")Long shopId,@Param("pageNum") Long pageNum,@Param("pageSize") Long pageSize); + + @InterceptorIgnore(tenantLine = "true") + Long selectGetShopGoodsNum(Long shopId); + + + @InterceptorIgnore(tenantLine = "true") + Map selectTaskStatus(); + + @InterceptorIgnore(tenantLine = "true") + List selectTaskAllNum(Long taskId); + + @InterceptorIgnore(tenantLine = "true") + Long selectTaskIsRunning(Long taskId); + + + @InterceptorIgnore(tenantLine = "true") + Long selectShopTaskByGetShopGoods(Long shopId); + + @InterceptorIgnore(tenantLine = "true") + Long selectTaskStatusByTaskType(@Param("shopId") Long shopId,@Param("taskType") String taskType); + + + @InterceptorIgnore(tenantLine = "true") + Long selectTaskStatusRunningCount(); + + @InterceptorIgnore(tenantLine = "true") + List selectTaskByGroupShopMd5(); + + @InterceptorIgnore(tenantLine = "true") + List selectTaskGroupShop(String taskType); + + + @InterceptorIgnore(tenantLine = "true") + List selectTaskShopNum(@Param("taskId") Long taskId,@Param("shopId") Long shopId); + + @InterceptorIgnore(tenantLine = "true") + int insert(RunningTask runningTask); + + /** + * 批量插入运行任务记录(如果需要也可以加上租户忽略) + * @param list 任务列表 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int batchInsert(List list); + + @InterceptorIgnore(tenantLine = "true") + int update(RunningTask runningTask); + + + @InterceptorIgnore(tenantLine = "true") + Boolean updataStatus(@Param("tableName") String tableName, @Param("taskId") Long shopId); + + @InterceptorIgnore(tenantLine = "true") + Long selectTaskStatusByTaskTypeAndIsbn(Long shopId, String taskType, String isbn); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopDepotMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopDepotMapper.java new file mode 100644 index 0000000..184496b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopDepotMapper.java @@ -0,0 +1,26 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.ShopDepot; + +import java.util.List; + +@Mapper +public interface ShopDepotMapper { + + /** + * 根据店铺ID查询绑定关系 + */ + List selectByShopId(Long shopId); + + /** + * 根据店铺ID删除绑定关系 + */ + int deleteByShopId(Long shopId); + + /** + * 插入绑定关系 + */ + int insertBatch(@Param("list") List shopDepots); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopDetailMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopDetailMapper.java new file mode 100644 index 0000000..72e6734 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopDetailMapper.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.ShopDetail; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 商品详情Mapper接口 + * + * @author yxy + * @date 2025-03-13 + */ +@Mapper +public interface ShopDetailMapper extends BaseMapperPlus { + + public ShopDetailVo selectVoByShopId(Long shopId); + + String getAutoAddByShopId(String shopId); + + String selectSaleTemplateIdByShopId(@Param("shopId") Long shopId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsMapper.java new file mode 100644 index 0000000..9fcbe1b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsMapper.java @@ -0,0 +1,235 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.dto.ShopGoodsDto; + +import java.util.List; +import java.util.Map; + +/** + * 商品信息Mapper接口 + */ +public interface ShopGoodsMapper { + + // ==================== 表管理 ==================== + + /** + * 检查表是否存在 + * @param tableName 表名 + * @return 存在数量 + */ + @InterceptorIgnore(tenantLine = "true") + int checkTableExists(@Param("tableName") String tableName); + + /** + * 创建表 + * @param tableName 表名 + */ + @InterceptorIgnore(tenantLine = "true") + void createTable(@Param("tableName") String tableName); + + // ==================== 插入操作 ==================== + + /** + * 插入单条数据 + * @param tableName 表名 + * @param shopGoods 商品信息 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int insert(@Param("tableName") String tableName, @Param("shopGoods") ShopGoodsDto shopGoods); + + /** + * 批量插入 + * @param tableName 表名 + * @param list 商品列表 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int batchInsert(@Param("tableName") String tableName, @Param("list") List list); + + // ==================== 删除操作 ==================== + + /** + * 根据ID删除 + * @param tableName 表名 + * @param id 主键ID + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteById(@Param("tableName") String tableName, @Param("id") Long id); + + /** + * 根据条件删除 + * @param tableName 表名 + * @param trilateralId 商品id + * @param isbn ISBN号 + * @param shopId 店铺id + * @param isOnSale 上下架状态 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteByCondition(@Param("tableName") String tableName, + @Param("trilateralId") String trilateralId, + @Param("isbn") String isbn, + @Param("shopId") String shopId, + @Param("isOnSale") String isOnSale); + + /** + * 批量删除 + * @param tableName 表名 + * @param ids ID列表 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int batchDeleteByIds(@Param("tableName") String tableName, @Param("ids") List ids); + + /** + * 删除所有数据 + * @param tableName 表名 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteAll(@Param("tableName") String tableName); + + // ==================== 更新操作 ==================== + + /** + * 根据ID更新 + * @param tableName 表名 + * @param shopGoods 商品信息 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int updateById(@Param("tableName") String tableName, @Param("shopGoods") ShopGoodsDto shopGoods); + + /** + * 更新上下架状态 + * @param tableName 表名 + * @param trilateralId 商品id + * @param isOnSale 上下架状态 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int updateOnSaleStatus(@Param("tableName") String tableName, + @Param("trilateralId") String trilateralId, + @Param("isOnSale") String isOnSale); + + /** + * 批量更新上下架状态 + * @param tableName 表名 + * @param trilateralIds 商品id列表 + * @param isOnSale 上下架状态 + * @return 影响行数 + */ + @InterceptorIgnore(tenantLine = "true") + int batchUpdateOnSaleStatus(@Param("tableName") String tableName, + @Param("trilateralIds") List trilateralIds, + @Param("isOnSale") String isOnSale); + + // ==================== 查询操作 ==================== + + /** + * 根据ID查询 + * @param tableName 表名 + * @param id 主键ID + * @return 商品信息 + */ + @InterceptorIgnore(tenantLine = "true") + ShopGoodsDto selectById(@Param("tableName") String tableName, @Param("id") Long id); + + /** + * 根据商品ID查询 + * @param tableName 表名 + * @param trilateralId 商品id + * @return 商品信息 + */ + @InterceptorIgnore(tenantLine = "true") + ShopGoodsDto selectByTrilateralId(@Param("tableName") String tableName, @Param("trilateralId") String trilateralId); + + /** + * 根据ISBN查询列表 + * @param tableName 表名 + * @param isbn ISBN号 + * @return 商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByIsbn(@Param("tableName") String tableName, @Param("isbn") String isbn); + + /** + * 根据店铺ID查询列表 + * @param tableName 表名 + * @param shopId 店铺id + * @return 商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByShopId(@Param("tableName") String tableName, @Param("shopId") String shopId); + + /** + * 分页条件查询 + * @param tableName 表名 + * @return 商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByCondition(@Param("tableName") String tableName,@Param("shopGoodsDto") ShopGoodsDto shopGoodsDto); + + /** + * 条件查询总数 + * @param tableName 表名 + * @return 总数 + */ + @InterceptorIgnore(tenantLine = "true") + int selectCountByCondition(@Param("tableName") String tableName,@Param("shopGoodsDto") ShopGoodsDto shopGoodsDto); + + /** + * 查询所有商品 + * @param tableName 表名 + * @return 商品列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectAll(@Param("tableName") String tableName); + + /** + * 统计在售商品数量 + * @param tableName 表名 + * @return 在售商品数量 + */ + @InterceptorIgnore(tenantLine = "true") + int countOnSale(@Param("tableName") String tableName); + + /** + * 统计总记录数 + * @param tableName 表名 + * @return 总记录数 + */ + @InterceptorIgnore(tenantLine = "true") + int countAll(@Param("tableName") String tableName); + + /** + * 根据商品编码查询 + * @param tableName 表名 + * @param goodsCode 商品编码 + * @return 商品信息 + */ + @InterceptorIgnore(tenantLine = "true") + ShopGoodsDto selectByGoodsCode(@Param("tableName") String tableName, @Param("goodsCode") String goodsCode); + + /** + * 根据SKU编码查询 + * @param tableName 表名 + * @param skuCode sku编号 + * @return 商品信息 + */ + @InterceptorIgnore(tenantLine = "true") + ShopGoodsDto selectBySkuCode(@Param("tableName") String tableName, @Param("skuCode") String skuCode); + + /** + * 批量查询是否存在 + * @param tableName 表名 + * @param trilateralIds 商品id列表 + * @return 存在映射 + */ + @InterceptorIgnore(tenantLine = "true") + List> batchCheckExists(@Param("tableName") String tableName, @Param("trilateralIds") List trilateralIds); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsPublishedLogMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsPublishedLogMapper.java new file mode 100644 index 0000000..144114d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsPublishedLogMapper.java @@ -0,0 +1,13 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; + +import java.util.List; + +@Mapper +public interface ShopGoodsPublishedLogMapper extends BaseMapper { + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsPublishedMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsPublishedMapper.java new file mode 100644 index 0000000..eaf34b6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsPublishedMapper.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +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.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.zhishu.domain.ShopGoodsPublished; +import org.dromara.zhishu.domain.bo.ShopGoodsPublishedBo; +import org.dromara.zhishu.domain.vo.PlatformIdUpdateVO; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; +import java.util.Map; + +/** + * 记录已发布书籍Mapper接口 + * + * @author yxy + * @date 2025-04-11 + */ +@Mapper +public interface ShopGoodsPublishedMapper extends BaseMapperPlus { + + + /** + * 根据shop_goods_id批量查询 + * @param shopGoodsIds 商品ID列表 + * @return 查询结果列表 + */ + List selectByShopGoodsIds(@Param("shopGoodsIds") List shopGoodsIds,@Param("shopId") Long shopId); + + + List selectListByShopsId(Long shopId); + + List selectShopGoodsPublishedByShopIdAndArtNo(@Param("shopId") Long shopId,@Param("artNo") String artNo); + + ShopGoodsPublishedVo selectDataById(Long id); + + + Page selectDataList(@Param("page") Page page,@Param("bo") ShopGoodsPublishedBo bo); + + Boolean delShopGoodsPublished(@Param("shopId") String shopId,@Param("platformId") String platformId); + + Boolean delByIds(Long id); + + Boolean delByShopId(Long shopId); + + /** + * 批量查询商品发布状态 + * + * @param goodsIds 商品ID列表 + * @param shopIds 店铺ID列表 + * @return 商品ID和发布状态的映射 + */ + List> selectPublishedStatus(@Param("goodsIds") List goodsIds, @Param("shopIds") List shopIds); + + List getPlatFormIdsByShopId( @Param("shopId") Long shopId); + + void batchUpdateKfzPlatformId(@Param("platformIdUpdateVOList") List platformIdUpdateVOList); + + ShopGoodsPublishedVo selectDataByPlatformId(@Param("platformId")Long platformId ,@Param("shopId")Long shopId); + + void batchDeleteByIds(List ids); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsRejectionMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsRejectionMapper.java new file mode 100644 index 0000000..6589328 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopGoodsRejectionMapper.java @@ -0,0 +1,60 @@ +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.*; +import org.dromara.zhishu.domain.ShopGoodsPublished; +import org.dromara.zhishu.domain.ShopGoodsRejection; +import org.dromara.zhishu.domain.bo.ShopGoodsPublishedBo; + +import java.util.List; + +@Mapper +public interface ShopGoodsRejectionMapper extends BaseMapper { + + + // 插入数据 + @Insert("INSERT INTO shop_goods_rejection (shop_goods_id, shop_id, platform_id, create_time, rejection_reason,tenant_id,isbn,platform_type,shop_goods_img,goods_type,offshelf_time,sync_flag) " + + "VALUES (#{shopGoodsId}, #{shopId}, #{platformId}, #{createTime}, #{rejectionReason},#{tenantId},#{isbn},#{platformType},#{shopGoodsImg},#{goodsType},#{offshelfTime},#{syncFlag} )") + @Options(useGeneratedKeys = true, keyProperty = "id") + int insert(ShopGoodsRejection shopGoodsRejection); + + // 根据ID删除 + @Delete("DELETE FROM shop_goods_rejection WHERE id = #{id}") + int deleteById(Long id); + + // 根据ID更新 + @Update("UPDATE shop_goods_rejection SET " + + "shop_goods_id = #{shopGoodsId}, " + + "shop_id = #{shopId}, " + + "platform_id = #{platformId}, " + + "rejection_reason = #{rejectionReason} " + + "WHERE id = #{id}") + int update(ShopGoodsRejection shopGoodsRejection); + + // 根据ID查询 + @Select("SELECT * FROM shop_goods_rejection WHERE id = #{id}") + ShopGoodsRejection selectById(Long id); + + // 查询所有 + @Select("SELECT * FROM shop_goods_rejection ORDER BY create_time DESC") + List selectAll(); + + // 根据店铺ID查询 + @Select("SELECT * FROM shop_goods_rejection WHERE shop_id = #{shopId} ORDER BY create_time DESC") + List selectByShopId(String shopId); + + // 根据平台商品ID查询 + @Select("SELECT * FROM shop_goods_rejection WHERE platform_id = #{platformId} ORDER BY create_time DESC") + List selectByPlatformId(String platformId); + + // 动态查询(使用XML配置) + List selectByCondition(ShopGoodsRejection condition); + + // 分页查询 + public Page selectByConditionWithPage(@Param("page") Page page, @Param("bo") ShopGoodsRejection bo); + + // 统计总数 + int countByCondition(ShopGoodsRejection condition); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopImgMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopImgMapper.java new file mode 100644 index 0000000..d9b9503 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopImgMapper.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.ShopImg; +import org.dromara.zhishu.domain.vo.ShopImgVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 店铺图片Mapper接口 + * + * @author yxy + * @date 2025-03-17 + */ +@Mapper +public interface ShopImgMapper extends BaseMapperPlus { + + List selectVoByShopId(String pid); + + int deleteByPidAndType(@Param("pid") String pid,@Param("type") String type); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopWarehouseAutoMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopWarehouseAutoMapper.java new file mode 100644 index 0000000..36e11c0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopWarehouseAutoMapper.java @@ -0,0 +1,58 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.ShopWarehouseAuto; + +import java.util.List; + +/** + * 店铺与仓库自动发布关联Mapper接口 + * + * @author yxy + * @date 2025-12-28 + */ +@Mapper +public interface ShopWarehouseAutoMapper { + + /** + * 根据店铺ID删除关联 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteByShopId(Long shopId); + + + @InterceptorIgnore(tenantLine = "true") + List selectList(ShopWarehouseAuto shopWarehouse); + + /** + * 根据店铺ID查询关联列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByShopId(Long shopId); + + /** + * 新增店铺与仓库关联 + */ + @InterceptorIgnore(tenantLine = "true") + int insert(ShopWarehouseAuto shopWarehouse); + + + /** + * 根据ID查询关联 + */ + @InterceptorIgnore(tenantLine = "true") + ShopWarehouseAuto selectById(Long id); + + /** + * 根据ID删除关联 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteById(Long id); + + /** + * 更新关联信息 + */ + @InterceptorIgnore(tenantLine = "true") + int update(ShopWarehouseAuto shopWarehouse); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopWarehouseMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopWarehouseMapper.java new file mode 100644 index 0000000..ffabf0f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ShopWarehouseMapper.java @@ -0,0 +1,55 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.zhishu.domain.ShopWarehouse; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 店铺与仓库自动发布关联Mapper接口 + * + * @author yxy + * @date 2025-12-28 + */ +@Mapper +public interface ShopWarehouseMapper { + + /** + * 根据店铺ID删除关联 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteByShopId(Long shopId); + + /** + * 根据店铺ID查询关联列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByShopId(Long shopId); + + /** + * 新增店铺与仓库关联 + */ + @InterceptorIgnore(tenantLine = "true") + int insert(ShopWarehouse shopWarehouse); + + + /** + * 根据ID查询关联 + */ + @InterceptorIgnore(tenantLine = "true") + ShopWarehouse selectById(Long id); + + /** + * 根据ID删除关联 + */ + @InterceptorIgnore(tenantLine = "true") + int deleteById(Long id); + + /** + * 更新关联信息 + */ + @InterceptorIgnore(tenantLine = "true") + int update(ShopWarehouse shopWarehouse); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/SpecMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/SpecMapper.java new file mode 100644 index 0000000..04ffcc1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/SpecMapper.java @@ -0,0 +1,19 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.Spec; +import org.dromara.zhishu.domain.vo.SpecVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 自定义规格设置Mapper接口 + * + * @author yxy + * @date 2025-03-27 + */ +@Mapper +public interface SpecMapper extends BaseMapperPlus { + + public SpecVo selectVoByShopId(Long shopId); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TAuditMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TAuditMapper.java new file mode 100644 index 0000000..f2a0a61 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TAuditMapper.java @@ -0,0 +1,43 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.zhishu.domain.NewUserInfo; +import org.dromara.zhishu.domain.TAudit; +import org.dromara.zhishu.domain.bo.TAuditBo; +import org.dromara.zhishu.domain.vo.TAuditVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.Collection; + +/** + * 审核Mapper接口 + * + * @author Lion Li + * @date 2025-04-01 + */ +@Mapper +public interface TAuditMapper extends BaseMapperPlus { + + NewUserInfo selectUserList(Long id); + + void updateByUser(NewUserInfo newUserInfo); + + void deleteUser(Collection ids); + + String selectUserName(Long userId); + + int updateStatus(TAuditBo bo); + + Long selectUserId(Long id); + + Integer insertUserRole(Long userId, long l); + + Integer insertAuditLog(TAuditBo bo); + + Integer deleteUserRole(Long userId, long l); + + Page selectPageVo(Page build, TAuditBo bo); + + TAudit selectId(Long id); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TFreightMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TFreightMapper.java new file mode 100644 index 0000000..bbc2e7f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TFreightMapper.java @@ -0,0 +1,79 @@ +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.apache.ibatis.annotations.Select; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TFreight; +import org.dromara.zhishu.domain.bo.TFreightBo; +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; + +/** + * 三级货区管理Mapper接口 + * + * @author Lion Li + * @date 2025-04-19 + */ +@Mapper +public interface TFreightMapper extends BaseMapperPlus { + + @Select("select id from t_freight where code = #{freightName} AND shelves_id = #{shelvesId}") + Long getFreightIdByName(String freightName, Long shelvesId); + + /** + * 根据三级获取名称获取获取信息 + * @param freightName + * @param shelvesId + * @return + */ + TFreightVo selectByFreightName(@Param("freightName") String freightName,@Param("shelvesId") Long shelvesId); + + + List selectDepotId(Long userId); + + List selectByList(List depotIdList); + + String setShelvesName(Long id); + + List selectByShelvesId(Long shelvesId); + + Map selectByFreightId(Long freightId); +// List selectCode(Collection ids); + +// Integer selectByCount2(Long userId,String code); + +// Integer selectByCount1(Long userId,String code); + + + String selectByCode(Long shelvesId); + + Integer selectFreName(String name, Long shelvesId,String code); + + List selectV(Long userId); + + List selectShe(List depotids); + + Page selectVo(Page build, TFreightBo bo, List sheIds); + + int insertFre(TFreight add); + + List selectVoLists(List sheIds); + + int updateBydate(TFreight update); + + TFreight selectSheName(Long id); + + TShelvesVo setShelvesName1(Long id); + + String selectDepotCode(String depotId); + + List selectListVo(Collection ids,Long userId); + + Integer selectByExcludeCurrent(String name, Long shelvesId, Long freightId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteCodeMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteCodeMapper.java new file mode 100644 index 0000000..a39a4b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteCodeMapper.java @@ -0,0 +1,54 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.TInviteCode; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.vo.InviteCodeVo; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.List; + +/** + * 邀请码 Mapper 接口 + */ +@Mapper +public interface TInviteCodeMapper extends BaseMapper { + + /** + * 验证邀请码有效性 + * + * @param code 邀请码 + * @return 邀请码信息 + */ + TInviteCode validateInviteCode(@Param("code") String code); + + /** + * 根据用户ID查询邀请码列表 + * + * @param userId 用户ID + * @return 邀请码列表 + */ + List selectListByUserId(@Param("userId") Long userId); + + /** + * 生成邀请码 + * + * @param bo 邀请码业务对象 + * @return 插入成功的行数 + */ + int insertGenerateInviteCode(TInviteCode bo); + + /** + * 自定义分页查询邀请码列表 + * + * @param page 分页参数 + * @param userId 用户ID + * @param code 邀请码 + * @param used 是否已使用 + * @return 邀请码列表 + */ + Page selectPageList(Page page, @Param("userId") Long userId, + @Param("code") String code, @Param("used") Boolean used); + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteRelationMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteRelationMapper.java new file mode 100644 index 0000000..1e18f21 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteRelationMapper.java @@ -0,0 +1,10 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.TInviteRelation; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 邀请关系 Mapper 接口 + */ +public interface TInviteRelationMapper extends BaseMapper { +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteRelationsMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteRelationsMapper.java new file mode 100644 index 0000000..d67d7d0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TInviteRelationsMapper.java @@ -0,0 +1,19 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.TInviteRelations; +import java.util.List; + +@Mapper +public interface TInviteRelationsMapper { + + /** + * 根据邀请人ID查询邀请关系 + * + * @param inviterId 邀请人ID + * @return 邀请关系列表 + */ + @InterceptorIgnore(tenantLine = "true") + List selectByInviterId(Long inviterId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TLogisticsMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TLogisticsMapper.java new file mode 100644 index 0000000..5dbe789 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TLogisticsMapper.java @@ -0,0 +1,45 @@ +package org.dromara.zhishu.mapper; + + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TLogistics; +import org.dromara.zhishu.domain.bo.TLogisticsBo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TLogisticsVo; +import org.springframework.data.repository.query.Param; + +import java.util.Collection; +import java.util.List; + +/** + * 物流管理Mapper接口 + * + * @author Lion Li + * @date 2025-04-22 + */ +@Mapper +public interface TLogisticsMapper extends BaseMapperPlus { + + TDepotVo selectDepotName(Long depotId); + + Page selectPageVo(@Param("page") Page build, @Param("bo") TLogisticsBo bo); + + TLogisticsVo selectByLId(Long id); + + List nameList(List depotIds); + + String selectByArea(String deliveryArea, String deliveryCity); + + String selectByCity(String deliveryCity, String deliveryProvince); + + String selectByProvince(String deliveryProvince); + + int deleteIds(Collection ids); + + List selectDepotId(Long userId); + + + List selectUserId(Long userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShelvesMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShelvesMapper.java new file mode 100644 index 0000000..8e9e73f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TShelvesMapper.java @@ -0,0 +1,97 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TFreight; +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.springframework.data.repository.query.Param; + +import java.util.Collection; +import java.util.List; + +/** + * 货架信息Mapper接口 + * + * @author Lion Li + * @date 2025-03-26 + */ +@Mapper +public interface TShelvesMapper extends BaseMapperPlus { + +// @Select("select count(1) from t_shelves where code=#{code} and depot_id=#{depotId}") + Integer selectByCode(String code, Long depotId, String sheName); + + String selectByName(Long shelvesId,Long userId); + + +// @Update("update t_shelves set depot_id=#{depotId} where id=#{id};") + Integer updateByShe(Long id, Long depotId); + + Integer insertFre(@Param("id") Long id,@Param("numbers1") List numbers1); + +// @Update("update t_depot set she_quantity_max=she_quantity_max+#{sheCap} where id=#{depotId} and user_id=#{userId}") +// void updateSheFre(Long depotId, Long userId); + + String selectBySCode(Long depotId); + + String selectByFreCode(Long freId);//查询货位code + + String selectFreCode(String depotCode, Long userId); + + + void deleteByIdShe(Collection ids); + + Page selectVo(@Param("build") Page build,@Param("bo") TShelvesBo bo,@Param("depotids") List depotids); + + List selectV(Long userId); + + List selectM(Long userId); + + int insertBo(TShelves add); + + List selectList1(Long userId); + + + int updateShe(TShelves update); + + Integer selectNumber(Long depotId); + + Integer selectcount(Long depotId); + + + Long selectBo(Long depotId, String code); + +// List selectByCodes(Collection ids); + + Integer selectCounts(Long userId, String code); + + String selectSCode(Long sheId); + + Integer selectCounts1(Long userId, String code); + + List selectFList(Long userId); + + String selectDName(Long depotId,Long userId); + + String selectDepotName(String depotId); + + TDepotVo selectByName1(Long id, Long userId); + + TDepotVo selectDepot(String depotId); + + List selectListVo(Collection ids, Long userId); + + List selectShelvesIdByDepotIdAndCode(String depotId, String code); + + List selectShelvesByDepotId(String depotId); + + Long selectDepotIdByShelvesId(Long shelvesId); + + TShelvesVo selectForLocal(Long depotId, String code); + + Integer selectByExcludeCurrent(String name, Long depotId, Long shelvesId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TaskMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TaskMapper.java new file mode 100644 index 0000000..dcfd32b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/TaskMapper.java @@ -0,0 +1,55 @@ +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.apache.ibatis.annotations.Param; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.TaskVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 任务列表Mapper接口 + * + * @author yxy + * @date 2025-03-21 + */ +@Mapper +public interface TaskMapper extends BaseMapperPlus { + + @Override + @DataPermission({ + @DataColumn(key = "userName", value = "create_by") + }) + default

> P selectVoPage(IPage page, Wrapper wrapper) { + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + List selectByShopId(Long userId); + + TaskVo selectByFileName(String fileName); + + List selectRunningTask(@Param("pageSize") Integer pageSize,@Param("pageNum") Integer pageNum); + + int selectRunningTaskCount(); + + void editTaskDataNum(@Param("shopIds")String shopIds, @Param("dataNum")Long dataNum, @Param("taskType") String taskType); + + Task getTaskBoByRelationId(String id); + + /** + * 批量查询店铺基本信息 + */ + List selectShopsByIds(@Param("ids") List ids); + + /** + * 批量查询店铺详情信息 + */ + List selectShopDetailsByIds(@Param("ids") List ids); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserRechargeMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserRechargeMapper.java new file mode 100644 index 0000000..10edb9c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserRechargeMapper.java @@ -0,0 +1,42 @@ +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.UserRecharge; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.UserRechargeVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 用户充值Mapper接口 + * + * @author yxy + * @date 2025-04-26 + */ +@Mapper +public interface UserRechargeMapper extends BaseMapperPlus { + + + @Override + @DataPermission({ + @DataColumn(key = "userName", value = "create_by") + }) + default

> P selectVoPage(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()); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserTAuditMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserTAuditMapper.java new file mode 100644 index 0000000..5b99d5e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/UserTAuditMapper.java @@ -0,0 +1,44 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.NewUserInfo; +import org.dromara.zhishu.domain.UserTAudit; +import org.dromara.zhishu.domain.bo.UserTAuditBo; +import org.dromara.zhishu.domain.vo.UserTAuditVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.springframework.data.repository.query.Param; + +import java.util.Collection; + +/** + * 列表Mapper接口 + * + * @author Lion Li + * @date 2025-04-02 + */ +@Mapper +public interface UserTAuditMapper extends BaseMapperPlus { + NewUserInfo selectUserList(Long id); + String selectUserName(Long userId); + + Long selectId(Long userId); + + Page customPageList(@Param("page") Page page, @Param("bo") UserTAuditBo bo); + + NewUserInfo selectU(Long id); + + UserTAuditVo selectM(Long auditId); + + String selectStatus(Long id); + + Boolean updateUserId(UserTAudit update); + + Long selectAudit(Collection ids); + + Integer deleteAudit(Long auditId); + + Long deleteByAudit(Collection ids); + + UserTAuditVo getAuditLog(Long message); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ViolationMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ViolationMapper.java new file mode 100644 index 0000000..491d949 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ViolationMapper.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.Violation; +import org.dromara.zhishu.domain.vo.ViolationVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 违规Mapper接口 + * + * @author yxy + * @date 2025-06-23 + */ +public interface ViolationMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WaveMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WaveMapper.java new file mode 100644 index 0000000..fd50667 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WaveMapper.java @@ -0,0 +1,19 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.zhishu.domain.vo.WaveVo; +import java.util.List; + +@Mapper +public interface WaveMapper { + + @InterceptorIgnore(tenantLine = "true") + String getStaffName(String staffId); + + @InterceptorIgnore(tenantLine = "true") + List getStaffId(); + + @InterceptorIgnore(tenantLine = "true") + List getStaffList(String userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WhiteListMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WhiteListMapper.java new file mode 100644 index 0000000..f716f7d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/WhiteListMapper.java @@ -0,0 +1,22 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.WhiteList; +import org.dromara.zhishu.domain.vo.WhiteListVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +import java.util.List; + +/** + * 白名单Mapper接口 + * + * @author yxy + * @date 2025-06-25 + */ +public interface WhiteListMapper extends BaseMapperPlus { + + List selectAll(); + + List selectByIp(String ip); + + void deleteAll(); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/XyBindMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/XyBindMapper.java new file mode 100644 index 0000000..be123f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/XyBindMapper.java @@ -0,0 +1,12 @@ +package org.dromara.zhishu.mapper; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.XyBind; +import org.dromara.zhishu.domain.vo.XyBindVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +@Mapper +public interface XyBindMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopGoodsDetailMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopGoodsDetailMapper.java new file mode 100644 index 0000000..fbbe4ca --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopGoodsDetailMapper.java @@ -0,0 +1,16 @@ +package org.dromara.zhishu.mapper; + +import org.dromara.zhishu.domain.ZhishuShopGoodsDetail; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsDetailVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; + +/** + * 商品信息补全表Mapper接口 + * + * @author yxy + * @date 2025-06-13 + */ +public interface ZhishuShopGoodsDetailMapper extends BaseMapperPlus { + + ZhishuShopGoodsDetailVo selectByPid(Long pid); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopGoodsMapper.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopGoodsMapper.java new file mode 100644 index 0000000..c1d7e1f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/mapper/ZhishuShopGoodsMapper.java @@ -0,0 +1,191 @@ +package org.dromara.zhishu.mapper; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.zhishu.domain.TFreight; +import org.dromara.zhishu.domain.TShelves; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.ZhishuShopImages; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; +import org.dromara.zhishu.domain.vo.*; +import org.springframework.data.repository.query.Param; + +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 商品信息Mapper接口 + * + * @author Lion Li + * @date 2025-03-07 + */ +@Mapper +public interface ZhishuShopGoodsMapper extends BaseMapperPlus { + + /** + * 批量查询商品根据id + * @param ids + * @return + */ + List selectByIds(List ids); + + List selectShopGoodsByIsbn(String isbn); + + ZhishuShopGoodsVo selectShopGoodsByItemNumbers(String itemNumber); + + ZhishuShopGoodsVo selectShopGoodsByArtNo(String artNo); + + + ZhishuShopGoodsVo selectShopGoodsByItemNumber1(ZhishuShopGoods zhishuShopGoods); + + + ZhishuShopGoods selectInventory(String barcode, String letterCode); + + void updateArtNo(String firstChar, String secondChar, String thirdChar, String artNo); + + Integer selectDepot(Long userId); + + List selectAll(Long userId); + + Integer updateByProduct(ZhishuShopGoods zhishuShopGoods); + + List selectSheCount(Long depotId); + + List selectFreCount(Long sheId); + + void insertTask(Long depotId, String filename, int count, Long userId); + + ZhishuShopGoods selectPriceByIsbnAndConditionCode(String barcode, String letterCode, Long price); + + ZhishuShopGoods selectartNoByIsbnAndConditionCodeAndArtNo(String barcode, String letterCode, String artNo, Long price, Long userId); + + long selectArtNo(String artNo, Long userId); + + long selectCodeByCodeAndIsbn(String barcode, String letterCode, Long userId); + + long selectUserId(Long userId); + + long selectIsbnCount(Long userId, String barcode); + + /** + * 查询是否存在 + * + * @param isbn ISBN + * @param artNo 货号 + * @param userId 用户id + * @param letterCode 品相 + * @param price 价格 + * @return + */ + long selectCountByIsbnAndArtNoAndUserIdAndBarcode(String isbn, String artNo, String userId, String letterCode, String price); + + void updateShop(ZhishuShopGoods existingGoods); + + void updateInventory(long newInventory, Long userId, String letterCode, String artNo, long price, String barcode); + + Long findBookMsgByISBN(ZhishuShopGoods zhishuShopGoods); + + Integer setExamineBook(ZhishuShopGoods zhishuShopGoods); + + Integer selectGoods(ZhishuShopGoods add); + + List selectFreCount1(@Param("sheCount") List sheCount); + +// void updateBook(ZhishuShopGoods add); + + String selectShopId(String userId, String barcode, String name); + + List selectBySId(Long id); + + List selectShopGoodsByUser(Long userId); + + List selectFreightGoodsNumber(@Param("userId") Long userId, @Param("freightIdList") List freightIdList); + + TDepotVo selectDepotName(Long userId, String depotCode); + + Integer deleteByIds1(Collection ids); + + ZhishuShopGoodsVo selectByIdVo(String id); + + Integer deleteIds(Collection ids); + + String selectArtNoCount(String artNo, Long price); + + String queryByShopId(String shopId); + +// Long selectArtNoCount1(String artNo,Long price); + + Map batchQueryPathByShopIds(List shopIds); + + String selectByBookPic(String id); + + Long selectArtNoCount1(String artNo, Long price, String letterCode); + + void delPubGood(String id); + + Integer selectPubCount(String id); + + Integer insertInventory(@Param("update") ZhishuShopGoods update,@Param("inventory") Long inventory); + + List selectStockLog(String id); + + Page selectShopGoodsByUserPage(Page page, Long userId); + + Page selectShopGoodsByUserPageWithDate( + @Param("page") Page page, + @Param("userId") Long userId, + @Param("startDate") Date startDate, + @Param("endDate") Date endDate + ); + + Long selectDepotIds(String artNo); + + Long selectSheId(Long depotId, String letterCode); + + Long selectFreId(Long sheId, String thirdChar); + + Map selectArt(@Param("userId") String userId,@Param("dcode") String dcode,@Param("scode") String scode,@Param("fcode") String fcode); + + Boolean updateChunkInventory(ZhishuShopGoods update); + + List selectImages(); + + String getSelectArtNo(Long deId, Long shId, Long frId, Long userId); + + Integer batchUpdateartNo(@Param("deId") Long deId,@Param("beartNo") String beartNo,@Param("ids") List ids); + + Page selectShopGoodsByUserPageWithDateArtNo( + @Param("page") Page page, + @Param("userId") Long userId, + @Param("startDate") Date startDate, + @Param("endDate") Date endDate, + @Param("code") String code + ); + + Page selectShopGoodsByUserPageArtNo(Page page, Long userId, String code); + + List selectAllArtNo(Long userId); + + List selectSheCounts(@Param("depotCount")List depotVos); + + Long getTaskDataNum(Long taskId); + + boolean updateByArtNo(ZhishuShopGoodsBo updateBo); + + int updateByArtNoPrefix(@Param("isJoinDistribution") String isJoinDistribution,@Param("artNoPrefix") String artNoPrefix,@Param("userId") Long userId,@Param("limitNum") Long limitNum); + +// @Select("select * from zhishu_shop_goods where isbn = #{barcode} AND condition_code = #{conditionCode}") +// ZhishuShopGoods selectInventory(String barcode, letterCode); + + int selectArtNobyartNo(String artNo, Long userId); + + ZhishuShopGoodsVo selectShopGoodsByShopIdAndPlatformId(@Param("shopId") String shopId,@Param("platformId") String platformId); + + ZhishuShopGoodsVo selectShopGoodsByArtNoAndUserId(@Param("artNo") String artNo,@Param("userId") Long userId); + + ZhishuShopGoodsVo selectShopGoodsByProductId(@Param("productId") String productId,@Param("userId") Long userId); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/CountService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/CountService.java new file mode 100644 index 0000000..6cb41f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/CountService.java @@ -0,0 +1,7 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.Statistic; + +public interface CountService { + Statistic selectStatistic(); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/EmployeeService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/EmployeeService.java new file mode 100644 index 0000000..3b77484 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/EmployeeService.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.EmployeeVo; +import java.util.List; + +public interface EmployeeService { + + List getEmployeeList(String userId); + + Boolean addEmployee(String employeeId, String employeeName, String userId); + + Boolean updateEmployee(String id, String employeeName, String userId); + + Boolean delEmployee(String id, String userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IAccountService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IAccountService.java new file mode 100644 index 0000000..601bf02 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IAccountService.java @@ -0,0 +1,18 @@ +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.Account; + +public interface IAccountService { + + /** + * 分页查询分润日志表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return + */ + TableDataInfo queryPageList(Account bo, PageQuery pageQuery); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IArtNoMoveService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IArtNoMoveService.java new file mode 100644 index 0000000..45419fd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IArtNoMoveService.java @@ -0,0 +1,4 @@ +package org.dromara.zhishu.service; + +public interface IArtNoMoveService { +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IBookBaseInfoService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IBookBaseInfoService.java new file mode 100644 index 0000000..758c12c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IBookBaseInfoService.java @@ -0,0 +1,136 @@ +package org.dromara.zhishu.service; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.bo.*; +import org.dromara.zhishu.domain.dto.BookBaseInfoDto; +import org.dromara.zhishu.domain.excel.BaseInfoExcel; +import org.dromara.zhishu.domain.vo.BaseInfoPricingVo; +import org.dromara.zhishu.domain.vo.BookBaseInfoVo; +import org.dromara.zhishu.domain.vo.TaskUrlVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 基础信息Service接口 + * + * @author Lion Li + * @date 2025-03-08 + */ +public interface IBookBaseInfoService { + + /** + * 查询基础信息 + * + * @param id 主键 + * @return 基础信息 + */ + BookBaseInfoVo queryById(String id); + + + /** + * 分页查询基础信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 基础信息分页列表 + */ + TableDataInfo queryPageList(BookBaseInfoDto bo, BookNumberRageBo number, PageQuery pageQuery); + + /** + * 查询符合条件的基础信息列表 + * + * @param bo 查询条件 + * @return 基础信息列表 + */ + List queryList(BookBaseInfoBo bo); + + /** + * 新增基础信息 + * + * @param bo 基础信息 + * @return 是否新增成功 + */ + Boolean insertByBo(BookBaseInfoBo bo); + + /** + * 修改基础信息 + * + * @param bo 基础信息 + * @return 是否修改成功 + */ + Boolean updateByBo(EditBookInfoBo bo); + + Boolean updateByIsbn(BookBaseInfoBo bo); + + /** + * 校验并批量删除基础信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + /** + * 校验并批量删除基础信息信息 + * + + * @return 是否删除成功 + */ + void importExcel( List list); + + /** + * 校验并批量删除基础信息信息 + * + + * @return 是否删除成功 + */ + Map getList( ); + + BookBaseInfoVo getIsbnInfo(String isbn); + + BookBaseInfoVo getIsbnList(String isbn); + + List getBookListByBookName(String bookName); + + List selectBookPicList(); + + List queryBookPicList(BookBaseInfoBo bo); + + String getpamp(BookBaseInfoBo bo, BookNumberRageBo number, BookBaseInfoDto dto, String page, String per_page); + + int delectByIsbn(String isbn); + + int updateByIllge(IllBaseInfoBo bo); + + TableDataInfo queryPagePricingList(BookBaseInfoDto bo, BookNumberRageBo number, PageQuery pageQuery); + + String pricingLink(BookBaseInfoBo bo, PageQuery pageQuery); + + Map pricingLinkDec(String link); + + Boolean getUserVip(Integer type); + + Map insertTask(TaskBo bo); + + int addNewTask(Task task); + + Map setBalance(); + + void insertUserInfo(UserRechargeBo bo,String title,Integer payType,Integer price); + + Map getImageDite(Long isbn); + + BookBaseInfoVo getBookByIsbn(@NotNull(message = "主键不能为空") String isbn); + + BookBaseInfoVo getBookData(@NotNull(message = "主键不能为空") String isbn); + + TableDataInfo getBookDataByIsbn(String isbn); + + Boolean updateCentBookByIsbn(BookUpdateInfoBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ICourierLogService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ICourierLogService.java new file mode 100644 index 0000000..9e99f6e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ICourierLogService.java @@ -0,0 +1,54 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.CourierLog; +import org.dromara.zhishu.domain.vo.CourierLogVo; +import org.dromara.zhishu.domain.bo.CourierLogBo; +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-18 + */ +public interface ICourierLogService { + + /** + * 查询快递日志 + * + * @param id 主键 + * @return 快递日志 + */ + CourierLogVo queryById(Long id); + + /** + * 分页查询快递日志列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 快递日志分页列表 + */ + TableDataInfo queryPageList(CourierLogBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的快递日志列表 + * + * @param bo 查询条件 + * @return 快递日志列表 + */ + List queryList(CourierLogBo bo); + + + /** + * 校验并批量删除快递日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IFilterSetService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IFilterSetService.java new file mode 100644 index 0000000..877904a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IFilterSetService.java @@ -0,0 +1,76 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.FilterSetVo; +import org.dromara.zhishu.domain.bo.FilterSetBo; +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-04-14 + */ +public interface IFilterSetService { + + /** + * 查询过滤设置 + * + * @param id 主键 + * @return 过滤设置 + */ + FilterSetVo queryById(Long id); + + /** + * 分页查询过滤设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 过滤设置分页列表 + */ + TableDataInfo queryPageList(FilterSetBo bo, PageQuery pageQuery); + + /** + * 查询过滤库 + * @return + */ + List selectVoListByBo(FilterSetBo bo); + + int deleteTrueById(Long id); + + /** + * 查询符合条件的过滤设置列表 + * + * @param bo 查询条件 + * @return 过滤设置列表 + */ + List queryList(FilterSetBo bo); + + /** + * 新增过滤设置 + * + * @param bo 过滤设置 + * @return 是否新增成功 + */ + Boolean insertByBo(FilterSetBo bo); + + /** + * 修改过滤设置 + * + * @param bo 过滤设置 + * @return 是否修改成功 + */ + Boolean updateByBo(FilterSetBo 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/IGoofishService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IGoofishService.java new file mode 100644 index 0000000..870cfeb --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IGoofishService.java @@ -0,0 +1,25 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.vo.ShopVo; + +/** + * Pdd接口Service + * + * @author yxy + * @date 2025-05-8 + */ +public interface IGoofishService { + + + void goodAdd(ShopVo shop, ZhishuShopGoods zhishuShopGoods, ShopDetailVo vo); + + /** + * 修改商品库存接口 + * itemId 闲鱼 + * number 库存 + */ + void goodUpdateStock(ShopVo shop, String itemId, String number, Integer type); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IOrderExternalGoodsService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IOrderExternalGoodsService.java new file mode 100644 index 0000000..3f98c66 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IOrderExternalGoodsService.java @@ -0,0 +1,42 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.vo.FastMailVo; + +import java.util.Map; + +public interface IOrderExternalGoodsService { + + + /** + * 获取韵达快递单的pdf + * @return + */ + R getYundaPdf(FastMailVo fastMailVo, String erpOrderId, String printTemplateData, String type, String deliveryMode, String orderSn); + + + /** + * 获取中通快递单PDF + * @param fastMailVo + * @param erpOrderId + * @param printTemplateData + * @param type + * @param deliveryMode + * @param orderSn + * @return + */ + R getZtoPdf(FastMailVo fastMailVo, String erpOrderId, String printTemplateData, String type, String deliveryMode, String orderSn); + + + /** + * 创建快递单并获取快递单信息 + * @param fastMailVo + * @param erpOrderId + * @param printTemplateData + * @param type + * @param deliveryMode + * @param orderS + * @return + */ + R orderCreate(FastMailVo fastMailVo, String erpOrderId, String printTemplateData, String type, String deliveryMode, String orderSn); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPddService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPddService.java new file mode 100644 index 0000000..94fde98 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPddService.java @@ -0,0 +1,99 @@ +package org.dromara.zhishu.service; + +import com.pdd.pop.sdk.http.api.pop.response.PddGoodsCatRuleGetResponse; +import com.pdd.pop.sdk.http.api.pop.response.PddGoodsSpecIdGetResponse; +import com.pdd.pop.sdk.http.api.pop.response.PddMallInfoGetResponse; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.dto.BookPriceInfoDto; +import org.dromara.zhishu.domain.dto.request.BatchSetSoldOutRequest; +import org.dromara.zhishu.domain.vo.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; +import java.util.Map; + +/** + * Pdd接口Service + * + * @author yxy + * @date 2025-03-10 + */ +public interface IPddService { + + /** + * 拉取商品,生成csv文件 + * + * @param shopId 店铺Id + * @param isOnsale 是否在售 + */ + void createShopGoodsList(ShopVo shopVo, TaskBo taskBo, Integer isOnsale); + + /** + * 拉取商品详情,生成csv文件 + * + * @param shopId 店铺Id + * @param isOnsale 是否在售 + */ + void createShopGoodsDetailList(ShopVo shopVo, TaskBo taskBo, Integer isOnsale); + + /** + * 获取拉取的数据 + * + * @param shopId 店铺Id + * @param page 页 + * @param pageSize 每页数量 + * @return 数据 + */ + TableDataInfo> getShopGoodsList(String shopId, String isOnsale,String isbn,String priceDown,String priceUp,String startDate,String endDate, Integer page, Integer pageSize,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode); + + + /** + * 导出 + * @param shopId + * @param isOnsale + * @return + */ + List emport(String shopId, String isOnsale); + /** + * 批量下架 + * + * @param shopId 店铺ID + */ + void batchSetSoldOut(Long shopId); + + /** + * 整店上下架 + */ + void editShopGoodsAllByIsOnSale(ShopVo shopVo,TaskBo taskBo,String isOnSale,String isbn,String priceDown,String priceUp,String startDate,String endDate,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode); + + /** + * 通过csv批量翻新商品上架拼多多 + * + * @param file csv文件 + * @param taskBo 任务信息 + * @param shopVo 店铺信息 + */ + void batchRenovateOnSaleByCsv(MultipartFile file, TaskBo taskBo, ShopVo shopVo); + + /** + * 翻新单个商品上架拼多多 + * + * @param data 翻新数据 + * @param shopId 店铺ID + * @param taskId 任务ID + */ + void renovateOnSale(BookPriceInfoDto data, String shopId, String taskId); + + String getSaleTemplateIdByShopId(Long shopId); + + + void sendPddGoodsToTargetShop(String shopId,String targetShopId,TaskBo taskBo,ShopVo shopVo); + + /** + * 根据shopId删除redis中的重复记录 + * @param shopId + * @return + */ + Boolean clearRedisBuffer(String shopId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPriceTemplateService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPriceTemplateService.java new file mode 100644 index 0000000..3c8d1f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPriceTemplateService.java @@ -0,0 +1,74 @@ +package org.dromara.zhishu.service; + +import jakarta.validation.constraints.NotEmpty; +import org.dromara.zhishu.domain.dto.request.CalculatePriceByTemplateRequest; +import org.dromara.zhishu.domain.dto.response.CalculatePriceByTemplateResponse; +import org.dromara.zhishu.domain.vo.PriceTemplateVo; +import org.dromara.zhishu.domain.bo.PriceTemplateBo; +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-03-17 + */ +public interface IPriceTemplateService { + + /** + * 查询价格模板 + * + * @param id 主键 + * @return 价格模板 + */ + PriceTemplateVo queryById(Long id); + + /** + * 分页查询价格模板列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 价格模板分页列表 + */ + TableDataInfo queryPageList(PriceTemplateBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的价格模板列表 + * + * @param bo 查询条件 + * @return 价格模板列表 + */ + List queryList(PriceTemplateBo bo); + + /** + * 新增价格模板 + * + * @param bo 价格模板 + * @return 是否新增成功 + */ + Boolean insertByBo(PriceTemplateBo bo); + + /** + * 修改价格模板 + * + * @param bo 价格模板 + * @return 是否修改成功 + */ + Boolean updateByBo(PriceTemplateBo bo); + + /** + * 校验并批量删除价格模板信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + + List getPriceByPlatformId(@NotEmpty(message = "价格计算请求不能为空") List requests); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPrintTemplateService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPrintTemplateService.java new file mode 100644 index 0000000..5772d7e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPrintTemplateService.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.PrintTemplateVo; +import org.dromara.zhishu.domain.bo.PrintTemplateBo; +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-07 + */ +public interface IPrintTemplateService { + + /** + * 查询打印模板 + * + * @param id 主键 + * @return 打印模板 + */ + PrintTemplateVo queryById(Long id); + + /** + * 分页查询打印模板列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 打印模板分页列表 + */ + TableDataInfo queryPageList(PrintTemplateBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的打印模板列表 + * + * @param bo 查询条件 + * @return 打印模板列表 + */ + List queryList(PrintTemplateBo bo); + + /** + * 新增打印模板 + * + * @param bo 打印模板 + * @return 是否新增成功 + */ + Boolean insertByBo(PrintTemplateBo bo); + + /** + * 修改打印模板 + * + * @param bo 打印模板 + * @return 是否修改成功 + */ + Boolean updateByBo(PrintTemplateBo 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/IPrinterService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPrinterService.java new file mode 100644 index 0000000..05c6c48 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IPrinterService.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.PrinterVo; +import org.dromara.zhishu.domain.bo.PrinterBo; +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-06 + */ +public interface IPrinterService { + + /** + * 查询打印机设置 + * + * @param id 主键 + * @return 打印机设置 + */ + PrinterVo queryById(Long id); + + /** + * 分页查询打印机设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 打印机设置分页列表 + */ + TableDataInfo queryPageList(PrinterBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的打印机设置列表 + * + * @param bo 查询条件 + * @return 打印机设置列表 + */ + List queryList(PrinterBo bo); + + /** + * 新增打印机设置 + * + * @param bo 打印机设置 + * @return 是否新增成功 + */ + Boolean insertByBo(PrinterBo bo); + + /** + * 修改打印机设置 + * + * @param bo 打印机设置 + * @return 是否修改成功 + */ + Boolean updateByBo(PrinterBo 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/IProfitSharingLogService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IProfitSharingLogService.java new file mode 100644 index 0000000..ce3e592 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IProfitSharingLogService.java @@ -0,0 +1,18 @@ +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.ProfitSharingLog; + +public interface IProfitSharingLogService { + + /** + * 分页查询分润日志表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return + */ + TableDataInfo queryPageList(ProfitSharingLog bo, PageQuery pageQuery); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningLogFileService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningLogFileService.java new file mode 100644 index 0000000..2aac20e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningLogFileService.java @@ -0,0 +1,75 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.RunningLogFileVo; +import org.dromara.zhishu.domain.bo.RunningLogFileBo; +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-12 + */ +public interface IRunningLogFileService { + + /** + * 查询程序运行日志表 + * + * @param id 主键 + * @return 程序运行日志表 + */ + RunningLogFileVo queryById(Long id); + + /** + * 根据文件类型获取最大顺序 + * @param fileType + * @return + */ + String selectMaxFileOrderByFileTypeAndCreateBy(String fileType,String userId); + + /** + * 分页查询程序运行日志表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 程序运行日志表分页列表 + */ + TableDataInfo queryPageList(RunningLogFileBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的程序运行日志表列表 + * + * @param bo 查询条件 + * @return 程序运行日志表列表 + */ + List queryList(RunningLogFileBo bo); + + /** + * 新增程序运行日志表 + * + * @param bo 程序运行日志表 + * @return 是否新增成功 + */ + Boolean insertByBo(RunningLogFileBo bo); + + /** + * 修改程序运行日志表 + * + * @param bo 程序运行日志表 + * @return 是否修改成功 + */ + Boolean updateByBo(RunningLogFileBo 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/IRunningTaskByShopService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningTaskByShopService.java new file mode 100644 index 0000000..0b4c546 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IRunningTaskByShopService.java @@ -0,0 +1,137 @@ +package org.dromara.zhishu.service; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.dto.ErpGoodsDto; +import org.dromara.zhishu.domain.dto.RunningTaskShopGoodsDto; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.dto.SuccessDataKfz; +import org.dromara.zhishu.domain.vo.RunningTaskNumVo; + +import java.util.List; +import java.util.Map; + +/** + * 执行的任务Service接口 + * + * @author yxy + * @date 2025-8-5 + */ +public interface IRunningTaskByShopService { + + + List selectGetShopGoodsList(String tableName,String isOnsale,String isbn,String priceDown,String priceUp,String startDate,String endDate, Long pageNum, Long pageSize,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode); + + int selectGetShopGoodsListCount(String tableName,String isOnsale,String isbn,String priceDown,String priceUp,String startDate,String endDate,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode); + + List selectGetShopGoodsListByDto(RunningTaskShopGoodsDto runningTaskShopGoodsDto); + + + /** + * 查询重复数据根据 isbn和价格 + * @param tableName + * @param isbn + * @return + */ + int selectNumByIsbn(String tableName, String isbn); + + int selectGetShopGoodsNum(String tableName,String isOnSale,String isbn,String priceDown,String priceUp,String startDate,String endDate,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode); + + int delShopGoods(String tableName,String isOnSale,String isbn,String priceDown,String priceUp,String startDate,String endDate); + + int selectByTrilateralId(String tableName,String trilateralId); + + RunningTask selectVoByTrilateralId(String tableName,String trilateralId); + + String selectLastFinishTime(String tableName); + + List selectByIsbn(String tableName,String isbn); + + List selectTaskShopNum(String tableName,Long taskId); + + int selectGetShopGoodsNumByTasKId(String tableName, String taskId); + + String selectStatus(String tableName); + + + /** + * 不分页查询重复数据 + * @param tableName + * @return + */ + List selectRepeatNoPage(String tableName); + + + List selectShopGoodsList(ErpGoodsDto erpGoodsDto); + + /** + * kfz专用导出店铺商品数据 + * @param erpGoodsDto + * @return + */ + List selectKfzShopGoodsList(ErpGoodsDto erpGoodsDto); + + /** + * 分页查询重复数据 + * @param tableName + * @param pageNum + * @param pageSize + * @return + */ + Page selectRepeat(String tableName, Long pageNum, Long pageSize); + + // 检查表是否存在 + int checkTableExists(String tableName); + + // 创建表 + void createTable(String tableName); + + // 插入数据 + void insert(String tableName, RunningTask task); + + //修改语句 + void update(String tableName, RunningTask task); + + void batchInsert(String tableName, List list); + + + void updateStatus(String tableName); + + void deleteAll(String tableName); + + void deleteByStatus(String tableName,String status); + + void deleteByTaskId(String tableName,String taskId); + + void deleteByGoodsId(String tableName,String goodsId); + + List selectOnSaleGoodsId(String tableName); + + List selectByGoodsId(String tableName, String trilateralId); + + void updateSuccessDataById( String tableName, String id, String successDataJsonStr); + + List getShopGoodsList(String tableName); + + Integer getShopGoodsTotalNum(String tableName); + + Integer getShopGoodsTotalNumByTaskId(String tableName,Long taskId); + + // Mapper接口 + Map batchCheckGoodsIdExists(String tableName, List goodsIds); + + Map selectTodayGoods(List shopId); + + Map selectTodaySales(List shopId); + List selectGetShopGoodsListAll(String tableName,String isOnsale, Long pageNum, Long pageSize); + Integer countAll(String tableName); + + /** + * 批量查询goods_id是否存在,返回存在的goods_id列表 + * @param tableName + * @param goodsIds + * @return + */ + List batchSelectExistsByGoodsIds(String tableName,List goodsIds); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopContextService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopContextService.java new file mode 100644 index 0000000..1e07b28 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopContextService.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.ShopContextVo; +import org.dromara.zhishu.domain.bo.ShopContextBo; +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-30 + */ +public interface IShopContextService { + + /** + * 查询店铺设置商品描述 + * + * @param id 主键 + * @return 店铺设置商品描述 + */ + ShopContextVo queryById(Long id); + + ShopContextVo selectByShopId(Long shopId); + + /** + * 分页查询店铺设置商品描述列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺设置商品描述分页列表 + */ + TableDataInfo queryPageList(ShopContextBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的店铺设置商品描述列表 + * + * @param bo 查询条件 + * @return 店铺设置商品描述列表 + */ + List queryList(ShopContextBo bo); + + /** + * 新增店铺设置商品描述 + * + * @param bo 店铺设置商品描述 + * @return 是否新增成功 + */ + Boolean insertByBo(ShopContextBo bo); + + /** + * 修改店铺设置商品描述 + * + * @param bo 店铺设置商品描述 + * @return 是否修改成功 + */ + Boolean updateByBo(ShopContextBo 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/IShopDetailService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopDetailService.java new file mode 100644 index 0000000..dc89842 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopDetailService.java @@ -0,0 +1,86 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.bo.ShopDetailBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; + +/** + * 商品详情Service接口 + * + * @author yxy + * @date 2025-03-13 + */ +public interface IShopDetailService { + + /** + * 查询商品详情 + * + * @param id 主键 + * @return 商品详情 + */ + ShopDetailVo queryById(Long id); + + /** + * 查询店铺设置信息 + * @param shopId 店铺id + * @return + */ + ShopDetailVo queryByShopId(Long shopId); + + /** + * 分页查询商品详情列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品详情分页列表 + */ + TableDataInfo queryPageList(ShopDetailBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的商品详情列表 + * + * @param bo 查询条件 + * @return 商品详情列表 + */ + List queryList(ShopDetailBo bo); + + /** + * 新增商品详情 + * + * @param bo 商品详情 + * @return 是否新增成功 + */ + Boolean insertByBo(ShopDetailBo bo); + + /** + * 修改商品详情 + * + * @param bo 商品详情 + * @return 是否修改成功 + */ + Boolean updateByBo(ShopDetailBo bo); + + /** + * 校验并批量删除商品详情信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + UploadResult upload(MultipartFile file); + + /** + * 根据店铺ID获取价格模板ID + * @param shopId 店铺ID + * @return 价格模板ID,如果不存在返回null + */ + String selectSaleTemplateIdByShopId(Long shopId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopImgService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopImgService.java new file mode 100644 index 0000000..ccb4f74 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopImgService.java @@ -0,0 +1,84 @@ +package org.dromara.zhishu.service; + +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.vo.ShopImgVo; +import org.dromara.zhishu.domain.bo.ShopImgBo; +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-03-17 + */ +public interface IShopImgService { + + /** + * 查询店铺图片 + * + * @param id 主键 + * @return 店铺图片 + */ + ShopImgVo queryById(Long id); + + /** + * 根据店铺id查询店铺图片 + * @param pid + * @return + */ + List selectVoByShopId(String pid); + + /** + * 分页查询店铺图片列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺图片分页列表 + */ + TableDataInfo queryPageList(ShopImgBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的店铺图片列表 + * + * @param bo 查询条件 + * @return 店铺图片列表 + */ + List queryList(ShopImgBo bo); + + /** + * 新增店铺图片 + * + * @param bo 店铺图片 + * @return 是否新增成功 + */ + Boolean insertByBo(ShopImgBo bo); + + /** + * 修改店铺图片 + * + * @param bo 店铺图片 + * @return 是否修改成功 + */ + Boolean updateByBo(ShopImgBo bo); + + /** + * 校验并批量删除店铺图片信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * + * @param pid 父id + * @param type 类型 1封面水印 2商详水印 3 商详头图 4 商详尾图 5 轮播尾图 + * @return + */ + int deleteByPidAndType(@Param("pid") String pid, @Param("type") String type); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopWarehouseAutoService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopWarehouseAutoService.java new file mode 100644 index 0000000..c3878aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopWarehouseAutoService.java @@ -0,0 +1,64 @@ +package org.dromara.zhishu.service; + + +import org.dromara.zhishu.domain.ShopWarehouseAuto; + +import java.util.List; + +/** + * + * @author yxy + * @date 2026-06-05 + */ +public interface IShopWarehouseAutoService { + + /** + * 查询店铺与仓库自动发布关联 + * + * @param id 主键 + * @return 店铺与仓库自动发布关联 + */ + ShopWarehouseAuto queryById(Long id); + + + /** + * 查询列表 + * @param bo + * @return + */ + List queryList(ShopWarehouseAuto bo); + + /** + * 根据店铺ID查询关联列表 + * + * @param shopId 店铺ID + * @return 关联列表 + */ + List queryListByShopId(Long shopId); + + + + /** + * 新增店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否新增成功 + */ + Boolean insertByBo(ShopWarehouseAuto bo); + + /** + * 修改店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否修改成功 + */ + Boolean updateByBo(ShopWarehouseAuto bo); + + /** + * 根据店铺ID删除关联信息 + * + * @param shopId 店铺ID + * @return 是否删除成功 + */ + Boolean deleteByShopId(Long shopId); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopWarehouseService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopWarehouseService.java new file mode 100644 index 0000000..c55b5ac --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IShopWarehouseService.java @@ -0,0 +1,59 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.ShopWarehouseVo; +import org.dromara.zhishu.domain.bo.ShopWarehouseBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.zhishu.domain.ShopWarehouse; + +import java.util.Collection; +import java.util.List; + +/** + * 店铺与仓库自动发布关联Service接口 + * + * @author yxy + * @date 2025-12-28 + */ +public interface IShopWarehouseService { + + /** + * 查询店铺与仓库自动发布关联 + * + * @param id 主键 + * @return 店铺与仓库自动发布关联 + */ + ShopWarehouseVo queryById(Long id); + + /** + * 根据店铺ID查询关联列表 + * + * @param shopId 店铺ID + * @return 关联列表 + */ + List queryListByShopId(Long shopId); + + /** + * 新增店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否新增成功 + */ + Boolean insertByBo(ShopWarehouseBo bo); + + /** + * 修改店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否修改成功 + */ + Boolean updateByBo(ShopWarehouseBo bo); + + /** + * 根据店铺ID删除关联信息 + * + * @param shopId 店铺ID + * @return 是否删除成功 + */ + Boolean deleteByShopId(Long shopId); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISpecService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISpecService.java new file mode 100644 index 0000000..b72c99b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISpecService.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.SpecVo; +import org.dromara.zhishu.domain.bo.SpecBo; +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-03-27 + */ +public interface ISpecService { + + /** + * 查询自定义规格设置 + * + * @param id 主键 + * @return 自定义规格设置 + */ + SpecVo queryById(Long id); + + SpecVo selectVoByShopId(Long shopId); + + /** + * 分页查询自定义规格设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 自定义规格设置分页列表 + */ + TableDataInfo queryPageList(SpecBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的自定义规格设置列表 + * + * @param bo 查询条件 + * @return 自定义规格设置列表 + */ + List queryList(SpecBo bo); + + /** + * 新增自定义规格设置 + * + * @param bo 自定义规格设置 + * @return 是否新增成功 + */ + Boolean insertByBo(SpecBo bo); + + /** + * 修改自定义规格设置 + * + * @param bo 自定义规格设置 + * @return 是否修改成功 + */ + Boolean updateByBo(SpecBo 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/ISyncLogService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISyncLogService.java new file mode 100644 index 0000000..2ed3cee --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISyncLogService.java @@ -0,0 +1,54 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.SyncLog; + +import java.util.List; + +/** + * 迁移日志Service接口 + * + * @author yxy + * @date 2026-06-06 + */ +public interface ISyncLogService { + + /** + * 根据ID查询迁移日志 + * + * @param id 主键 + * @return 迁移日志 + */ + SyncLog queryById(Long id); + + /** + * 查询迁移日志列表 + * + * @param bo 查询条件 + * @return 迁移日志列表 + */ + List queryList(SyncLog bo); + + /** + * 新增迁移日志 + * + * @param bo 迁移日志 + * @return 是否新增成功 + */ + Boolean insertByBo(SyncLog bo); + + /** + * 修改迁移日志 + * + * @param bo 迁移日志 + * @return 是否修改成功 + */ + Boolean updateByBo(SyncLog bo); + + /** + * 根据ID删除迁移日志 + * + * @param id 主键 + * @return 是否删除成功 + */ + Boolean deleteById(Long id); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISynchronizationShopLogService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISynchronizationShopLogService.java new file mode 100644 index 0000000..297737f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ISynchronizationShopLogService.java @@ -0,0 +1,44 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.SynchronizationShopLogVo; +import org.dromara.zhishu.domain.bo.SynchronizationShopLogBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.List; +import java.util.Map; + +/** + * 同步店铺商品库存日志Service接口 + * + * @author yxy + * @date 2026-04-14 + */ +public interface ISynchronizationShopLogService { + + /** + * 查询同步店铺商品库存日志 + * + * @param id 主键 + * @return 同步店铺商品库存日志 + */ + SynchronizationShopLogVo queryById(Long id); + + /** + * 分页查询同步店铺商品库存日志列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 同步店铺商品库存日志分页列表 + */ + TableDataInfo> queryPageList(SynchronizationShopLogBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的同步店铺商品库存日志列表 + * + * @param bo 查询条件 + * @return 同步店铺商品库存日志列表 + */ + List queryList(SynchronizationShopLogBo bo); + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITAuditService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITAuditService.java new file mode 100644 index 0000000..7e809af --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITAuditService.java @@ -0,0 +1,72 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.TAuditVo; +import org.dromara.zhishu.domain.bo.TAuditBo; +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-01 + */ +public interface ITAuditService { + + /** + * 查询审核 + * + * @param id 主键 + * @return 审核 + */ + TAuditVo queryById(Long id); + + /** + * 分页查询审核列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 审核分页列表 + */ + TableDataInfo queryPageList(TAuditBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的审核列表 + * + * @param bo 查询条件 + * @return 审核列表 + */ + List queryList(TAuditBo bo); + + /** + * 新增审核 + * + * @param bo 审核 + * @return 是否新增成功 + */ + Boolean insertByBo(TAuditBo bo); + + /** + * 修改审核 + * + * @param bo 审核 + * @return 是否修改成功 + */ + Boolean updateByBo(TAuditBo bo); + + /** + * 校验并批量删除审核信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + int updateByStatus(TAuditBo bo); + + Integer InsertLog(TAuditBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITBookAuditService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITBookAuditService.java new file mode 100644 index 0000000..c7cf5e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITBookAuditService.java @@ -0,0 +1,70 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.TBookAuditVo; +import org.dromara.zhishu.domain.bo.TBookAuditBo; +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-18 + */ +public interface ITBookAuditService { + + /** + * 查询图书审核管理 + * + * @param id 主键 + * @return 图书审核管理 + */ + TBookAuditVo queryById(Long id); + + /** + * 分页查询图书审核管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 图书审核管理分页列表 + */ + TableDataInfo queryPageList(TBookAuditBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的图书审核管理列表 + * + * @param bo 查询条件 + * @return 图书审核管理列表 + */ + List queryList(TBookAuditBo bo); + + /** + * 新增图书审核管理 + * + * @param bo 图书审核管理 + * @return 是否新增成功 + */ + Boolean insertByBo(TBookAuditBo bo); + + /** + * 修改图书审核管理 + * + * @param bo 图书审核管理 + * @return 是否修改成功 + */ + Boolean updateByBo(TBookAuditBo bo); + + /** + * 校验并批量删除图书审核管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + Boolean updateStatus(TBookAuditBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITDistrictService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITDistrictService.java new file mode 100644 index 0000000..59cad6a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITDistrictService.java @@ -0,0 +1,82 @@ +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.TDistrictBo; +import org.dromara.zhishu.domain.vo.DistrictsVo; +import org.dromara.zhishu.domain.vo.TDistrictVo; + +import java.util.Collection; +import java.util.List; + +public interface ITDistrictService { + + /** + * 查询【请填写功能名称】 + * + * @param id 主键 + * @return 【请填写功能名称】 + */ + TDistrictVo queryById(Long id); + + /** + * 分页查询【请填写功能名称】列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 【请填写功能名称】分页列表 + */ + TableDataInfo queryPageList(TDistrictBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的【请填写功能名称】列表 + * + * @param bo 查询条件 + * @return 【请填写功能名称】列表 + */ + List queryList(TDistrictBo bo); + + /** + * 新增【请填写功能名称】 + * + * @param bo 【请填写功能名称】 + * @return 是否新增成功 + */ + Boolean insertByBo(TDistrictBo bo); + + /** + * 修改【请填写功能名称】 + * + * @param bo 【请填写功能名称】 + * @return 是否修改成功 + */ + Boolean updateByBo(TDistrictBo bo); + + /** + * 校验并批量删除【请填写功能名称】信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + List selectList(); + + List selectDistrictByPid(String pid); + + + List selectCityList(TDistrictVo vo); + + List selectAreaList(TDistrictVo vo); + + /** + * 查询地址数据 + * + * @param vo + * @return + */ + List selectDistricts(TDistrictVo vo); + + List queryListByName(List districtNames); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITFreightService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITFreightService.java new file mode 100644 index 0000000..11ae68b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITFreightService.java @@ -0,0 +1,96 @@ +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.TFreight; +import org.dromara.zhishu.domain.bo.TFreightBo; +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-04-19 + */ +public interface ITFreightService { + + List selectDepotTree(); + + /** + * 根据二级货区id获取三级货区 + * @param shelvesId + * @return + */ + List selectByShelvesId(Long shelvesId); + + /** + * 根据货区id获取 一级二级三级货区的编号和id + * @param freightId + * @return + */ + Map selectByFreightId(Long freightId); + /** + * 查询三级货区管理 + * + * @param id 主键 + * @return 三级货区管理 + */ + TFreightVo queryById(Long id); + + /** + * 分页查询三级货区管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 三级货区管理分页列表 + */ + TableDataInfo queryPageList(TFreightBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的三级货区管理列表 + * + * @param bo 查询条件 + * @return 三级货区管理列表 + */ + List queryList(TFreightBo bo); + + /** + * 新增三级货区管理 + * + * @param bo 三级货区管理 + * @return 是否新增成功 + */ + TFreightBo insertByBo(TFreightBo bo); + + /** + * 修改三级货区管理 + * + * @param bo 三级货区管理 + * @return 是否修改成功 + */ + Boolean updateByBo(TFreightBo bo); + + /** + * 校验并批量删除三级货区管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid,Long LocalUserId); + + List querySheNameList(); + + /** + * 根据三级获取名称获取获取信息 + * @param freightName + * @param shelvesId + * @return + */ + TFreightVo selectByFreightName(String freightName, Long shelvesId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITInviteCodeService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITInviteCodeService.java new file mode 100644 index 0000000..e63308a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITInviteCodeService.java @@ -0,0 +1,65 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.TInviteCode; +import org.dromara.zhishu.domain.bo.InviteCodeBo; +import org.dromara.zhishu.domain.vo.InviteCodeVo; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +import java.util.List; + +/** + * 邀请码 Service 接口 + */ +public interface ITInviteCodeService { + + /** + * 查询邀请码 + * + * @param id 邀请码主键 + * @return 邀请码 + */ + InviteCodeVo queryById(Long id); + + /** + * 查询邀请码列表 + * + * @param userId 用户ID + * @return 邀请码列表 + */ + List queryListByUserId(Long userId); + + /** + * 查询邀请码分页列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 邀请码分页列表 + */ + TableDataInfo queryPageList(InviteCodeBo bo, PageQuery pageQuery); + + /** + * 生成邀请码 + * + * @param bo 邀请码信息 + * @return 邀请码 + */ + int generateInviteCode(InviteCodeBo bo); + + /** + * 验证邀请码 + * + * @param code 邀请码 + * @return 邀请码信息,如果无效则返回null + */ + TInviteCode validateInviteCode(String code); + + /** + * 使用邀请码 + * + * @param code 邀请码 + * @param inviteeId 被邀请人ID + * @return 是否使用成功 + */ + boolean useInviteCode(String code, Long inviteeId); +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITInviteRelationsService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITInviteRelationsService.java new file mode 100644 index 0000000..ada50fa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITInviteRelationsService.java @@ -0,0 +1,15 @@ +package org.dromara.zhishu.service; + + +import org.dromara.zhishu.domain.TInviteRelations; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.TInviteRelationsVo; + +import java.util.List; + +public interface ITInviteRelationsService { + + List selectByInviterId(Long inviterId); + + List selectUserShopList(Long userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShelvesService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShelvesService.java new file mode 100644 index 0000000..7e330c5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShelvesService.java @@ -0,0 +1,79 @@ +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.TShelvesBo; +import org.dromara.zhishu.domain.vo.TShelvesVo; + +import java.util.Collection; +import java.util.List; + +/** + * 货架信息Service接口 + * + * @author Lion Li + * @date 2025-03-26 + */ +public interface ITShelvesService { + + /** + * 查询货架信息 + * + * @param id 主键 + * @return 货架信息 + */ + TShelvesVo queryById(Long id); + + /** + * + */ + TShelvesVo queryFoundId(Long depotId, String code); + + /** + * 分页查询货架信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 货架信息分页列表 + */ + TableDataInfo queryPageList(TShelvesBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的货架信息列表 + * + * @param bo 查询条件 + * @return 货架信息列表 + */ + List queryList(TShelvesBo bo); + + /** + * 新增货架信息 + * + * @param bo 货架信息 + * @return 是否新增成功 + */ + Boolean insertByBo(TShelvesBo bo); + + /** + * 修改货架信息 + * + * @param bo 货架信息 + * @return 是否修改成功 + */ + Boolean updateByBo(TShelvesBo bo); + + /** + * 校验并批量删除货架信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid,Long LocalUserId); + + List queryList1(); + + List selectShelvesIdByDepotIdAndCode(String depotId, String code); + + List selectShelvesByDepotId(String depotId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopDepotAotuService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopDepotAotuService.java new file mode 100644 index 0000000..0b6ff18 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITShopDepotAotuService.java @@ -0,0 +1,43 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.TShopDepotAotuVo; +import org.dromara.zhishu.domain.bo.TShopDepotAotuBo; +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-09-05 + */ +public interface ITShopDepotAotuService { + + /** + * 查询店铺自动发布仓库关联 + * + * @param id 主键 + * @return 店铺自动发布仓库关联 + */ + TShopDepotAotuVo queryById(Long id); + + /** + * 分页查询店铺自动发布仓库关联列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺自动发布仓库关联分页列表 + */ + TableDataInfo queryPageList(TShopDepotAotuBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的店铺自动发布仓库关联列表 + * + * @param bo 查询条件 + * @return 店铺自动发布仓库关联列表 + */ + List queryList(TShopDepotAotuBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITUserPlatformService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITUserPlatformService.java new file mode 100644 index 0000000..70a8452 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITUserPlatformService.java @@ -0,0 +1,8 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.TUserPlatform; + +public interface ITUserPlatformService { + + void insertTUserPlatform(TUserPlatform userPlatform); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITaskPauseService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITaskPauseService.java new file mode 100644 index 0000000..72de53b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ITaskPauseService.java @@ -0,0 +1,20 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.TaskPause; + + +public interface ITaskPauseService { + + /** + * 新增暂停任务 + * + */ + Boolean insert(TaskPause taskPause); + + /** + * 删除暂停任务 + * @param taskId + * @return + */ + Boolean deleteByTaskId(Long taskId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserAccountService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserAccountService.java new file mode 100644 index 0000000..096d579 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserAccountService.java @@ -0,0 +1,75 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.UserAccountVo; +import org.dromara.zhishu.domain.bo.UserAccountBo; +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-02-25 + */ +public interface IUserAccountService { + + /** + * 查询账号管理 + * + * @param id 主键 + * @return 账号管理 + */ + UserAccountVo queryById(Long id); + + /** + * 分页查询账号管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 账号管理分页列表 + */ + TableDataInfo queryPageList(UserAccountBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的账号管理列表 + * + * @param bo 查询条件 + * @return 账号管理列表 + */ + List queryList(UserAccountBo bo); + + /** + * 查询管理员下的账户 + * @param bo + * @return + */ + List queryListAdmin(UserAccountBo bo); + + /** + * 新增账号管理 + * + * @param bo 账号管理 + * @return 是否新增成功 + */ + Boolean insertByBo(UserAccountBo bo); + + /** + * 修改账号管理 + * + * @param bo 账号管理 + * @return 是否修改成功 + */ + Boolean updateByBo(UserAccountBo 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/IUserRechargeService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserRechargeService.java new file mode 100644 index 0000000..4b01563 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IUserRechargeService.java @@ -0,0 +1,88 @@ +package org.dromara.zhishu.service; + +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.vo.UserRechargeVo; +import org.dromara.zhishu.domain.bo.UserRechargeBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.springframework.web.bind.annotation.RequestBody; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 用户充值Service接口 + * + * @author yxy + * @date 2025-04-26 + */ +public interface IUserRechargeService { + + /** + * 查询用户充值 + * + * @param id 主键 + * @return 用户充值 + */ + UserRechargeVo queryById(Long id); + + /** + * 分页查询用户充值列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 用户充值分页列表 + */ + TableDataInfo queryPageList(UserRechargeBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的用户充值列表 + * + * @param bo 查询条件 + * @return 用户充值列表 + */ + List queryList(UserRechargeBo bo); + + /** + * 新增用户充值 + * + * @param bo 用户充值 + * @return 是否新增成功 + */ + Boolean insertByBo(UserRechargeBo bo); + + /** + * 修改用户充值 + * + * @param bo 用户充值 + * @return 是否修改成功 + */ + Boolean updateByBo(UserRechargeBo bo); + + /** + * 校验并批量删除用户充值信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 充值金额到钱包里 + * @return + */ + R addUserBalance(UserRechargeBo bo); + + /** + * 余额支付 + * @param userId + * @param shopId + * @param logType + * @param rechargPrice + * @return + */ + R balancePayment(Long userId, Long shopId, int logType, BigDecimal rechargPrice); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IViolationService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IViolationService.java new file mode 100644 index 0000000..bf22e7e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IViolationService.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.ViolationVo; +import org.dromara.zhishu.domain.bo.ViolationBo; +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-23 + */ +public interface IViolationService { + + /** + * 查询违规 + * + * @param id 主键 + * @return 违规 + */ + ViolationVo queryById(Long id); + + /** + * 分页查询违规列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 违规分页列表 + */ + TableDataInfo queryPageList(ViolationBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的违规列表 + * + * @param bo 查询条件 + * @return 违规列表 + */ + List queryList(ViolationBo bo); + + /** + * 新增违规 + * + * @param bo 违规 + * @return 是否新增成功 + */ + Boolean insertByBo(ViolationBo bo); + + /** + * 修改违规 + * + * @param bo 违规 + * @return 是否修改成功 + */ + Boolean updateByBo(ViolationBo 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/IWarehouseSettingsService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWarehouseSettingsService.java new file mode 100644 index 0000000..e87b689 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWarehouseSettingsService.java @@ -0,0 +1,76 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.WarehouseSettings; +import org.dromara.zhishu.domain.vo.WarehouseSettingsVo; +import org.dromara.zhishu.domain.bo.WarehouseSettingsBo; +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-12-19 + */ +public interface IWarehouseSettingsService { + + /** + * 查询设置 + * + * @param id 主键 + * @return 设置 + */ + WarehouseSettingsVo queryById(Long id); + + /** + * 分页查询设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 设置分页列表 + */ + TableDataInfo queryPageList(WarehouseSettingsBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的设置列表 + * + * @param bo 查询条件 + * @return 设置列表 + */ + List queryList(WarehouseSettingsBo bo); + + /** + * 新增设置 + * + * @param bo 设置 + * @return 是否新增成功 + */ + Boolean insertByBo(WarehouseSettingsBo bo); + + /** + * 修改设置 + * + * @param bo 设置 + * @return 是否修改成功 + */ + Boolean updateByBo(WarehouseSettingsBo bo); + + /** + * 修改启用状态 + * @param bo + * @return + */ + Boolean updateStatus(WarehouseSettingsBo 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/IWaveDetailService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWaveDetailService.java new file mode 100644 index 0000000..91707d2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWaveDetailService.java @@ -0,0 +1,30 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.dto.WaveDetailRequestDto; +import org.springframework.web.bind.annotation.RequestBody; + +/** + * 波次信息Service接口 + * + * @author Lion Li + * @date 2026-01-22 + */ +public interface IWaveDetailService { + + /** + * 新增波次信息 + * + * @param requestDto 波次信息请求DTO + * @return 是否新增成功 + */ + Boolean insertWaveDetail(String userid, WaveDetailRequestDto requestDto); + + /** + * 获取波次ID + */ + Long getWaveID(); + + String getEmployeeId(String name, String userId); + + Boolean countVerWave(String waveId, String employeeId, Integer submitCount); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWaveService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWaveService.java new file mode 100644 index 0000000..6459ebf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWaveService.java @@ -0,0 +1,13 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.WaveVo; + +import java.util.List; + +public interface IWaveService { + String getStaffName(String staffId); + + List getStaffId(); + + List getStaffList(String userId); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWhiteListService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWhiteListService.java new file mode 100644 index 0000000..720b1a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IWhiteListService.java @@ -0,0 +1,77 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.WhiteListVo; +import org.dromara.zhishu.domain.bo.WhiteListBo; +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-25 + */ +public interface IWhiteListService { + + /** + * 查询白名单 + * + * @param id 主键 + * @return 白名单 + */ + WhiteListVo queryById(Long id); + + /** + * 分页查询白名单列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 白名单分页列表 + */ + TableDataInfo queryPageList(WhiteListBo bo, PageQuery pageQuery); + + + List selectAll(); + + List selectByIp(String ip); + /** + * 查询符合条件的白名单列表 + * + * @param bo 查询条件 + * @return 白名单列表 + */ + List queryList(WhiteListBo bo); + + /** + * 新增白名单 + * + * @param bo 白名单 + * @return 是否新增成功 + */ + Boolean insertByBo(WhiteListBo bo); + + /** + * 修改白名单 + * + * @param bo 白名单 + * @return 是否修改成功 + */ + Boolean updateByBo(WhiteListBo bo); + + /** + * 校验并批量删除白名单信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 清空数据表 + */ + void deleteAll(); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IXyBindService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IXyBindService.java new file mode 100644 index 0000000..cd537a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IXyBindService.java @@ -0,0 +1,14 @@ +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.XyBindBo; +import org.dromara.zhishu.domain.vo.XyBindVo; + +public interface IXyBindService { + XyBindVo queryById(String token); + TableDataInfo queryPageList(XyBindBo bo, PageQuery pageQuery); + Boolean insertByBo(XyBindBo bo); + Boolean updateByBo(XyBindBo bo); + Boolean deleteByToken(String token); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IXyCategoryService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IXyCategoryService.java new file mode 100644 index 0000000..1ef3d3e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IXyCategoryService.java @@ -0,0 +1,12 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.XyCategoryVo; + +import java.util.List; + +public interface IXyCategoryService { + /** + * 查询闲鱼类目列表 + */ + List selectXyCategoryList(); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopGoodsDetailService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopGoodsDetailService.java new file mode 100644 index 0000000..783dbc8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopGoodsDetailService.java @@ -0,0 +1,77 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsDetailVo; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsDetailBo; +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-13 + */ +public interface IZhishuShopGoodsDetailService { + + /** + * 查询商品信息补全表 + * + * @param id 主键 + * @return 商品信息补全表 + */ + ZhishuShopGoodsDetailVo queryById(Long id); + + /** + * 根据父id查询信息 + * @param pid + * @return + */ + ZhishuShopGoodsDetailVo selectByPid(Long pid); + + + + /** + * 分页查询商品信息补全表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品信息补全表分页列表 + */ + TableDataInfo queryPageList(ZhishuShopGoodsDetailBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的商品信息补全表列表 + * + * @param bo 查询条件 + * @return 商品信息补全表列表 + */ + List queryList(ZhishuShopGoodsDetailBo bo); + + /** + * 新增商品信息补全表 + * + * @param bo 商品信息补全表 + * @return 是否新增成功 + */ + Boolean insertByBo(ZhishuShopGoodsDetailBo bo); + + /** + * 修改商品信息补全表 + * + * @param bo 商品信息补全表 + * @return 是否修改成功 + */ + Boolean updateByBo(ZhishuShopGoodsDetailBo 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/IZhishuShopGoodsService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopGoodsService.java new file mode 100644 index 0000000..14d1b77 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopGoodsService.java @@ -0,0 +1,292 @@ +package org.dromara.zhishu.service; + +import jakarta.validation.constraints.NotNull; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.domain.SysUser; +import org.dromara.zhishu.domain.StockChangeLog; +import org.dromara.zhishu.domain.Task; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.bo.BatchUpdateCargoBo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsBo; +import org.dromara.zhishu.domain.dto.request.BatchGoodsRequest; +import org.dromara.zhishu.domain.dto.request.GoodsComparisonRequest; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.domain.vo.ProductSubmitResultVo; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 商品信息Service接口 + * + * @author Lion Li + * @date 2025-03-07 + */ +public interface IZhishuShopGoodsService { + + /** + * 批量查询商品根据id + * @param ids + * @return + */ + List selectByIds(List ids); + + /** + * 查询商品信息 + * + * @param id 主键 + * @return 商品信息 + */ + ZhishuShopGoodsVo queryById(String id); + + /** + * 根据isbn查询商品信息 + * + * @param isbn 主键 + * @return 商品信息 + */ + List getProductByBarcode(String isbn); + + /** + * 根据商品编码查询信息 + * + * @param itemNumber + * @return + */ + ZhishuShopGoodsVo selectShopGoodsByItemNumber(String itemNumber); + + + /** + * 根据货号查询商品 + * + * @param artNo + * @return + */ + ZhishuShopGoodsVo selectShopGoodsByArtNo(String artNo); + + /** + * 提交商品信息 + * + * @param form 商品信息表单 + */ + ProductSubmitResultVo submitProduct(ProductForm form); + + /** + * 上传商品照片 + * + * @param photos 照片文件列表 + */ + void uploadPhotos(MultipartFile[] photos); + + /** + * 分页查询商品信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品信息分页列表 + */ + TableDataInfo queryPageList(ZhishuShopGoodsBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的商品信息列表 + * + * @param bo 查询条件 + * @return 商品信息列表 + */ + List queryList(ZhishuShopGoodsBo bo); + + /** + * 新增商品信息 + * + * @param bo 商品信息 + * @return 是否新增成功 + */ + Boolean insertByBo(ZhishuShopGoodsBo bo); + + /** + * 批量新增商品信息 + * + * @param list 商品列表 + */ + Boolean insertList(List list, Long depotid, String Filename); + + /** + * 自营书品批量新增商品信息 + * + * @param list 商品列表 + */ + Boolean insertListGoodsInfo(List list, Long depotId, Long shelvesDepotId, Long freightDepotId, String Filename, String code ,Long userId,String type); + + /** + * 修改商品信息 + * + * @param bo 商品信息 + * @return 是否修改成功 + */ + Boolean updateByBo(ZhishuShopGoodsBo bo); + + /** + * 校验并批量删除商品信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 通过孔夫子网站API查询图书信息 + * + * @param isbn ISBN编号 + * @return 图书信息 + */ + + List getProductByKongfz(String isbn, String searchType, String sortType, String conditionValue, String cookies, String publisher, String author); + + /** + * 初始化库存到redis + */ + void batchInitInventoryToRedis(); + + void batchRedisInitInventory(List goodsList); + + /** + * 操作库存 + * + * @param shopGoodsId + * @param count + * @return + */ + Boolean operatingInventory(Integer operationType, String shopGoodsId, Integer count, Integer type, String aboutId, Long operationBy); + + ProductVo queryBookByPython(String isbn); + +// List selectShopGoodsByPhoneNumber(String phoneNumber,); + + /** + * 库存比对存入表格 + * + * @param request + */ + void goodsComparison(GoodsComparisonRequest request); + + /** + * 批量库存比对存入表格 + * + * @param request + */ + void batchGoodsComparison(BatchGoodsRequest request); + + /** + * 根据用户选择货号规则将商品存入数据库 + */ + void saveShopGoodsInDb(SaveGoodsVo saveGoodsVo); + + ProductForm repeatBook(ProductForm form); + + /** + * 根据库存操作类型操作库存并同步平台库存 + * + * @param operationType + * @param shopGoodsPublishedVo + * @param count + */ + Boolean operatingGoodsInventory(Long shopId, Integer shopType, Integer operationType, ShopGoodsPublishedVo shopGoodsPublishedVo, Integer count, String orderSn); + + + Boolean goofishoperatingGoodsInventory(Long shopId, Integer shopType, Integer operationType, ZhishuShopGoodsVo zhishuShopGoodsVo, Integer count, String orderSn); + + + + + void randomUpdateArtNo(Long userId, Long shopId); + + void goodsAdd(Map map); + + void goodsAutoAdd(Map map); + + + void goodsAdd(Map map, Long userId,ShopVo shopVo); + + int zanTing(String threadId); + + int huanXing(String threadId); + + String artNoProcessing(Integer saveArtNoRule, Long userId, String isbn, String oldArtNo, double conditionCode, FreightGoodsCountVo freightGoodsCountVo); + + List selectShopStockLog(String id); + + Integer queryInventory(@NotNull(message = "商品Id不能为空") Long shopGoodsId); + + ProductSubmitResultVo submitFromCopyrightPage(ProductForm form); + + List getAuthorAndPublisher(String keyword, String cookies); + + TableDataInfo selectShopGoodsByPhoneNumber(String phoneNumber, int pageNum, int pageSize, String date); + + Map selectDepotIds(String userId, String artNo); + + StockChangeLog queryStockChangeLogByOrderSn(@NotNull(message = "平台订单编码不能为空") String orderSn, @NotNull(message = "库存操作日志类型不能为空") Integer type); + + /** + * 根据用户ID查询商品数量 + * + * @param userId 用户ID + * @return 商品数量 + */ + Long queryGoodsCountByUserId(Long userId); + + SysUser queryUserByUserId(@NotNull(message = "店铺ID不能为空") Long userId); + + Boolean operatingGoodsSoldOut(Long shopId, Integer platformType, Integer logType, Integer operationType, ShopGoodsPublishedVo shopGoodsPublishedVo, String orderSn); + + TableDataInfo queryGoodListByArtNo(String code, Long userId, int pageNum, int pageSize, String date); + + /** + * 批量移动商品位置 + * + * @param itemIds 商品ID列表 + * @param warehouse 货区编码 + * @param shelf 货架编码 + * @param freight 货位编码 + * @param userId 用户ID + * @return 操作结果 + */ + String batchMoveItems(List itemIds, String warehouse ,String shelf, String freight, Long userId); + + + int batchUpdateCargo(BatchUpdateCargoBo bo); + + /** + * 根据货号前缀 分页 修改 分销状态 + * @param isJoinDistribution + * @param artNoPrefix + * @param userId + * @param limitNum + * @return + */ + int updateByArtNoPrefix(String isJoinDistribution,String artNoPrefix,Long userId, Long limitNum); + + void createShopGoodsList(BatchGoodsRequest request); + + void deleteTaskDataByShopId(Long shopId); + + void syncRunningTaskToShopGoods(@NotNull(message = "店铺ID不能为空") Long shopId, Long freightId, Long userId, TaskBo taskBo); + + void synchronousTask(ShopVo shopVo, TaskBo taskBo); + + Map uploadImg(MultipartFile file); + + void synShopImg(Long userId); + + void synPddShopImg(Long userId); + + Long getTaskDataNum(Long taskId); + +// void batchUpdateCargo(BatchUpdateCargoBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopImagesService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopImagesService.java new file mode 100644 index 0000000..8c1e1e7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/IZhishuShopImagesService.java @@ -0,0 +1,72 @@ +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.ZhishuShopImages; +import org.dromara.zhishu.domain.bo.ZhishuShopImagesBo; +import org.dromara.zhishu.domain.vo.ZhishuShopImagesVo; + +import java.util.Collection; +import java.util.List; + +/** + * 商品图片Service接口 + * + * @author Lion Li + * @date 2025-03-13 + */ +public interface IZhishuShopImagesService { + + /** + * 查询商品图片 + * + * @param id 主键 + * @return 商品图片 + */ + ZhishuShopImagesVo queryById(String id); + + List selectShopImagesByShopId(String goodsId); + + /** + * 分页查询商品图片列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品图片分页列表 + */ + TableDataInfo queryPageList(ZhishuShopImagesBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的商品图片列表 + * + * @param bo 查询条件 + * @return 商品图片列表 + */ + List queryList(ZhishuShopImagesBo bo); + + /** + * 新增商品图片 + * + * @param bo 商品图片 + * @return 是否新增成功 + */ + Boolean insertByBo(ZhishuShopImagesBo bo); + + /** + * 修改商品图片 + * + * @param bo 商品图片 + * @return 是否修改成功 + */ + Boolean updateByBo(ZhishuShopImagesBo 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/LogisticsService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/LogisticsService.java new file mode 100644 index 0000000..eef91af --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/LogisticsService.java @@ -0,0 +1,18 @@ +package org.dromara.zhishu.service; + +import jakarta.validation.constraints.NotNull; +import org.dromara.zhishu.domain.Logistics; +import org.dromara.zhishu.domain.bo.LogisticsBo; + +import java.util.List; + +public interface LogisticsService { + + Integer insert(LogisticsBo bo); + + List selectLogistics(String warehouseId); + + Logistics queryById(@NotNull(message = "主键不能为空") Long id); + + Boolean setTemplate(LogisticsBo bo); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/PddRequestService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/PddRequestService.java new file mode 100644 index 0000000..7694173 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/PddRequestService.java @@ -0,0 +1,8 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.dto.PddOrderIncrementQuery; + +public interface PddRequestService { + + void getIncrementRequest(PddOrderIncrementQuery query); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsPublishedLogService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsPublishedLogService.java new file mode 100644 index 0000000..f4eb415 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ShopGoodsPublishedLogService.java @@ -0,0 +1,20 @@ +package org.dromara.zhishu.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.validation.constraints.NotNull; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; + +public interface ShopGoodsPublishedLogService extends IService { + + /** + * 通过相关Id查询商品发布记录日志 + * @param platformId + * @param aboutId + * @param platformType + * @param logType + * @param operationType + * @return + */ + ShopGoodsPublishedLog queryPublishedLogByOrderSn(@NotNull(message = "平台订单编码不能为空") String platformId, @NotNull(message = "日志类型不能为空") String aboutId, @NotNull(message = "平台类型不能为空") Integer platformType, @NotNull(message = "日志类型不能为空") Integer logType, @NotNull(message = "操作类型不能为空") Integer operationType); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/SignGeneratorService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/SignGeneratorService.java new file mode 100644 index 0000000..7e4260a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/SignGeneratorService.java @@ -0,0 +1,5 @@ +package org.dromara.zhishu.service; + +public interface SignGeneratorService { + String generateCallbackSign(String loginCode, long timestamp, String secret); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/TShopMessageSubscribeService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/TShopMessageSubscribeService.java new file mode 100644 index 0000000..78f1640 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/TShopMessageSubscribeService.java @@ -0,0 +1,10 @@ +package org.dromara.zhishu.service; + +import org.dromara.zhishu.domain.vo.MessageSubscribeVo; + +import java.util.List; + +public interface TShopMessageSubscribeService { + + void insertOrUpdate(List messageSubscribeVo, Long id); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ZhishuShopGoodsAopService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ZhishuShopGoodsAopService.java new file mode 100644 index 0000000..24e7833 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/ZhishuShopGoodsAopService.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.service; + +import org.apache.ibatis.annotations.Param; +import org.dromara.zhishu.domain.dto.request.ZhishuShopGoodsRequest; +import org.dromara.zhishu.domain.vo.FreightGoodsCountVo; +import org.dromara.zhishu.domain.vo.SaveGoodsVo; +import org.dromara.zhishu.domain.vo.ShopVo; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +public interface ZhishuShopGoodsAopService { + + void insertNewDataList( + @Param("data") ZhishuShopGoodsRequest data, @Param("userId") Long userId, + @Param("freightGoodsCountList") List freightGoodsCountList, + @Param("saveGoodsVo") SaveGoodsVo saveGoodsVo, + @Param("failedList") List failedList, + @Param("successList") List successList, + @Param("successMarkI") AtomicInteger successMarkI, @Param("failMarkI") AtomicInteger failMarkI, + @Param("shopVo") ShopVo shopVo, @Param("totalNum") Integer totalNum, @Param("time") long time, + @Param("status") AtomicBoolean status, + @Param("taskType") String taskType + ); + + void updateChangedDataList( + @Param("data") ZhishuShopGoodsRequest data, @Param("userId") Long userId, + @Param("freightGoodsCountList") List freightGoodsCountList, + @Param("saveGoodsVo") SaveGoodsVo saveGoodsVo, + @Param("failedList") List failedList, + @Param("successList") List successList, + @Param("successMarkI") AtomicInteger successMarkI, @Param("failMarkI") AtomicInteger failMarkI, + @Param("shopVo") ShopVo shopVo, @Param("totalNum") Integer totalNum, @Param("newTime") long time, + @Param("status") AtomicBoolean status + ); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/KfzClient.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/KfzClient.java new file mode 100644 index 0000000..4798cf1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/KfzClient.java @@ -0,0 +1,77 @@ +package org.dromara.zhishu.service.client; + +import com.dtflys.forest.annotation.*; +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryKWRequest; +import org.dromara.zhishu.domain.dto.request.SoldOutRequest; +import org.dromara.zhishu.domain.dto.request.UpdateArtNoRequest; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public interface KfzClient { + + /** + * 拉取孔夫子商品 + * + * @param myURL + * @param shopId + * @return + */ + @Get(value = "{myURL}/api/kfz/synchronizationGoods", dataType = "json") + Boolean synchronizationGoods(@Var("myURL") String myURL, @Query("shopId") Long shopId, @Query("taskId") Long taskId, @Query("sycFlag") Integer sycFlag); + + /** + * 更新商品货号 + * + * @param myURL + * @param request + * @return + */ + @Post(value = "{myURL}/api/kfz/updateArtNo", dataType = "json", contentType = "application/json") + Boolean updateArtNo(@Var("myURL") String myURL, @Body UpdateArtNoRequest request); + + /** + * 同步近30天历史存量订单 + * + * @param myURL + * @param shopIdList + * @return + */ + @Post(value = "{myURL}/api/kfz/order/fullSynchronizationOrder", dataType = "json", contentType = "application/json") + String fullSynchronizationOrder(@Var("myURL") String myURL, @Query("days") Integer days, @Query("type") String type, @Body List shopIdList); + + + /** + * 获取物流配送方式 + * + * @param myURL + * @param shopId + * @return + */ + @Get(value = "{myURL}/api/kfz/order/delivery/methodList", dataType = "json") + List deliveryMethodList(@Var("myURL") String myURL, @Query("shopId") Long shopId); + + + /** + * 订单发货 + * + * @param myURL + * @param request + * @return + */ + @Post(value = "{myURL}/api/kfz/order/deliver", dataType = "json", contentType = "application/json") + R orderDelivery(@Var("myURL") String myURL, @Body OrderDeliveryKWRequest request); + + /** + * 下架商品 + * + * @param myURL + * @param request + * @return + */ + @Post(value = "{myURL}/api/kfz/soldOut", dataType = "json", contentType = "application/json") + R soldOut(@Var("myURL") String myURL, @Body SoldOutRequest request); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/PddClient.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/PddClient.java new file mode 100644 index 0000000..f3dceaa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/PddClient.java @@ -0,0 +1,66 @@ +package org.dromara.zhishu.service.client; + +import com.dtflys.forest.annotation.*; +import org.dromara.common.core.domain.R; +import org.dromara.zhishu.domain.dto.request.*; +import org.dromara.zhishu.domain.dto.response.GoodsSaleStatusSetResponse; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.response.UpdateSkuPriceResponse; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.PostMapping; + +import java.util.List; + +@Service +public interface PddClient { + + /** + * 查询物流公司列表 + * + * @param myURL + * @return + */ + @Get(value = "{myURL}/api/pdd/order/delivery/methodList", dataType = "json") + List deliveryMethodList(@Var("myURL") String myURL); + + /** + * 订单发货 + * + * @param myURL + * @param request + * @return + */ + @Post(value = "{myURL}/api/pdd/order/deliver", dataType = "json", contentType = "application/json") + R orderDelivery(@Var("myURL") String myURL, @Body OrderDeliveryPddRequest request); + + + /** + * 同步90天存量订单 + */ + @Post(value = "{myURL}/api/pdd/order/fullSynchronizationOrder", dataType = "json", contentType = "application/json") + String fullSynchronizationOrder(@Var("myURL") String myURL, @Query("days") Integer days, @Query("type") String type, @Body List shopIdList); + + /** + * 设置商品上下架状态 + */ + @Post(value = "{myURL}/api/pdd/goods/goodsSaleStatusSet", dataType = "json", contentType = "application/json") + R goodsSaleStatusSet(@Var("myURL") String myURL, @Body GoodsSaleStatusSetBatchRequest request); + + /** + * 设置单个商品上下架状态 + */ + @Post(value = "{myURL}/api/pdd/goods/goodsSaleStatusSetSingle", dataType = "json", contentType = "application/json") + R goodsSaleStatusSetSingle(@Var("myURL") String myURL, @Body GoodsSaleStatusSetRequest request); + + /** + * 修改商品sku价格 + */ + @Post(value = "{myURL}/api/pdd/goods/updateSkuPrice", dataType = "json", contentType = "application/json") + R updateSkuPrice(@Var("myURL") String myURL, @Body UpdateSkuPriceRequest request); + + /** + * 修改商品sku价格 + */ + @Post(value = "{myURL}/api/pdd/goods/deleteSaleOutGoodsBatch", dataType = "json", contentType = "application/json") + R deleteSaleOutGoodsBatch(@Var("myURL") String myURL, @Body DeleteSaleOutGoodsBatchRequest request); +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/WlnClient.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/WlnClient.java new file mode 100644 index 0000000..164bacd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/client/WlnClient.java @@ -0,0 +1,54 @@ +package org.dromara.zhishu.service.client; + +import com.dtflys.forest.annotation.Body; +import com.dtflys.forest.annotation.Header; +import com.dtflys.forest.annotation.Post; +import com.dtflys.forest.annotation.Var; +import com.dtflys.forest.converter.json.JacksonEncoder; +import org.dromara.zhishu.domain.dto.request.ErpBaseShopPageGetRequest; +import org.dromara.zhishu.domain.dto.request.ErpGoodsQueryOlnGoodsRequest; +import org.dromara.zhishu.domain.dto.request.ErpGoodsUpdateItemRequest; +import org.dromara.zhishu.domain.dto.response.ErpBaseShopPageGetResponse; +import org.dromara.zhishu.domain.dto.response.ErpGoodsQueryOlnGoodsResponse; +import org.dromara.zhishu.domain.dto.response.WlnBaseResponse; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public interface WlnClient { + + /** + * 查询店铺 + * + * @param myURL + * @param request + * @return + */ + @JacksonEncoder + @Post(value = "{myURL}/api/erpBaseShopPageGet", dataType = "json", contentType = "application/json") + WlnBaseResponse> erpBaseShopPageGet(@Var("myURL") String myURL, @Header("appKey") String appKey, @Header("appSecret") String appSecret, @Body ErpBaseShopPageGetRequest request); + + /** + * 查询线上商品 + * + * @param myURL + * @param request + * @return + */ + @JacksonEncoder + @Post(value = "{myURL}/api/erpGoodsQueryOlngoods", dataType = "json", contentType = "application/json") + WlnBaseResponse erpGoodsQueryOlnGoods(@Var("myURL") String myURL, @Header("appKey") String appKey, @Header("appSecret") String appSecret, @Body ErpGoodsQueryOlnGoodsRequest request); + + /** + * 修改商品 + * + * @param myURL + * @param request + * @return + */ + @JacksonEncoder + @Post(value = "{myURL}/api/erpGoodsUpdateItem", dataType = "json", contentType = "application/json") + WlnBaseResponse erpGoodsUpdateItem(@Var("myURL") String myURL, @Header("appKey") String appKey, @Header("appSecret") String appSecret, @Body ErpGoodsUpdateItemRequest request); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/InventorySynchronizedStrategyFactory.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/InventorySynchronizedStrategyFactory.java new file mode 100644 index 0000000..c97dad8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/InventorySynchronizedStrategyFactory.java @@ -0,0 +1,40 @@ +package org.dromara.zhishu.service.factory; + +import org.dromara.zhishu.service.strategy.InventorySynchronizedGFtrategy; +import org.dromara.zhishu.service.strategy.InventorySynchronizedKWStrategy; +import org.dromara.zhishu.service.strategy.InventorySynchronizedPddStrategy; +import org.dromara.zhishu.service.strategy.InventorySynchronizedStrategy; +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 InventorySynchronizedStrategyFactory implements ApplicationContextAware { + + private static ApplicationContext context; + + private static final Map> strategyClasses = new HashMap<>(); + + static { + // 可以继续添加其他的消息类型对应的策略 + strategyClasses.put("1", InventorySynchronizedPddStrategy.class); + strategyClasses.put("2", InventorySynchronizedKWStrategy.class); + strategyClasses.put("5", InventorySynchronizedGFtrategy.class); + } + + public static InventorySynchronizedStrategy getStrategy(String type) { + Class strategyClass = strategyClasses.get(type); + if (strategyClass != null) { + return context.getBean(strategyClass); + } + return null; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + context = applicationContext; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/ShopGoodsFactory.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/ShopGoodsFactory.java new file mode 100644 index 0000000..60cc554 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/factory/ShopGoodsFactory.java @@ -0,0 +1,38 @@ +package org.dromara.zhishu.service.factory; + +import org.dromara.zhishu.service.strategy.*; +import org.springframework.beans.BeansException; +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 ShopGoodsFactory implements ApplicationContextAware { + + private static ApplicationContext context; + + private static final Map> strategyClasses = new HashMap<>(); + + static { + // 可以继续添加其他的消息类型对应的策略 + strategyClasses.put(1, ShopGoodsPddStrategy.class); + strategyClasses.put(2, ShopGoodsKWStrategy.class); + strategyClasses.put(3, ShopGoodsWlnStrategy.class); + } + + public static ShopGoodsStrategy getStrategy(Integer type) { + Class strategyClass = strategyClasses.get(type); + if (strategyClass != null) { + return context.getBean(strategyClass); + } + return null; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + context = applicationContext; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ArtNoMoveServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ArtNoMoveServiceImpl.java new file mode 100644 index 0000000..2f55a5f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ArtNoMoveServiceImpl.java @@ -0,0 +1,8 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.zhishu.service.IArtNoMoveService; +import org.springframework.stereotype.Service; + +@Service +public class ArtNoMoveServiceImpl implements IArtNoMoveService { +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/CountServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/CountServiceImpl.java new file mode 100644 index 0000000..06ec8ab --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/CountServiceImpl.java @@ -0,0 +1,33 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.Statistic; + +import org.dromara.zhishu.mapper.CountMapper; +import org.dromara.zhishu.service.CountService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class CountServiceImpl implements CountService { + + @Autowired + private CountMapper countMapper; + + @Override + public Statistic selectStatistic() { + Long userId = LoginHelper.getUserId(); + //查询当前用户下的库房 + List depotId = countMapper.selectDepotId(userId); + Long wNum = countMapper.selectW(userId); + Long sNum = countMapper.selectS(depotId); + Statistic statistic=new Statistic(); + statistic.setWarehousesNum(wNum); + statistic.setShelvesNum(sNum); + return statistic; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/CourierLogServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/CourierLogServiceImpl.java new file mode 100644 index 0000000..dd6ab6f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/CourierLogServiceImpl.java @@ -0,0 +1,111 @@ +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.CourierLog; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.CourierLogBo; +import org.dromara.zhishu.domain.vo.CourierLogVo; +import org.dromara.zhishu.service.ICourierLogService; + +import java.util.HashMap; +import java.util.List; +import java.util.Collection; +import java.util.Map; + +/** + * 快递日志Service业务层处理 + * + * @author yxy + * @date 2026-03-18 + */ +@RequiredArgsConstructor +@Service +public class CourierLogServiceImpl implements ICourierLogService { + + /** + * 查询快递日志 + * + * @param id 主键 + * @return 快递日志 + */ + @Override + public CourierLogVo queryById(Long id){ + String courierLogStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/courierLog/"+id,new HashMap<>()); + CourierLogVo courierLog = JsonUtil.transferToObj(courierLogStr, CourierLogVo.class); + return courierLog; + } + + /** + * 分页查询快递日志列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 快递日志分页列表 + */ + @Override + public TableDataInfo queryPageList(CourierLogBo bo, PageQuery pageQuery) { + + Map params = new HashMap<>(); + params.put("pageNum", pageQuery.getPageNum()); + params.put("pageSize", pageQuery.getPageSize()); + + // 添加查询条件 + if (bo.getErpOrderId() != null) { + params.put("erpOrderId", bo.getErpOrderId()); + } + if (bo.getOrderSn() != null && !bo.getOrderSn().isEmpty()) { + params.put("orderSn", bo.getOrderSn()); + } + if (bo.getPartnerId() != null && !bo.getPartnerId().isEmpty()) { + params.put("partnerId", bo.getPartnerId()); + } + if (bo.getOrderSerialNo() != null && !bo.getOrderSerialNo().isEmpty()) { + params.put("orderSerialNo", bo.getOrderSerialNo()); + } + + String courierLogListStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(), "/api/courierLog/getList", params); + Map dataMap = JsonUtil.transferToObj(courierLogListStr, Map.class); + List courierLogList = (List) dataMap.get("data"); + int total = (int) dataMap.get("total"); + + Page result = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize(), total); + result.setRecords(courierLogList); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的快递日志列表 + * + * @param bo 查询条件 + * @return 快递日志列表 + */ + @Override + public List queryList(CourierLogBo bo) { + // 导出功能可能需要,暂时返回null,如有需要可实现 + return null; + } + + + + /** + * 校验并批量删除快递日志信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + for (Long id : ids) { + InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(), "/api/courierLog/deleteById/" + id, 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/DepotOrderServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/DepotOrderServiceImpl.java new file mode 100644 index 0000000..4b5654d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/DepotOrderServiceImpl.java @@ -0,0 +1,157 @@ +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.DepotOrderBo; +import org.dromara.zhishu.domain.vo.DepotOrderVo; +import org.dromara.zhishu.domain.DepotOrder; +import org.dromara.zhishu.mapper.DepotOrderMapper; +import org.dromara.zhishu.service.IDepotOrderService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 仓库订单信息Service业务层处理 + * + * @author yxy + * @date 2025-06-03 + */ +@RequiredArgsConstructor +@Service +public class DepotOrderServiceImpl implements IDepotOrderService { + + private final DepotOrderMapper baseMapper; + + /** + * 查询仓库订单信息 + * + * @param id 主键 + * @return 仓库订单信息 + */ + @Override + public DepotOrderVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询仓库订单信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 仓库订单信息分页列表 + */ + @Override + public TableDataInfo queryPageList(DepotOrderBo bo, PageQuery pageQuery) { + + + + bo.setPageNum(pageQuery.getPageNum() - 1); + bo.setPageSize(pageQuery.getPageSize()); + bo.setDelFlag("0"); + //LoginHelper.getUserId().toString() + bo.setUserId(Long.valueOf(LoginHelper.getUserId().toString())); + List depotOrderVoList = baseMapper.selectListPage(bo); + + + Page result = new Page<>(); + result.setCurrent(pageQuery.getPageNum()); + result.setSize(pageQuery.getPageSize()); + result.setTotal(baseMapper.selectTotal(bo)); + result.setRecords(depotOrderVoList); + + + return TableDataInfo.build(result); + } + + @Override + public DepotOrderVo selectDepotOrderById(String id){ + return baseMapper.selectDepotOrderById(id); + } + + /** + * 查询符合条件的仓库订单信息列表 + * + * @param bo 查询条件 + * @return 仓库订单信息列表 + */ + @Override + public List queryList(DepotOrderBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(DepotOrderBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(DepotOrder::getId); + lqw.eq(StringUtils.isNotBlank(bo.getShopOrderId()), DepotOrder::getShopOrderId, bo.getShopOrderId()); + lqw.eq(bo.getUserId() != null, DepotOrder::getUserId, bo.getUserId()); + lqw.eq(StringUtils.isNotBlank(bo.getItemList()), DepotOrder::getItemList, bo.getItemList()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), DepotOrder::getStatus, bo.getStatus()); + lqw.eq(bo.getCreateBy() != null, DepotOrder::getCreateBy, bo.getCreateBy()); + lqw.eq(bo.getCreateTime() != null, DepotOrder::getCreateTime, bo.getCreateTime()); + return lqw; + } + + /** + * 新增仓库订单信息 + * + * @param bo 仓库订单信息 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(DepotOrderBo bo) { + DepotOrder add = MapstructUtils.convert(bo, DepotOrder.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改仓库订单信息 + * + * @param bo 仓库订单信息 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(DepotOrderBo bo) { + DepotOrder update = MapstructUtils.convert(bo, DepotOrder.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DepotOrder 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/EmployeeServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/EmployeeServiceImpl.java new file mode 100644 index 0000000..ef33698 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/EmployeeServiceImpl.java @@ -0,0 +1,54 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.zhishu.domain.vo.EmployeeVo; +import org.dromara.zhishu.mapper.EmployeeMapper; +import org.dromara.zhishu.service.EmployeeService; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.util.List; + +@RequiredArgsConstructor +@Service +@Slf4j +public class EmployeeServiceImpl implements EmployeeService { + + private final EmployeeMapper employeeMapper; + + @Override + public List getEmployeeList(String userId) { + return employeeMapper.getEmployeeInfo(userId); + } + + @Override + public Boolean addEmployee(String employeeId, String employeeName, String userId) { + EmployeeVo employeeVo = new EmployeeVo(); + employeeVo.setId(employeeId); + employeeVo.setName(employeeName); + employeeVo.setUserId(Long.parseLong(userId)); + long timestamp = Instant.now().getEpochSecond(); + employeeVo.setCreatTime(timestamp); + employeeVo.setUpdateTime(timestamp); + employeeVo.setDelFlag(0); + return employeeMapper.addEmployee(employeeVo) > 0; + } + + @Override + public Boolean updateEmployee(String employeeId, String employeeName, String userId) { + long timestampSeconds = Instant.now().getEpochSecond(); + EmployeeVo employeeVo = new EmployeeVo(); + employeeVo.setId(employeeId); + employeeVo.setName(employeeName); + employeeVo.setUserId(Long.parseLong(userId)); + employeeVo.setUpdateTime(timestampSeconds); + return employeeMapper.updateEmployee(employeeVo) > 0; + } + + @Override + public Boolean delEmployee(String id, String userId) { + return employeeMapper.delEmployee(id, Long.parseLong(userId)) > 0; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/FastMailServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/FastMailServiceImpl.java new file mode 100644 index 0000000..09f3146 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/FastMailServiceImpl.java @@ -0,0 +1,341 @@ +package org.dromara.zhishu.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.dromara.common.core.domain.R; +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.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.FastMailBo; +import org.dromara.zhishu.domain.vo.FastMailVo; +import org.dromara.zhishu.domain.FastMail; +import org.dromara.zhishu.mapper.FastMailMapper; +import org.dromara.zhishu.service.IFastMailService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 快递打单账号管理Service业务层处理 + * + * @author yxy + * @date 2025-06-06 + */ +@RequiredArgsConstructor +@Service +public class FastMailServiceImpl implements IFastMailService { + + private final FastMailMapper baseMapper; + + /** + * 查询快递打单账号管理 + * + * @param id 主键 + * @return 快递打单账号管理 + */ + @Override + public FastMailVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 根据用户id和快递类型查询 + * @param userId + * @param type + * @return + */ + @Override + public FastMailVo selectByUserIdAndType(String userId,String type){ + return baseMapper.selectByUserIdAndType(userId,type); + } + + /** + * 分页查询快递打单账号管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 快递打单账号管理分页列表 + */ + @Override + public TableDataInfo queryPageList(FastMailBo 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); + List fastMailVoList = result.getRecords(); + for (FastMailVo vo : fastMailVoList){ + Map map = new HashMap(); + if (vo.getFastMailType().equals("1")){ + if(vo.getType().equals("YUNDA")){ + map.put("partnerId",vo.getPartnerId()); + map.put("secret",vo.getSecret()); + map.put("type","common"); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/searchCount",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (commonDataMap.get("code").equals("200") && !commonDataMap.get("data").toString().contains("ERROR")){ + // 韵达调用成功后,在调用获取 "代收货款" 的数量 + List commonDataList = (List) commonDataMap.get("data"); + Map commonData = (Map) commonDataList.get(0); + String commonRemainNum = commonData.get("remain_num").toString(); + map.put("type","cod"); + String codStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/searchCount",map); + Map codDataMap = JsonUtil.transferToObj(codStr,Map.class); + List codDataList = (List) codDataMap.get("data"); + Map codData = (Map) codDataList.get(0); + String codRemainNum = codData.get("remain_num").toString(); + vo.setCommonRemainNum(commonRemainNum); + vo.setCodRemainNum(codRemainNum); + }else{ + // 赋值0 + vo.setCommonRemainNum("异常"); + vo.setCodRemainNum("异常"); + } + }else if (vo.getType().equals("ZTO")){ + map.put("expressDeliveryType","ZTO"); + map.put("account",vo.getPartnerId()); + map.put("password",vo.getSecret()); + String codStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/faceSheetBalance",map); + Map codDataMap = JsonUtil.transferToObj(codStr,Map.class); + if (codDataMap.get("message").toString().equals("操作成功")){ + vo.setRemark(JsonUtil.transferToJson(codDataMap.get("result"))); + } + System.out.println(codDataMap); + }else if (vo.getType().equals("JTSD")){ + // 极兔快递获取余额 + map.put("customerCode",vo.getPartnerId()); + map.put("password",vo.getSecret()); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/jtPrint/jtEssBalance",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (commonDataMap.get("msg").equals("success")){ + Map data = (Map) commonDataMap.get("data"); + vo.setRemark(data.get("balance").toString()); + } + } + } + } + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的快递打单账号管理列表 + * + * @param bo 查询条件 + * @return 快递打单账号管理列表 + */ + @Override + public List queryList(FastMailBo bo) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + // 获取白名单 + if (userId != 1) { + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + @Override + public List queryListApi(Long userId){ + FastMailBo bo = new FastMailBo(); + bo.setCreateBy(userId); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List fastMailVoList = baseMapper.selectVoList(lqw); + for (FastMailVo vo : fastMailVoList){ + Map map = new HashMap(); + map.put("partnerId",vo.getPartnerId()); + map.put("secret",vo.getSecret()); + map.put("type","common"); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/searchCount",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (commonDataMap.get("code").equals("200") && !commonDataMap.get("data").toString().contains("ERROR")){ + List commonDataList = (List) commonDataMap.get("data"); + Map commonData = (Map) commonDataList.get(0); + String commonRemainNum = commonData.get("remain_num").toString(); + map.put("type","cod"); + String codStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/searchCount",map); + Map codDataMap = JsonUtil.transferToObj(codStr,Map.class); + List codDataList = (List) codDataMap.get("data"); + Map codData = (Map) codDataList.get(0); + String codRemainNum = codData.get("remain_num").toString(); + vo.setCommonRemainNum(commonRemainNum); + vo.setCodRemainNum(codRemainNum); + }else{ + // 赋值0 + vo.setCommonRemainNum("异常"); + vo.setCodRemainNum("异常"); + } + } + return fastMailVoList; + } + + private LambdaQueryWrapper buildQueryWrapper(FastMailBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(FastMail::getId); + lqw.eq(bo.getCreateBy() != null, FastMail::getCreateBy, bo.getCreateBy()); + lqw.eq(StringUtils.isNotBlank(bo.getType()), FastMail::getType, bo.getType()); + lqw.eq(StringUtils.isNotBlank(bo.getPartnerId()), FastMail::getPartnerId, bo.getPartnerId()); + lqw.eq(StringUtils.isNotBlank(bo.getSecret()), FastMail::getSecret, bo.getSecret()); + lqw.eq(StringUtils.isNotBlank(bo.getFastMailType()), FastMail::getFastMailType, bo.getFastMailType()); + lqw.eq(bo.getCreateTime() != null, FastMail::getCreateTime, bo.getCreateTime()); + lqw.eq(bo.getUpdateTime() != null, FastMail::getUpdateTime, bo.getUpdateTime()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), FastMail::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增快递打单账号管理 + * + * @param bo 快递打单账号管理 + * @return 是否新增成功 + */ + @Override + public R insertByBo(FastMailBo bo) { + // 网点面单的情况进行校验 + if (bo.getFastMailType().equals("1")){ + FastMailVo fastMailVo = selectByUserIdAndType(LoginHelper.getUserId().toString(),bo.getType()); + if(fastMailVo != null){ + return R.fail("该用户已存在该类型的快递打单账号"); + } + Map map = new HashMap(); + if(bo.getType().equals("YUNDA")){ + // 韵达 + map.put("partnerId",bo.getPartnerId()); + map.put("secret",bo.getSecret()); + map.put("type","common"); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/searchCount",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (commonDataMap.get("data").toString().contains("ERROR")){ + return R.fail("账号或联调密码不正确"); + } + }else if (bo.getType().equals("ZTO")){ + // 中通 + map.put("expressDeliveryType",bo.getType()); + map.put("account",bo.getPartnerId()); + map.put("password",bo.getSecret()); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("siteCode",bo.getRemark()); + map.put("json",jsonObject.toString()); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/ztoPrint/bindingEaccount",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (!commonDataMap.get("message").toString().contains("已绑定") && !commonDataMap.get("message").toString().contains("已绑定成功")){ + return R.fail(commonDataMap.get("message").toString()); + }else{ + bo.setRemark(jsonObject.toString()); + } + }else if (bo.getType().equals("JTSD")){ + // 极兔速递 + map.put("customerCode",bo.getPartnerId()); + map.put("password",bo.getSecret()); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/jtPrint/jtVipCheckCusPwd",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (!commonDataMap.get("msg").equals("success")){ + return R.fail(commonDataMap.get("msg").toString()); + } + } + } + + FastMail add = MapstructUtils.convert(bo, FastMail.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return R.ok("新增成功"); + } + + /** + * 修改快递打单账号管理 + * + * @param bo 快递打单账号管理 + * @return 是否修改成功 + */ + @Override + public R updateByBo(FastMailBo bo) { + + if (bo.getFastMailType().equals("1")){ + Map map = new HashMap(); + if(bo.getType().equals("YUNDA")){ + map.put("partnerId",bo.getPartnerId()); + map.put("secret",bo.getSecret()); + map.put("type","common"); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/print/searchCount",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (commonDataMap.get("data").toString().contains("ERROR")){ + return R.fail("账号或联调密码不正确"); + } + }else if (bo.getType().equals("ZTO")){ + // 中通 + map.put("expressDeliveryType",bo.getType()); + map.put("account",bo.getPartnerId()); + map.put("password",bo.getSecret()); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("siteCode",bo.getRemark()); + map.put("json",jsonObject.toString()); + String commonStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/ztoPrint/bindingEaccount",map); + Map commonDataMap = JsonUtil.transferToObj(commonStr,Map.class); + if (!commonDataMap.get("message").toString().contains("已绑定") && !commonDataMap.get("message").toString().contains("已绑定成功")){ + return R.fail(commonDataMap.get("message").toString()); + }else{ + bo.setRemark(jsonObject.toString()); + } + } + } + FastMail update = MapstructUtils.convert(bo, FastMail.class); + validEntityBeforeSave(update); + if (baseMapper.updateById(update) > 0){ + return R.ok("修改成功"); + }else { + return R.fail("修改失败"); + } + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FastMail entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除快递打单账号管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 根据面单类型删除数据 + * @param fastMailType + * @return + */ + @Override + public int deleteByFastMailType(Long userId,String fastMailType){ + return baseMapper.deleteByFastMailType(userId,fastMailType); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/FilterSetServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/FilterSetServiceImpl.java new file mode 100644 index 0000000..dfc3ac2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/FilterSetServiceImpl.java @@ -0,0 +1,203 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +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.satoken.utils.LoginHelper; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.FilterSetBo; +import org.dromara.zhishu.domain.vo.FilterSetVo; +import org.dromara.zhishu.domain.FilterSet; +import org.dromara.zhishu.mapper.FilterSetMapper; +import org.dromara.zhishu.service.IFilterSetService; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.stream.Collectors; + +/** + * 过滤设置Service业务层处理 + * + * @author yxy + * @date 2025-04-14 + */ +@RequiredArgsConstructor +@Service +public class FilterSetServiceImpl implements IFilterSetService { + + private final FilterSetMapper baseMapper; + + /** + * 查询过滤设置 + * + * @param id 主键 + * @return 过滤设置 + */ + @DS("taskSlave") + @Override + public FilterSetVo queryById(Long id){ + FilterSetVo vo = baseMapper.selectVoById(id); + return vo; + } + + /** + * 分页查询过滤设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 过滤设置分页列表 + */ + @DS("taskSlave") + @Override + public TableDataInfo queryPageList(FilterSetBo bo, PageQuery pageQuery) { + + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + bo.setCreateBy(userId); +// if (userId != 1) { +// bo.setCreateBy(userId); +// } + + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @DS("taskSlave") + @Override + public List selectVoListByBo(FilterSetBo bo) { + // 获取当前用户id + Long userId = LoginHelper.getUserId() == null ? 1L : LoginHelper.getUserId(); + bo.setCreateBy(userId); + return baseMapper.selectVoListByBo(bo); + } + + @DS("taskSlave") + @Override + public int deleteTrueById(Long id){ + return baseMapper.deleteTrueById(id); + } + + /** + * 查询符合条件的过滤设置列表 + * + * @param bo 查询条件 + * @return 过滤设置列表 + */ + @DS("taskSlave") + @Override + public List queryList(FilterSetBo bo) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + if (userId != 1) { + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(FilterSetBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); +// lqw.orderByAsc(FilterSet::getId); + lqw.orderByDesc(FilterSet::getCreateTime); + lqw.eq(StringUtils.isNotBlank(bo.getFilterType()), FilterSet::getFilterType, bo.getFilterType()); + lqw.eq(StringUtils.isNotBlank(bo.getLimitationType()), FilterSet::getLimitationType, bo.getLimitationType()); + lqw.eq(StringUtils.isNotBlank(bo.getAddWay()), FilterSet::getAddWay, bo.getAddWay()); + lqw.like(StringUtils.isNotBlank(bo.getAddTxt()), FilterSet::getAddTxt, bo.getAddTxt()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), FilterSet::getStatus, bo.getStatus()); + // 处理 sort 条件 + if (StringUtils.isNotEmpty(bo.getSort())) { + String[] sortArray = bo.getSort().split(","); + List sortList = Arrays.stream(sortArray) + .filter(StringUtils::isNotEmpty) + .map(String::trim) + .collect(Collectors.toList()); + + // 使用 FIND_IN_SET,更稳定 + for (String sortValue : sortList) { + lqw.apply("FIND_IN_SET({0}, sort) > 0", sortValue); + } + } + + + + lqw.eq(bo.getCreateBy() != null, FilterSet::getCreateBy, bo.getCreateBy()); + return lqw; + } + + /** + * 新增过滤设置 + * + * @param bo 过滤设置 + * @return 是否新增成功 + */ + @DS("taskSlave") + @Override + public Boolean insertByBo(FilterSetBo bo) { + Long userId = LoginHelper.getUserId() == null ? 1L : LoginHelper.getUserId(); + + bo.setCreateBy(userId); + bo.setCreateTime(DateUtils.getNowDate()); + bo.setUpdateBy(userId); + bo.setUpdateTime(DateUtils.getNowDate()); + + FilterSet add = MapstructUtils.convert(bo, FilterSet.class); + add.setSort(bo.getSort()); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改过滤设置 + * + * @param bo 过滤设置 + * @return 是否修改成功 + */ + @DS("taskSlave") + @Override + public Boolean updateByBo(FilterSetBo bo) { + FilterSet update = MapstructUtils.convert(bo, FilterSet.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(FilterSet entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除过滤设置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @DS("taskSlave") + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + for (Long id : ids){ + baseMapper.deleteTrueById(id); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/GoofishServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/GoofishServiceImpl.java new file mode 100644 index 0000000..ae921ab --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/GoofishServiceImpl.java @@ -0,0 +1,258 @@ +package org.dromara.zhishu.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonArray; +import lombok.RequiredArgsConstructor; + + +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.service.*; +import org.springframework.stereotype.Service; +import java.nio.charset.StandardCharsets; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.util.ArrayList; +import java.util.HexFormat; +import java.util.List; + + +/** + * 店铺主表Service业务层处理 + * + * @author yxy + * @date 2025-05-8 + */ +@RequiredArgsConstructor +@Service +public class GoofishServiceImpl implements IGoofishService { + + private final IShopService shopService; + private final ISysConfigService configService; + private final IPriceTemplateService priceTemplateService; + + + @Override + public void goodAdd(ShopVo shop, ZhishuShopGoods zhishuShopGoods, ShopDetailVo shopDetailVo) { + long timestamp = System.currentTimeMillis() / 1000L; + // 生成签名 + String domain = "https://open.goofish.pro"; // 域名 + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("product_id", Long.parseLong(zhishuShopGoods.getProductId())); + jsonObject.put("stock", zhishuShopGoods.getInventory()); + System.out.println("入参goofish"+jsonObject.toJSONString()); + + // 生成签名 + String sign = genSign(timestamp, jsonObject.toJSONString(), shop.getMallId().toString(), shop.getToken()); + //调用编辑库存的接口 + String apiUrl = domain + "/api/open/product/edit/stock?appid=" + shop.getMallId().toString() + "×tamp=" + timestamp + "&sign=" + + sign; + try { + // 创建URL对象 + URL url = new URL(apiUrl); + + // 打开连接 + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + // 设置请求方法为POST + connection.setRequestMethod("POST"); + + // 设置请求头部 + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept", "application/json"); + + // 启用输出流 + connection.setDoOutput(true); + + // 获取输出流并写入请求体 + OutputStream outputStream = connection.getOutputStream(); + outputStream.write(jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8)); + outputStream.close(); + + // 获取响应状态码 + int responseCode = connection.getResponseCode(); + System.out.println("API Response Code: " + responseCode); + + // 读取响应内容 + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + StringBuilder response = new StringBuilder(); + while ((line = bufferedReader.readLine()) != null) { + response.append(line); + } + bufferedReader.close(); + + // 关闭连接 + connection.disconnect(); + + System.out.println("API Response: " + response.toString()); + + } catch (IOException e) { + // 在此处处理异常 + e.printStackTrace(); + } + } + + + + + /** + * 调用闲鱼服务接口修改商品库存 + * @param + */ + public void goodUpdateStock(ShopVo shop, String itemId, String number,Integer type){ + + long timestamp = System.currentTimeMillis() / 1000L; + // 生成签名 + String domain = "https://open.goofish.pro"; // 域名 + + // 请求体JSON字符串 + //String productId = itemId; + + JSONObject jsonObject = new JSONObject(); + + + // 生成签名 + + String apiUrl=null; + String sign=null; + + if (2==type){ + jsonObject.put("product_id", Long.parseLong(itemId)); + jsonObject.put("stock", Long.parseLong(number)); + System.out.println("入参goofish"+jsonObject.toJSONString()); + sign = genSign(timestamp, jsonObject.toJSONString(), shop.getMallId().toString(), shop.getToken()); + if ("0".equals(number)){ + + //调用下架商品 + // 拼接请求地址 + apiUrl = domain + "/api/open/product/downShelf?appid=" + shop.getMallId().toString() + "×tamp=" + timestamp + "&sign=" + + sign; + + }else{ + //调用编辑库存的接口 + apiUrl = domain + "/api/open/product/edit/stock?appid=" + shop.getMallId().toString() + "×tamp=" + timestamp + "&sign=" + + sign; + } + } else if (3==type) { + + //调用上架商品 + if ("1".equals(number)){ + List jsonArray=new ArrayList<>(); + jsonArray.add(shop.getShopKey()); + jsonObject.put("product_id", Long.parseLong(itemId)); + jsonObject.put("user_name", jsonArray); + System.out.println("入参goofish1 3"+jsonObject.toJSONString()); + sign = genSign(timestamp, jsonObject.toJSONString(), shop.getMallId().toString(), shop.getToken()); + + //调用下架商品 + // 拼接请求地址 + apiUrl = domain + "/api/open/product/publish?appid=" + shop.getMallId().toString() + "×tamp=" + timestamp + "&sign=" + + sign; + + }else{ + jsonObject.put("product_id", Long.parseLong(itemId)); + jsonObject.put("stock", Long.parseLong(number)); + System.out.println("入参goofish 3"+jsonObject.toJSONString()); + sign = genSign(timestamp, jsonObject.toJSONString(), shop.getMallId().toString(), shop.getToken()); + + //调用编辑库存的接口 + apiUrl = domain + "/api/open/product/edit/stock?appid=" + shop.getMallId().toString() + "×tamp=" + timestamp + "&sign=" + + sign; + } + + } + + + try { + // 创建URL对象 + URL url = new URL(apiUrl); + + // 打开连接 + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + // 设置请求方法为POST + connection.setRequestMethod("POST"); + + // 设置请求头部 + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Accept", "application/json"); + + // 启用输出流 + connection.setDoOutput(true); + + // 获取输出流并写入请求体 + OutputStream outputStream = connection.getOutputStream(); + outputStream.write(jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8)); + outputStream.close(); + + // 获取响应状态码 + int responseCode = connection.getResponseCode(); + System.out.println("API Response Code: " + responseCode); + + // 读取响应内容 + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + StringBuilder response = new StringBuilder(); + while ((line = bufferedReader.readLine()) != null) { + response.append(line); + } + bufferedReader.close(); + + // 关闭连接 + connection.disconnect(); + + System.out.println("API Response: " + response.toString()); + + } catch (IOException e) { + // 在此处处理异常 + e.printStackTrace(); + } + + } + + + + + // 生成签名 + private static String genSign(long timestamp, String jsonStr, String apiKey, String apiKeySecret) { + // 拼接字符串 + String data = apiKey + "," + genMd5(jsonStr) + "," + timestamp + "," + apiKeySecret; + + // 商务对接模式 拼接字符串 + // String data = apiKey + "," + genMd5(jsonStr) + "," + timestamp + "," + seller_id + "," + apiKeySecret; + + // 生成签名 + return genMd5(data); + } + + // md5加密 + private static String genMd5(String str) { + StringBuilder result = new StringBuilder(); + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(str.getBytes(StandardCharsets.UTF_8)); + for (byte b : digest) { + result.append(String.format("%02x", b & 0xff)); + } + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + return result.toString(); + } + +} + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/KongfzItemService.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/KongfzItemService.java new file mode 100644 index 0000000..318cde7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/KongfzItemService.java @@ -0,0 +1,128 @@ +// service/KongfzItemService.java +package org.dromara.zhishu.service.impl; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import kotlin.Result; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.hpsf.Decimal; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.dto.KongfzRequestDto; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.dromara.zhishu.util.HttpUtils; +import org.dromara.zhishu.util.KongfzApiUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.configurationprocessor.json.JSONException; +import org.springframework.boot.configurationprocessor.json.JSONObject; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +public class KongfzItemService { + + @Autowired + private KongfzApiUtils kongfzApiUtils; + @Autowired + private ZhishuShopGoodsMapper zhishuShopGoodsMapper; + @Autowired + private ObjectMapper objectMapper; + + public String getShopInfo(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url, headers, requestBody); + } + + + public String listing(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + + } + + public String delisting(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + } + + public String shopList(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + } + + public String updateItemNumber(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + } + + + public String updateItemPrice(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + } + + public String updateItemName(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + } + + public String updateItemsn(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + } + + public String deleteItem(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + return HttpUtils.sendPost(url,headers,requestBody); + } + + public String batchDeleteItem(Map params) throws Exception { + String url = "https://kongfz-api.kongfz.com"; + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + String requestBody = HttpUtils.convertObjectToJson(params); + + return HttpUtils.sendPost(url,headers,requestBody); + } + +} + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/KongfzServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/KongfzServiceImpl.java new file mode 100644 index 0000000..e10825b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/KongfzServiceImpl.java @@ -0,0 +1,328 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.ZhishuShopImages; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.util.CnumberUtils; +import org.dromara.zhishu.util.ImageUtils; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UploadUtil; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.file.Path; +import java.util.*; + +/** + * 店铺主表Service业务层处理 + * + * @author yxy + * @date 2025-05-8 + */ +@RequiredArgsConstructor +@Service +public class KongfzServiceImpl implements IKongFzService { + + private final IShopService shopService; + private final ISysConfigService configService; + private final IBookBaseInfoService bookBaseInfoService; + private final IZhishuShopImagesService zhishuShopImagesService; + private final IPriceTemplateService priceTemplateService; + private final IShopImgService shopImgService; + +// @Override +// public void goodAdd(String shopId, ZhishuShopGoods zhishuShopGoods, ShopDetailVo shopDetailVo) { +// //店铺数据 +// ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); +// //获取中心书库的数据 +// BookBaseInfoVo bookBaseInfoVo = bookBaseInfoService.queryByIsbn(zhishuShopGoods.getIsbn()); +// //获取实拍图 +// List zhishuShopImagesVoList = zhishuShopImagesService.selectShopImagesByShopId(zhishuShopGoods.getId()); +// +// +// +// Map map = new HashMap(); +// map.put("shopId",shopId); +// map.put("goodId", zhishuShopGoods.getId()); +// map.put("userId", zhishuShopGoods.getUserId()); +// map.put("token",shopVo.getToken()); +// map.put("tpl",shopDetailVo.getBookTemplate()); +// map.put("catId",""); +// map.put("myCatId",""); +// /** +// * 获取书名和中央书库不匹配 +// */ +// if (!zhishuShopGoods.getGoodsName().equals(bookBaseInfoVo.getBookName())){ +// map.put("otherName",zhishuShopGoods.getGoodsName()); +// } +// /** +// * 商品标题 +// */ +// map.put("itemName",getGoodTitle(shopDetailVo,zhishuShopGoods,bookBaseInfoVo)); +// map.put("importantDesc",shopDetailVo.getRecommend()); +// /** +// * 价格 +// */ +// map.put("price",getPrice(shopDetailVo,zhishuShopGoods)); +// map.put("number",zhishuShopGoods.getInventory()); +// if(StringUtils.isNotEmpty(zhishuShopGoods.getConditionCode())){ +// String qualityNum = CnumberUtils.getQualityNum(zhishuShopGoods.getConditionCode()); +// if(!qualityNum.equals("UNDEFINED")){ +// map.put("quality",qualityNum); +// }else{ +// map.put("quality",shopDetailVo.getConditionDef()); +// } +// }else{ +// map.put("quality",shopDetailVo.getConditionDef()); +// } +// +// map.put("qualityDesc",shopDetailVo.getConditionDes()); +// map.put("itemSn",zhishuShopGoods.getArtNo()); +// /** +// * 获取水印图片 +// */ +// /** +// * 封面水印 specSyImageUrl +// */ +// String specSyImageUrl = ""; +// List shopImgList = shopImgService.selectVoByShopId(shopId); +// for (ShopImgVo shopImgMap : shopImgList){ +// specSyImageUrl = shopImgMap.getAbsolutePath(); +// } +// +// //无水印图片记录 +// String noSyImage = ""; +// String images = ""; +// if(zhishuShopImagesVoList.size() == 0){ +// //没有实拍图则获取中心书库的图片 +// String image = UploadUtil.getFiles(bookBaseInfoVo.getBookName(), bookBaseInfoVo.getBookPic(),"bookInfoImages",""); +// +// //如果图片访问不到 +// Boolean bool = ImageUtils.isImageExists(image); +// if(!bool){ +// //白底图 +// image = getWhiteImage(zhishuShopGoods); +// noSyImage = image; +// }else{ +// noSyImage = image; +// //图片增加水印,若报错则返回白底图 +// if(specSyImageUrl != ""){ +// image = getImageSy(specSyImageUrl,image,zhishuShopGoods); +// } +// } +// System.out.println("中央书库上传首图-------------"+image+";书名:"+bookBaseInfoVo.getBookName()); +// map.put("imgUrl", image); +// //实拍图 +// images = image; +// }else{ +// //第一张图作为首图,第一张肯定有水印 +// String imageFirst = UploadUtil.getFiles("", "","",zhishuShopImagesVoList.get(0).getPath()); +// +// +// noSyImage = imageFirst; +// if(specSyImageUrl != ""){ +// imageFirst = getImageSy(specSyImageUrl,imageFirst,zhishuShopGoods); +// } +// System.out.println("用户上传首图-------------"+imageFirst+";书名:"+zhishuShopGoods.getGoodsName()); +// map.put("imgUrl", imageFirst); +// // WatermarkPosition 水印位置 0 全部 1第一张 +// if(shopDetailVo.getWatermarkPosition().equals("0")){ +// //为0是全部增加水印 +// for(ZhishuShopImagesVo vo : zhishuShopImagesVoList){ +// //图片路径 +// String image = UploadUtil.getFiles("","","",vo.getPath()); +// //水印不为空则增加水印 +// if(specSyImageUrl != ""){ +// image = getImageSy(specSyImageUrl,image,zhishuShopGoods); +// } +// System.out.println("用户上传后续-------------"+image+";书名:"+zhishuShopGoods.getGoodsName()); +// //记录图片 +// if(images == ""){ +// images = image; +// }else{ +// images = images + ";" + image; +// } +// } +// }else{ +// //实拍图 为1时,正常不加水印图片 +// for(ZhishuShopImagesVo vo : zhishuShopImagesVoList){ +// String image = UploadUtil.getFiles("","","",vo.getPath()); +// System.out.println("实拍图 为1时,正常不加水印图片:用户上传后续-------------"+image+";书名:"+zhishuShopGoods.getGoodsName()); +// if(images == ""){ +// images = image; +// }else{ +// images = images + ";" + image; +// } +// } +// } +// } +// //只有1张图片,并且只在第一张图片上加水印 +// if(images.split(";").length == 1 && shopDetailVo.getWatermarkPosition().equals("1")){ +// images = images +";"+ noSyImage; +// } +// int index = images.indexOf(";") + 1; +// if(index != -1){ +// images = images.substring(index); +// } +// +// +// map.put("images",images); +// +// map.put("itemDesc",bookBaseInfoVo.getContent()); +// if(shopDetailVo.getIsParcel().equals("0")){ +// //不包邮 +// map.put("bearShipping","buyer"); +// }else{ +// //包邮 +// map.put("bearShipping","seller"); +// } +// map.put("mouldld", shopDetailVo.getTemplateId()); +// map.put("weight",shopDetailVo.getBookWeight()); +// map.put("weightPiece",shopDetailVo.getStandardNumber()); +// +// map.put("isbn",zhishuShopGoods.getIsbn()); +// map.put("author",bookBaseInfoVo.getAuthor()); +// map.put("press",bookBaseInfoVo.getPublisher()); +// map.put("pubDate",bookBaseInfoVo.getPublicationTime()); +// map.put("binding",bookBaseInfoVo.getBindingLayout()); +// map.put("oriPrice",bookBaseInfoVo.getFixPrice()); +// +// InterfaceUtils.getInterfacePost(configService.selectConfigByKey("kongfz.ip"), "/api/kfz/goodAddOne", map); +// +// } + + /** + * 获取商品标题 + * @return + */ + public String getGoodTitle(ShopDetailVo shopDetailVo,ZhishuShopGoods zhishuShopGoods,BookBaseInfoVo bookBaseInfoVo){ + //获取标题组成的内容 + String titleStr = shopDetailVo.getTitleConsistOf(); + String[] titleOfArr = titleStr.split(","); + titleStr = ""; + for(int i=0;i 0){ + //大于最高价 + priceL = highPrice; + }else{ + priceL = priceOld; + } + + //获取价格模板 + PriceTemplateVo priceTemplateVo = priceTemplateService.queryById(shopDetailVo.getSaleTemplateId()); + + //根据价格模板换算后的价格 + BigDecimal price = new BigDecimal(String.valueOf(priceTemplateVo.getProportion())) + .divide(new BigDecimal(100)) + .multiply(priceL) + .add(priceL) + .add(new BigDecimal(priceTemplateVo.getAddAmount().toString())) + .multiply(new BigDecimal(100)) + .setScale(0, RoundingMode.DOWN); + + return price.toString(); + } + + /** + * 获取白底图 + */ + public String getWhiteImage(ZhishuShopGoods zhishuShopGoods){ + String uuid = UUID.randomUUID().toString(); + String fileUrl = ImageUtils.generateImage(zhishuShopGoods.getGoodsName(), 800, 800,uuid+".jpg"); + MultipartFile multipartFile = UploadUtil.getMultipartFileFromPath(fileUrl); + //上传文件 + UploadUtil.upload(multipartFile,"userShopGoodsImages"); + //获取上传文件网络地址 + return UploadUtil.getFiles("","","","other/"+ LoginHelper.getUserId()+"/userShopGoodsImages/"+uuid+".jpg"); + } + + /** + * 处理水印图片 + * specSyImageUrl 水印图片 + */ + public String getImageSy(String specSyImageUrl,String iamge,ZhishuShopGoods zhishuShopGoods){ + + try { + String uuid = UUID.randomUUID().toString(); + //本地缓存路径 + String filePath = UploadUtil.mergeImages(iamge,specSyImageUrl); + MultipartFile multipartFile = UploadUtil.getMultipartFileFromPath(filePath); + //上传图片空间 + UploadUtil.upload(multipartFile,"userShopGoodsImages"); + //获取图片空间路径 + return UploadUtil.getFiles("","","","other/"+ LoginHelper.getUserId()+"/userShopGoodsImages/"+multipartFile.getOriginalFilename()); + } catch (IOException e) { + e.printStackTrace(); + return getWhiteImage(zhishuShopGoods); + } + } + + /** + * 调用kongfz服务接口修改商品库存 + * @param map + */ + public void goodUpdateStock(String token,String itemId,String number){ + Map map = new HashMap(); + map.put("token",token); + map.put("itemId",itemId); + map.put("number",number); + InterfaceUtils.getInterfacePost(configService.selectConfigByKey("kongfz.ip"), "/api/kfz/itemNumberUpdate", map); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/LogisticsServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/LogisticsServiceImpl.java new file mode 100644 index 0000000..b6308f1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/LogisticsServiceImpl.java @@ -0,0 +1,139 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.zhishu.domain.Logistics; +import org.dromara.zhishu.domain.bo.LogisticsBo; +import org.dromara.zhishu.mapper.LogisticsMapper; +import org.dromara.zhishu.service.LogisticsService; +import org.dromara.zhishu.util.JsonObjUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +public class LogisticsServiceImpl implements LogisticsService { + @Autowired + private LogisticsMapper logisticsMapper; + ; + + @Override + public Integer insert(LogisticsBo bo) { + Logistics add = new Logistics(); + String are = logisticsMapper.selectByArea(bo.getDelivery_area(), bo.getDelivery_city()); + String city = logisticsMapper.selectByCity(bo.getDelivery_city(), bo.getDelivery_province()); + String province = logisticsMapper.selectByProvince(bo.getDelivery_province()); + add.setDeliveryProvince(province); + add.setDeliveryCity(city); + add.setDeliveryArea(are); + + add.setPricingMethod(bo.getPricing_method().toString()); + add.setShipping(bo.getShipping()); + add.setStatus("0"); + add.setWarehouseId(bo.getWarehouse_id()); + + if (city == null) { + add.setDeliveryAddress(province + "/" + are); + } else { + add.setDeliveryAddress(province + "/" + city + "/" + are); + } + add.setTemplateName(bo.getTemplate_name()); + log.info("打印数据-{}", JSONObject.toJSONString(bo)); + add.setShippingRange(JSONObject.toJSONString(bo.getShippingRange())); + add.setRemark(bo.getRemark()); + logisticsMapper.insert(add); + System.out.println(add); + return 0; + } + + @Override + public List selectLogistics(String warehouseId) { + return logisticsMapper.selectLogistice(warehouseId); + } + + @Override + public Logistics queryById(Long id) { + Logistics logistics = logisticsMapper.selectByWareId(id); + if(logistics!=null) { + String[] name = logistics.getDeliveryAddress().split("/"); + Long proId =logisticsMapper.selectByid(name[0],null,null,null,null); + Long cityId =logisticsMapper.selectByid(null,name[1],null,proId,null); + Long areaId =logisticsMapper.selectByid(null,null,name[2],proId,cityId); + logistics.setDeliveryProvince(proId.toString()); + logistics.setDeliveryCity(cityId.toString()); + logistics.setDeliveryArea(areaId.toString()); + } + return logistics; +// return null; + } + + @Override + public Boolean setTemplate(LogisticsBo bo) { + Integer message = 0; + if (bo.getId() != null) { + Logistics add = new Logistics(); + add.setId(bo.getId()); + String are = logisticsMapper.selectByArea(bo.getDelivery_area(), bo.getDelivery_city()); + String city = logisticsMapper.selectByCity(bo.getDelivery_city(), bo.getDelivery_province()); + String province = logisticsMapper.selectByProvince(bo.getDelivery_province()); + add.setDeliveryProvince(province); + add.setDeliveryCity(city); + add.setDeliveryArea(are); + add.setContact(bo.getContact()); + add.setPhoneNumber(bo.getPhoneNumber()); + add.setFullAddress(bo.getFullAddress()); + add.setPricingMethod(bo.getPricing_method().toString()); + add.setShipping(bo.getShipping()); + add.setStatus("0"); + add.setWarehouseId(bo.getWarehouse_id()); + add.setRemark(bo.getRemark()); + + if (city == null) { + add.setDeliveryAddress(province + "/" + are); + } else { + add.setDeliveryAddress(province + "/" + city + "/" + are); + } + add.setTemplateName(bo.getTemplate_name()); + log.info("打印数据-{}", JSONObject.toJSONString(bo)); + String jsonString = JSONObject.toJSONString(bo.getShippingRange()); + add.setShippingRange(jsonString); + + // 赋值最低价格 + ObjectMapper objectMapper = new ObjectMapper(); + + // 将 JSON 转换为 Map> + Map> regionMap = null; + try { + regionMap = objectMapper.readValue(jsonString, Map.class); + } catch (JsonProcessingException e) { + throw new ServiceException("解析模板运送范围失败", 555); + } + if (ObjectUtil.isNotEmpty(regionMap)) { + List priceList = new ArrayList<>(); + // 遍历 Map 并修改每个列表中的第二个元素 + for (Map.Entry> entry : regionMap.entrySet()) { + List list = entry.getValue(); + String strValue = String.valueOf(list.get(1)); + priceList.add(new BigDecimal(strValue)); + } + BigDecimal minPrice = Collections.min(priceList); + add.setFirPrice(minPrice); + } + message = logisticsMapper.updateByBo(add); + } + + return message > 0; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/NewUserServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/NewUserServiceImpl.java new file mode 100644 index 0000000..25219aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/NewUserServiceImpl.java @@ -0,0 +1,51 @@ +package org.dromara.zhishu.service.impl; + +import lombok.extern.log4j.Log4j2; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.NewUserInfo; +import org.dromara.zhishu.domain.bo.NewUserBo; +import org.dromara.zhishu.mapper.NewUserBoMapper; +import org.dromara.zhishu.service.NewUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Log4j2 +public class NewUserServiceImpl implements NewUserService { + @Autowired + private NewUserBoMapper newUserMapper; + + + @Transactional + @Override + public boolean insertByBo(NewUserBo newUserBo) { + Long userId = LoginHelper.getUserId(); + NewUserInfo add = MapstructUtils.convert(newUserBo, NewUserInfo.class); + if(add.getLicenseTime().equals("")){ + add.setLicenseTime(null); + } + if(add.getBusinessLicenseTime().equals("")){ + add.setBusinessLicenseTime(null); + } + Integer message = newUserMapper.selectAudit(userId); + //当message不等于0时返回false,否则执行下面代码 +// Integer message2 = newUserMapper.selectByPhone(add.getContactPhone()); + if (message != 0) { + throw new RuntimeException("您已经提交过申请,请耐心等待审核"); + } + try { + newUserMapper.insertAudit(userId); + Long id = newUserMapper.selectId(userId); + add.setAuditId(id); + Integer message1 = newUserMapper.insertAuditInfo(add); + System.out.println(message1); + newUserMapper.updatePhone(newUserBo.getEmail(),newUserBo.getContactPhone(),userId); + } catch (Exception e) { + log.error("插入数据失败",e); + return false; + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/NoticeServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/NoticeServiceImpl.java new file mode 100644 index 0000000..a764578 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/NoticeServiceImpl.java @@ -0,0 +1,135 @@ +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.zhishu.domain.ShopImg; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.NoticeBo; +import org.dromara.zhishu.domain.vo.NoticeVo; +import org.dromara.zhishu.domain.Notice; +import org.dromara.zhishu.mapper.NoticeMapper; +import org.dromara.zhishu.service.INoticeService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 消息通知Service业务层处理 + * + * @author yxy + * @date 2025-05-17 + */ +@RequiredArgsConstructor +@Service +public class NoticeServiceImpl implements INoticeService { + + private final NoticeMapper baseMapper; + + /** + * 查询消息通知 + * + * @param id 主键 + * @return 消息通知 + */ + @Override + public NoticeVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询消息通知列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 消息通知分页列表 + */ + @Override + public TableDataInfo queryPageList(NoticeBo 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(NoticeBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(NoticeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByDesc(Notice::getCreateTime); + lqw.eq(StringUtils.isNotBlank(bo.getSender()), Notice::getSender, bo.getSender()); + lqw.eq(StringUtils.isNotBlank(bo.getRecipient()), Notice::getRecipient, bo.getRecipient()); + lqw.eq(StringUtils.isNotBlank(bo.getContent()), Notice::getContent, bo.getContent()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Notice::getStatus, bo.getStatus()); + lqw.eq(bo.getCreateTime() != null, Notice::getCreateTime, bo.getCreateTime()); + return lqw; + } + + /** + * 新增消息通知 + * + * @param bo 消息通知 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(NoticeBo bo) { + Notice add = MapstructUtils.convert(bo, Notice.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改消息通知 + * + * @param bo 消息通知 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(NoticeBo bo) { + Notice update = MapstructUtils.convert(bo, Notice.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(Notice 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/PddServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PddServiceImpl.java new file mode 100644 index 0000000..6556326 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PddServiceImpl.java @@ -0,0 +1,996 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.opencsv.bean.CsvToBean; +import com.opencsv.bean.CsvToBeanBuilder; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.enums.FormatsType; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.bo.ShopBo; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.dto.BookPriceInfoDto; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.dto.request.AddTaskLogRequest; +import org.dromara.zhishu.domain.dto.request.BatchSetSoldOutRequest; +import org.dromara.zhishu.domain.dto.request.DeleteSaleOutGoodsBatchRequest; +import org.dromara.zhishu.domain.dto.request.GoodsSaleStatusSetRequest; +import org.dromara.zhishu.domain.dto.response.AddTaskLogResponse; +import org.dromara.zhishu.domain.dto.response.GetBookByISBNResponse; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.domain.vo.TaskVo; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.client.BookCenterClient; +import org.dromara.zhishu.service.client.FileClient; +import org.dromara.zhishu.service.client.LogClient; +import org.dromara.zhishu.service.client.PddClient; +import org.dromara.zhishu.util.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.text.DecimalFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; + +import static cn.dev33.satoken.SaManager.log; + +/** + * 店铺主表Service业务层处理 + * + * @author yxy + * @date 2025-03-10 + */ +@RequiredArgsConstructor +@Service +public class PddServiceImpl implements IPddService { + + private final ISysConfigService configService; + + private final IShopService shopService; + + private final FileClient fileClient; + + private final TaskServiceImpl taskService; + + private final IRunningTaskService runningTaskService; + + private final IRunningTaskByShopService runningTaskByShopService; + + private final IBookBaseInfoService bookBaseInfoService; + + private final IShopDetailService shopDetailService; + + private final PddClient pddClient; + + private final LogClient logClient; + + private final UrlUtil urlUtil; + + private final BookCenterClient bookCenterClient; + + @Override + public void createShopGoodsList(ShopVo shopVo, TaskBo taskBo, Integer isOnsale) { + System.out.println("任务开始:" + DateUtils.dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS)); + + // 根据shopId查询数据表是否存在 + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopVo.getId()); + if (checkMark == 0) { + // 不存在则创建表 + runningTaskByShopService.createTable("t_running_task_" + shopVo.getId()); + } + // 根据token获取店铺信息 + String accessToken = shopVo.getToken(); + /** + * + */ + Integer page = 1; + Integer pageSize = 100; + // 首次调用第一页,获取查询结果总数 + String pddIp = configService.selectConfigByKey("pdd.ip"); + String url = "/api/pdd/auth/getShopGoodsList?" + + "accessToken=" + accessToken; + if (isOnsale != null) { + url += "&isOnsale=" + isOnsale; + } + String dataStr = InterfaceUtils.getInterface(pddIp, url + "&page=" + page + "&pageSize=" + pageSize); + Map dataMap = JsonUtil.transferToObj(dataStr, Map.class); + // 记录总数据 + List> allList = new ArrayList<>(); + // 结束时间,如果传入的结束时间为空,则使用新的结束时间 + Long startTime = null; + Long endTime = null; + // 标记结束 + int endMark = 0; + // 标记 + int runMark = 0; + do { + for (; page <= 100; page++) { + url = "/api/pdd/auth/getShopGoodsList?" + + "accessToken=" + accessToken; + if (startTime != null) { + url += "&createdAtFrom=" + startTime; + } + if (endTime != null) { + url += "&createdAtEnd=" + endTime; + } + if (isOnsale != null) { + url += "&isOnsale=" + isOnsale; + } + // 继续查询数据 + dataStr = InterfaceUtils.getInterface(pddIp, url + "&page=" + page + "&pageSize=" + pageSize); + dataMap = JsonUtil.transferToObj(dataStr, Map.class); + int errorMark = 0; + while (dataMap == null) { + System.out.println("接口异常,正在重试..."); + dataStr = InterfaceUtils.getInterface(pddIp, url + "&page=" + page + "&pageSize=" + pageSize); + dataMap = JsonUtil.transferToObj(dataStr, Map.class); + errorMark++; + if (errorMark > 10) { + break; + } + } + List> dataList = new ArrayList<>(); + if (dataMap != null) { + dataList = (List>) dataMap.get("goods_list"); + } + if (runMark == 1 && dataList.size() == 0) { + endMark = 1; + } + if (dataList.size() > 0) { + List runningTaskList = new ArrayList<>(); + for (Map map : dataList) { + List> skuList = (List>) map.get("sku_list"); + // 构建 JSON 对象 + JSONObject json = new JSONObject(); + json.put("trilateralId", map.get("goods_id").toString()); + json.put("img", map.get("thumb_url").toString()); + json.put("finishTime", DateUtilsUtils.getNowDate()); + json.put("imageSelect", "11"); + json.put("totalPrice", ""); + json.put("isbn", skuList.get(0).get("outer_goods_id").toString()); + json.put("priority", "3"); + json.put("imageBigUrl", ""); + json.put("title", map.get("goods_name").toString()); + json.put("quality", "100"); + json.put("shopType", shopVo.getShopType()); + json.put("stock", map.get("goods_quantity").toString()); + json.put("skuCode", ""); + json.put("skuId", skuList.get(0).get("sku_id").toString()); + json.put("isOnSale", map.get("is_onsale").toString()); + json.put("isMoreSku", map.get("is_more_sku").toString()); + // 如果数据存在则修改,不存在则添加 + RunningTask runningTask = runningTaskByShopService.selectVoByTrilateralId("t_running_task_" + shopVo.getId(), map.get("goods_id").toString()); + if (runningTask == null) { + String jsonString = json.toString(); + runningTask = new RunningTask(); + runningTask.setTaskId(taskBo.getId()); + runningTask.setShopId(shopVo.getId()); + runningTask.setGoodsId(Long.parseLong(map.get("goods_id").toString())); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setTaskName(taskBo.getFileName()); + runningTask.setPriority(255L); + runningTask.setData(""); + runningTask.setStatus("2"); + runningTask.setTaskType("GET_SHOP_GOODS"); + runningTask.setSuccessData(jsonString); + runningTask.setCallBackData("拉取成功"); + // 新增 + runningTaskList.add(runningTask); + } else { + // 解析价格和上架编码 + Map successData = JsonUtil.transferToObj(runningTask.getSuccessData(), Map.class); + String totalPrice = successData.get("totalPrice").toString(); + String skuCode = successData.get("skuCode").toString(); + json.put("totalPrice", totalPrice); + json.put("skuCode", skuCode); + String jsonString = json.toString(); + // 修改文件名和状态 + runningTask.setTaskId(taskBo.getId()); + runningTask.setTaskName(taskBo.getFileName()); + runningTask.setStatus("2"); + runningTask.setSuccessData(jsonString); + runningTaskByShopService.update("t_running_task_" + shopVo.getId(), runningTask); + } + } + if (runningTaskList.size() > 0) { + runningTaskByShopService.batchInsert("t_running_task_" + shopVo.getId(), runningTaskList); + } + } + if (page == 100 || dataList.size() == 0) { + if (startTime == null && endTime == null && dataList.size() == 0) { + runMark = 1; + break; + } + if (dataList.size() == 0) { + startTime = endTime; + } else { + startTime = Long.parseLong(dataList.get(dataList.size() - 1).get("created_at").toString()); + } + Long nowTime = System.currentTimeMillis() / 1000; + Long newEndTime = addDaysToTimestamp(startTime, 30); + if (newEndTime < nowTime) { + endTime = newEndTime; + } else { + endTime = nowTime; + runMark = 1; + } + page = 1; + break; + } + } + } while (endMark == 0); + //此时状态为3的数据都是为拉取的数据,都删除 + runningTaskByShopService.deleteByStatus("t_running_task_" + shopVo.getId(), "3"); + // 修改状态为完成 + runningTaskByShopService.updateStatus("t_running_task_" + shopVo.getId()); + } + + + @Override + public void createShopGoodsDetailList(ShopVo shopVo, TaskBo taskBo, Integer isOnsale) { + System.out.println("任务开始:" + DateUtils.dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS)); + + // 根据shopId查询数据表是否存在 + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopVo.getId()); + if (checkMark == 0) { + // 不存在则创建表 + runningTaskByShopService.createTable("t_running_task_" + shopVo.getId()); + } + // 根据token获取店铺信息 + String accessToken = shopVo.getToken(); + /** + * + */ + Integer page = 1; + Integer pageSize = 100; + // 首次调用第一页,获取查询结果总数 + String pddIp = configService.selectConfigByKey("pdd.ip"); + String url = "/api/pdd/auth/getShopGoodsList?" + + "accessToken=" + accessToken; + if (isOnsale != null) { + url += "&isOnsale=" + isOnsale; + } + String dataStr = InterfaceUtils.getInterface(pddIp, url + "&page=" + page + "&pageSize=" + pageSize); + Map dataMap = JsonUtil.transferToObj(dataStr, Map.class); + // 记录总数据 + List> allList = new ArrayList<>(); + // 结束时间,如果传入的结束时间为空,则使用新的结束时间 + Long startTime = null; + Long endTime = null; + // 标记结束 + int endMark = 0; + // 标记 + int runMark = 0; + do { + for (; page <= 100; page++) { + url = "/api/pdd/auth/getShopGoodsDetailList?" + + "accessToken=" + accessToken; + if (startTime != null) { + url += "&createdAtFrom=" + startTime; + } + if (endTime != null) { + url += "&createdAtEnd=" + endTime; + } + if (isOnsale != null) { + url += "&isOnsale=" + isOnsale; + } + // 继续查询数据 + dataStr = InterfaceUtils.getInterface(pddIp, url + "&page=" + page + "&pageSize=" + pageSize); + dataMap = JsonUtil.transferToObj(dataStr, Map.class); + int errorMark = 0; + while (dataMap == null) { + System.out.println("接口异常,正在重试..."); + dataStr = InterfaceUtils.getInterface(pddIp, url + "&page=" + page + "&pageSize=" + pageSize); + dataMap = JsonUtil.transferToObj(dataStr, Map.class); + errorMark++; + if (errorMark > 10) { + break; + } + } + List> dataList = new ArrayList<>(); + if (dataMap != null) { + dataList = (List>) dataMap.get("goods_list"); + } + if (runMark == 1 && dataList.size() == 0) { + endMark = 1; + } + if (dataList.size() > 0) { + List runningTaskList = new ArrayList<>(); + for (Map map : dataList) { + List> skuList = (List>) map.get("sku_list"); + // 构建 JSON 对象 + JSONObject json = new JSONObject(); + json.put("trilateralId", map.get("goods_id").toString()); + json.put("img", map.get("thumb_url").toString()); + json.put("finishTime", DateUtilsUtils.getNowDate()); + json.put("imageSelect", "11"); + json.put("totalPrice", map.get("price") == null ? "" : map.get("price").toString()); + json.put("isbn", skuList.get(0).get("outer_goods_id").toString()); + json.put("priority", "3"); + json.put("imageBigUrl", ""); + json.put("title", map.get("goods_name").toString()); + json.put("quality", "100"); + json.put("shopType", shopVo.getShopType()); + json.put("stock", map.get("goods_quantity").toString()); + json.put("skuCode", map.get("skuCode") == null ? "" : map.get("skuCode").toString()); + json.put("skuId", skuList.get(0).get("sku_id").toString()); + json.put("isOnSale", map.get("is_onsale").toString()); + json.put("isMoreSku", map.get("is_more_sku").toString()); + String jsonString = json.toString(); + // 如果数据存在则修改,不存在则添加 + RunningTask runningTask = runningTaskByShopService.selectVoByTrilateralId("t_running_task_" + shopVo.getId(), map.get("goods_id").toString()); + if (runningTask == null) { + + runningTask = new RunningTask(); + runningTask.setTaskId(taskBo.getId()); + runningTask.setShopId(shopVo.getId()); + runningTask.setGoodsId(Long.parseLong(map.get("goods_id").toString())); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setTaskName(taskBo.getFileName()); + runningTask.setPriority(255L); + runningTask.setData(""); + runningTask.setStatus("2"); + runningTask.setTaskType("GET_SHOP_GOODS"); + runningTask.setSuccessData(jsonString); + runningTask.setCallBackData("拉取成功"); + // 新增 + runningTaskList.add(runningTask); + } else { + // 修改文件名和状态 + runningTask.setTaskId(taskBo.getId()); + runningTask.setTaskName(taskBo.getFileName()); + runningTask.setStatus("2"); + runningTask.setSuccessData(jsonString); + runningTaskByShopService.update("t_running_task_" + shopVo.getId(), runningTask); + } + } + if (runningTaskList.size() > 0) { + runningTaskByShopService.batchInsert("t_running_task_" + shopVo.getId(), runningTaskList); + } + } + if (page == 100 || dataList.size() == 0) { + if (startTime == null && endTime == null && dataList.size() == 0) { + runMark = 1; + break; + } + if (dataList.size() == 0) { + startTime = endTime; + } else { + startTime = Long.parseLong(dataList.get(dataList.size() - 1).get("created_at").toString()); + } + Long nowTime = System.currentTimeMillis() / 1000; + Long newEndTime = addDaysToTimestamp(startTime, 30); + if (newEndTime < nowTime) { + endTime = newEndTime; + } else { + endTime = nowTime; + runMark = 1; + } + page = 1; + break; + } + } + } while (endMark == 0); + //此时状态为3的数据都是为拉取的数据,都删除 + runningTaskByShopService.deleteByStatus("t_running_task_" + shopVo.getId(), "3"); + // 修改状态为完成 + runningTaskByShopService.updateStatus("t_running_task_" + shopVo.getId()); + } + + @Override + public TableDataInfo> getShopGoodsList(String shopId, String isOnsale,String isbn,String priceDown,String priceUp,String startDate,String endDate, Integer page, Integer pageSize,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode) { +// ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + + String[] shopIds=shopId.split(","); + Page> result = new Page<>(); + result.setCurrent(page); + result.setSize(pageSize); + Long pageNum = (long) ((page - 1) * pageSize); + int total=0; + for (String shopIdsingle : shopIds){ + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopIdsingle); + if (checkMark == 0) { + result.setTotal(0); + result.setRecords(new ArrayList<>()); + } else { + List mapList = runningTaskByShopService.selectGetShopGoodsList("t_running_task_" + shopIdsingle, isOnsale,isbn,priceDown,priceUp,startDate,endDate,pageNum, Long.parseLong(pageSize.toString()), goodsName, stockDown, stockUp, trilateralId, goodsCode, skuCode); + + List> mapList2 = new ArrayList<>(); + + for (Map map : mapList) { + Map successData = JsonUtil.transferToObj((String) map.get("success_data"), Map.class); + + Map map2 = new HashMap(); + map2.put("shopId",map.get("shop_id")); + map2.put("Title", successData.get("title")); + map2.put("TrilateralId", successData.get("trilateralId")); + map2.put("SkuCode", successData.get("skuCode") == null ? (successData.get("artNo") == null ? "": successData.get("artNo")) : successData.get("skuCode")); + map2.put("SkuId", successData.get("skuId")); + map2.put("ISBN", successData.get("isbn")); + map2.put("GoodsCode", successData.get("goodsCode")); + + + + // 获取img值并进行类型判断 + Object imgObj = successData.get("img"); + boolean isImgString = (imgObj instanceof String); + if (isImgString){ + map2.put("Img", imgObj); // 保持原有值 + }else{ + Map imgMap = (Map) imgObj; + List carouselUrlArray = (List) imgMap.get("carousel_url_array"); + if (!carouselUrlArray.isEmpty()){ + map2.put("Img",carouselUrlArray.get(0)); + }else{ + map2.put("Img", ""); + } + } + + + + map2.put("ImgBigUrl", ""); + map2.put("TotalPrice", successData.get("totalPrice")); + map2.put("Stock", successData.get("stock")); + map2.put("FinishTime", successData.get("finishTime")); + map2.put("IsOnSale", successData.get("isOnSale")); + map2.put("IsMoreSku", ""); + mapList2.add(map2); + } + + result.setRecords(mapList2); + total =total+ runningTaskByShopService.selectGetShopGoodsNum("t_running_task_" + shopIdsingle, isOnsale,isbn,priceDown,priceUp,startDate,endDate, goodsName, stockDown, stockUp, trilateralId, goodsCode, skuCode); + } + } + + result.setTotal(total); + + + return TableDataInfo.build(result); + + + } + + @Override + public List emport(String shopId, String isOnsale) { + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopId); + if (checkMark == 0) { + return new ArrayList<>(); + } else { + return runningTaskByShopService.selectGetShopGoodsList("t_running_task_" + shopId, isOnsale,null,"","",null,null, 0L, 9999999L,null,null,null,null,null,null); + } + } + + /** + * 给定一个 10 位秒级时间戳,增加指定的天数(如 30 天),并返回新的秒级时间戳 + * + * @param timestampSeconds 10 位时间戳(秒) + * @param daysToAdd 要增加的天数(如 30 表示加 30 天) + * @return 新的秒级时间戳 + */ + public static long addDaysToTimestamp(long timestampSeconds, int daysToAdd) { + LocalDateTime dateTime = LocalDateTime.ofInstant( + Instant.ofEpochSecond(timestampSeconds), + ZoneId.systemDefault() + ); + + // 增加指定天数 + LocalDateTime newDateTime = dateTime.plusDays(daysToAdd); + + // 返回秒级时间戳 + return newDateTime.atZone(ZoneId.systemDefault()).toEpochSecond(); + } + + + /** + * 下架重复 + * @param shopId 店铺ID + */ + @Override + public void batchSetSoldOut(Long shopId) { + ShopVo shopVo = shopService.queryById(shopId); + // 判断token是否不为空 + String token = shopVo.getToken(); + if (ObjectUtil.isEmpty(token)) { + throw new ServiceException("店铺未授权,无法批量下架商品"); + } + List items = runningTaskByShopService.selectRepeatNoPage("t_running_task_" + shopId); + if (!items.isEmpty()) { + + // 创建下架任务 + TaskBo taskBo = new TaskBo(); + taskBo.setTaskType("EDIT_ISONSALE_GOODS"); + taskBo.setFileName("下架重复商品任务"); + taskBo.setShopIds(shopId.toString()); + taskBo.setShopNames(shopVo.getShopName()); + taskBo.setDataNum((long) items.size()); + taskBo.setTaskStatus("0"); + taskBo.setStatus("0"); + taskService.insertByBo(taskBo); + //开启线程 + Thread thread = new Thread(() -> { + for(SuccessDataItemDto item : items){ + //调用接口 + Map mapData = new HashMap(); + mapData.put("priority","4"); + mapData.put("retry_count","3"); + mapData.put("taskId",taskBo.getId().toString()); + mapData.put("shopId",shopId.toString()); + mapData.put("token",shopVo.getToken()); + mapData.put("isOnsale","1"); + mapData.put("serviceName","EDIT_ISONSALE_GOODS"); + mapData.put("trilateralId", item.getTrilateralId()); + mapData.put("shopType",shopVo.getShopType()); + if(shopVo.getShopType().equals("5")){ + //咸鱼 + mapData.put("appId", shopVo.getMallId().toString()); + mapData.put("shopKey",shopVo.getShopKey()); + } + /** + * 创建运行任务对象 + */ + RunningTask runningTaskDate = new RunningTask(); + runningTaskDate.setTaskId(taskBo.getId()); + runningTaskDate.setShopId(shopVo.getId()); + runningTaskDate.setGoodsId(0L); + runningTaskDate.setRandomNum(System.currentTimeMillis()); + runningTaskDate.setTaskName(taskBo.getFileName()); + runningTaskDate.setPriority(255L); + runningTaskDate.setData(JsonUtil.transferToJson(mapData)); + runningTaskDate.setStatus("0"); + runningTaskDate.setTaskType("EDIT_ISONSALE_GOODS"); + runningTaskService.insert(runningTaskDate); + } + }); + thread.start(); + + }else{ + throw new ServiceException("该店铺下没有需要下架的商品"); + } + + } + + @Override + public void editShopGoodsAllByIsOnSale(ShopVo shopVo, TaskBo taskBo, String isOnSale, String isbn, String priceDown, String priceUp, String startDate, String endDate,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode) { + String isOnSaleNum = isOnSale.equals("0") ? "1" : "0"; + + int count = runningTaskByShopService.selectGetShopGoodsListCount("t_running_task_" + shopVo.getId(), isOnSaleNum, isbn, priceDown, priceUp, startDate, endDate,goodsName,stockDown,stockUp,trilateralId,goodsCode,skuCode); + + Long pageSize = 100L; + // 计算总页数 + Long totalPages = (count + pageSize - 1) / pageSize; + + // 从最后一页开始往前执行 + int runNum = 0; + List> bodyList = new ArrayList<>(); + Map setTaskBodyMap = new HashMap(); + setTaskBodyMap.put("task_id",taskBo.getId()); + + Long usageCount = shopService.checkUsageCount(shopVo); + + for (Long pageNum = totalPages; pageNum >= 1; pageNum--) { + Long page = (pageNum - 1) * pageSize; + List dataMap = runningTaskByShopService.selectGetShopGoodsList("t_running_task_" + shopVo.getId(), isOnSaleNum, isbn, priceDown, priceUp, startDate, endDate, page, pageSize,goodsName,stockDown,stockUp,trilateralId,goodsCode,skuCode); + + if (dataMap.size() == 0) { + continue; + } + + for (Map map : dataMap) { + runNum++; + Map successData = JsonUtil.transferToObj((String) map.get("success_data"), Map.class); + Map body = new HashMap(); + Map bookInfo = new HashMap(); + bookInfo.put("isbn",successData.get("isbn").toString()); + bookInfo.put("trilateralId",successData.get("trilateralId").toString()); + bookInfo.put("goodsCode",""); + body.put("book_info",bookInfo); + Map detail = new HashMap(); + // 1 上架 2 下架 + detail.put("status",isOnSale.equals("0") ? 2 : 1); + body.put("detail",detail); + bodyList.add(body); + + if (bodyList.size() % 500 == 0 || runNum == count){ + NewTaskUtils.newTaskPost(taskBo.getId().toString(),shopVo.getId().toString(),bodyList); + // 清空列表,准备下一批 + bodyList.clear(); + } + + usageCount--; + if (usageCount == 0){ + break; + } + } + if (usageCount == 0){ + break; + } + } + // 处理剩余数据 + if (!bodyList.isEmpty()) { + NewTaskUtils.newTaskPost(taskBo.getId().toString(),shopVo.getId().toString(),bodyList); + System.out.println("新发布任务发布结束:"+bodyList.size()+"条"); + } + // 更新使用次数 + shopService.updateUsageCount(shopVo,usageCount); + } + + /** + * 通过csv批量翻新商品上架拼多多 + * + * @param file + * @param taskBo + * @param shopVo + */ + @Async + @Override + public void batchRenovateOnSaleByCsv(MultipartFile file, TaskBo taskBo, ShopVo shopVo) { + try { + String defaultStock = "0"; + ShopDetailVo shopDetailVo = shopDetailService.queryByShopId(shopVo.getId()); + if (shopDetailVo != null) defaultStock = String.valueOf(shopDetailVo.getStockDeff()); + // 读取CSV文件 + List dataList = readCsvData(file); + + // 分批处理数据 + int batchSize = 1000; + int totalBatches = (int) Math.ceil((double) dataList.size() / batchSize); + + // 处理每个批次 + for (int batchNum = 0; batchNum < totalBatches; batchNum++) { + int fromIndex = batchNum * batchSize; + int toIndex = Math.min((batchNum + 1) * batchSize, dataList.size()); + List batchList = dataList.subList(fromIndex, toIndex); + + // 计算当前批次需要的线程数 (最多10个) + int threadCount = Math.min(10, batchList.size()); + + // 使用CountDownLatch等待所有线程完成 + CountDownLatch latch = new CountDownLatch(threadCount); + + // 分配每个线程处理的数据量 + int perThreadSize = (int) Math.ceil((double) batchList.size() / threadCount); + + for (int i = 0; i < threadCount; i++) { + int threadFrom = i * perThreadSize; + int threadTo = Math.min((i + 1) * perThreadSize, batchList.size()); + List batchData = batchList.subList(threadFrom, threadTo); + + String finalDefaultStock = defaultStock; + ThreadPoolUtils.execute(() -> { + try { + for (BookPriceInfoDto data : batchData) { + // 调用单条数据处理逻辑 + processSingleData(data, shopVo, taskBo.getId(), taskBo.getFileName(), finalDefaultStock, "0", "1"); + } + } finally { + latch.countDown(); + } + }); + } + + // 等待当前批次所有线程完成 + latch.await(); + } + } catch (Exception e) { + throw new ServiceException("批量处理CSV文件失败:" + e.getMessage()); + } + } + + // 读取CSV文件 + private List readCsvData(MultipartFile file) throws IOException { + try (Reader reader = new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8)) { + CsvToBean csvToBean = new CsvToBeanBuilder(reader) + .withType(BookPriceInfoDto.class) + .withIgnoreLeadingWhiteSpace(true) + .build(); + return csvToBean.parse(); + } + } + + // 单条数据处理方法 + public Boolean processSingleData(BookPriceInfoDto data, ShopVo shopVo, Long taskId, String taskName, String defaultStock, String status, String taskType) { + + // 将字符串转换为BigDecimal以确保精确计算 + BigDecimal fen = new BigDecimal(data.getCorePrice()); + // 分转元:除以100 + BigDecimal yuan = fen.divide(new BigDecimal("100")); + // 设置小数位数并四舍五入 + DecimalFormat df = new DecimalFormat("0.00"); + + Map goMap = new HashMap(); + goMap.put("priority", "3"); + goMap.put("retry_count", "3"); + goMap.put("isbn", data.getIsbn()); + goMap.put("totalPrice", df.format(yuan)); + goMap.put("stock", defaultStock); + goMap.put("bookName", data.getBookName()); + goMap.put("code", data.getIsbn()); + goMap.put("imgBigUrl", ""); + goMap.put("artNo", data.getIsbn()); + goMap.put("taskId", taskId.toString()); + goMap.put("shopId", shopVo.getId().toString()); + goMap.put("imageSelect", "12"); + goMap.put("way", "2"); + + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(taskId); + runningTask.setShopId(shopVo.getId()); + runningTask.setGoodsId(Long.valueOf(data.getPlatformId())); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setTaskName(taskName); + runningTask.setPriority(255L); + runningTask.setData(JsonUtil.transferToJson(goMap)); + runningTask.setStatus(status); + runningTask.setTaskType(taskType); + + // 删除pdd商品 + DeleteSaleOutGoodsBatchRequest deleteSaleOutGoodsBatchRequest = new DeleteSaleOutGoodsBatchRequest(); + deleteSaleOutGoodsBatchRequest.setToken(shopVo.getToken()); + List goodsIds = List.of(Long.valueOf(data.getPlatformId())); + deleteSaleOutGoodsBatchRequest.setGoodsIds(goodsIds); + R deleteSaleOutGoodsBatchR = pddClient.deleteSaleOutGoodsBatch(UrlUtil.getPddServiceUrl(), deleteSaleOutGoodsBatchRequest); + if (!R.isError(deleteSaleOutGoodsBatchR)) { + // 同步删除数据库商品 + runningTaskByShopService.deleteByGoodsId("t_running_task_" + shopVo.getId(), data.getPlatformId()); + } + + // 无论是否删除成功都要重新发布上架商品 + runningTaskService.insert(runningTask); + return Boolean.TRUE; + } + + // 翻新数据处理方法 + @Async + @Override + public void renovateOnSale(BookPriceInfoDto data, String shopId, String taskId) { + // 获取店铺信息 + ShopVo shopVo = shopService.queryById(Long.valueOf(shopId)); + + // 获取任务详情 + TaskVo taskVo = taskService.queryById(Long.valueOf(taskId)); + + // 获取默认库存 + String defaultStock = "0"; + ShopDetailVo shopDetailVo = shopDetailService.queryByShopId(Long.valueOf(shopId)); + if (shopDetailVo != null) defaultStock = String.valueOf(shopDetailVo.getStockDeff()); + processSingleData(data, shopVo, taskVo.getId(), taskVo.getFileName(), defaultStock, "0", "UPDATE_GOODS_PRICE"); + + } + + public String getSaleTemplateIdByShopId(Long shopId) { + // 直接调用Mapper查询价格模板ID + return shopDetailService.selectSaleTemplateIdByShopId(shopId); + } + + @Override + public void sendPddGoodsToTargetShop(String shopId, String targetShopId, TaskBo taskBo, ShopVo shopVo) { + //查询出搬家数据 + Long pageNum = 1L; + Long pageSize = 100L; + Long maxPages = 5L; // 防止死循环 + String taskId=taskBo.getId().toString(); + try { + while (pageNum <= maxPages) { + Long offset = (pageNum - 1) * pageSize; + List dataMap = runningTaskByShopService.selectGetShopGoodsListAll( + "t_running_task_" + shopId, // 假设商品表名格式 + "1", + offset, + pageSize); + if (dataMap == null || dataMap.isEmpty()) { + break; + } + List runningTaskList = new ArrayList<>(); + List runningTaskList1 = new ArrayList<>(); + for (Map map : dataMap) { + + try { + // 关键字段非空检查 + if (map.get("goods_id") == null) { + log.warn("商品ID为空,跳过处理"); + continue; + } + + // 获取原始 success_data + Object dataObj = map.get("data"); + Map dataMaptable = null; + + Object successDataObj = map.get("success_data"); + Map successDataObjMaptable = null; + Map jsonmap = new HashMap<>(); + + if (dataObj != null && StringUtils.isNotBlank(dataObj.toString())) { + try { + // 尝试解析为 Map + dataMaptable = JsonUtil.transferToObj(dataObj.toString(), Map.class); + } catch (Exception e) { + log.warn("解析 success_data 失败: {}, 原始数据: {}", e.getMessage(), dataObj); + dataMaptable = new HashMap<>(); + dataMaptable.put("originalData", dataObj.toString()); + } + } + if (dataMaptable == null) { + dataMaptable = new HashMap<>(); + } + + if (successDataObj != null && StringUtils.isNotBlank(successDataObj.toString())) { + try { + // 尝试解析为 Map + successDataObjMaptable = JsonUtil.transferToObj(successDataObj.toString(), Map.class); + } catch (Exception e) { + log.warn("解析 success_data 失败: {}, 原始数据: {}", e.getMessage(), successDataObj); + dataMaptable = new HashMap<>(); + dataMaptable.put("originalData", successDataObj.toString()); + } + } + if (successDataObjMaptable == null) { + successDataObjMaptable = new HashMap<>(); + } + + // 添加 isMove 属性 + dataMaptable.put("isMove", "1"); + dataMaptable.put("shopId", targetShopId); + dataMaptable.put("taskId", taskId); + jsonmap.put("retry_count", "3"); + jsonmap.put("priority", "3"); + jsonmap.put("isbn", successDataObjMaptable.get("isbn")); + + // 从Map中获取totalPrice的值 + Object totalPriceObj = successDataObjMaptable.get("totalPrice"); + if (totalPriceObj != null) { + // 将分转换为元 + double totalPriceYuan; + + if (totalPriceObj instanceof Number) { + // 如果是数值类型 + totalPriceYuan = ((Number) totalPriceObj).doubleValue() / 100.0; + } else { + // 如果是字符串或其他类型 + try { + totalPriceYuan = Double.parseDouble(totalPriceObj.toString()) / 100.0; + } catch (NumberFormatException e) { + // 处理转换异常 + totalPriceYuan = 0.0; + } + } + + // 将转换后的元单位价格存入jsonmap + jsonmap.put("totalPrice", totalPriceYuan); + } else { + // 如果totalPrice为null,可以设置默认值或处理异常 + jsonmap.put("totalPrice", 1000); + } + + jsonmap.put("stock",successDataObjMaptable.get("stock")); + jsonmap.put("taskId", taskId); + jsonmap.put("shopId",targetShopId); + jsonmap.put("imageSelect", map.get("imageSelect")); + jsonmap.put("imageChoice", map.get("imageChoice")); + jsonmap.put("way",map.get("way")); + jsonmap.put("isMove", "1"); + jsonmap.put("imgBigUrl", successDataObjMaptable.get("img")); + + + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(Long.parseLong(taskId)); + runningTask.setShopId(Long.parseLong(targetShopId)); // 目标店铺 + runningTask.setGoodsId(Long.parseLong(map.get("goods_id").toString())); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setStatus("3"); + runningTask.setCallBackData("搬家成功"); + runningTask.setPriority(255L); + runningTask.setData(""); + runningTask.setTaskType("GET_SHOP_GOODS"); + + // success_data 可能为空 + RunningTask runningTask1 = new RunningTask(); + runningTask1.setTaskId(Long.parseLong(taskId)); + runningTask1.setShopId(Long.parseLong(targetShopId)); // 目标店铺 + runningTask1.setGoodsId(Long.parseLong(map.get("goods_id").toString())); + runningTask1.setRandomNum(System.currentTimeMillis()); + runningTask1.setStatus("0"); + runningTask1.setPriority(255L); + runningTask1.setData(""); + runningTask1.setTaskType("GET_MOVE_GOODS"); + + + // 序列化并设置 + String successDataJson = JsonUtil.transferToJson(dataMaptable); + String jsonmapDataJson = JsonUtil.transferToJson(jsonmap); + + runningTask.setData(successDataJson); + runningTask1.setData(jsonmapDataJson); + + runningTaskList.add(runningTask); + runningTaskList1.add(runningTask1); + } catch (Exception e) { + // 记录具体错误信息 + log.error("处理商品数据时出错: {}, 数据: {}", + e.getMessage(), map, e); + } + } + + // 批量插入到目标店铺的任务表 + if (!runningTaskList.isEmpty()) { + // 注意:这里应该是目标店铺的任务表 + runningTaskByShopService.batchInsert( + "t_running_task_" + targetShopId, // 关键修改 + runningTaskList); + + log.info("成功插入 {} 条任务到店铺 {}", + runningTaskList.size(), targetShopId); + } + if (!runningTaskList1.isEmpty()) { + System.out.println(runningTaskList1); + //插入任务表中 + runningTaskByShopService.batchInsert("t_running_task",runningTaskList1); + log.info("任务到店铺", runningTaskList1.size()); + } + + + + pageNum++; + // 如果返回的数据少于 pageSize,说明是最后一页 + if (dataMap.size() < pageSize) { + break; + } + + + } + + + }catch (Exception e){ + log.error("sendPddGoodsToTargetShop 执行失败: ", e); + throw new RuntimeException("商品搬家任务执行失败", e); + } + + + } + + @Override + public Boolean clearRedisBuffer(String shopId) { + try { + // 构建请求参数 + Map params = new HashMap<>(); + params.put("key", shopId); + + // 调用接口 + String ip = "http://36.212.12.92:30180"; + String url = "/deleteRedisKey"; + String responseStr = InterfaceUtils.getInterfaceGetWithParams(ip, url, params); + + // 解析响应 + Map responseMap = JsonUtil.transferToObj(responseStr, Map.class); + if (responseMap != null && responseMap.containsKey("success")) { + return (Boolean) responseMap.get("success"); + } + return false; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PrintTemplateServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PrintTemplateServiceImpl.java new file mode 100644 index 0000000..92adbd3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/PrintTemplateServiceImpl.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.Shop; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.PrintTemplateBo; +import org.dromara.zhishu.domain.vo.PrintTemplateVo; +import org.dromara.zhishu.domain.PrintTemplate; +import org.dromara.zhishu.mapper.PrintTemplateMapper; +import org.dromara.zhishu.service.IPrintTemplateService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 打印模板Service业务层处理 + * + * @author yxy + * @date 2026-03-07 + */ +@RequiredArgsConstructor +@Service +public class PrintTemplateServiceImpl implements IPrintTemplateService { + + private final PrintTemplateMapper baseMapper; + + /** + * 查询打印模板 + * + * @param id 主键 + * @return 打印模板 + */ + @Override + public PrintTemplateVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询打印模板列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 打印模板分页列表 + */ + @Override + public TableDataInfo queryPageList(PrintTemplateBo bo, PageQuery pageQuery) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + // 非管理员只能查看自己创建的 + if (userId != null && userId != 1) { + bo.setCreateBy(userId); + } + pageQuery.setOrderByColumn("t.create_by,t.id"); + pageQuery.setIsAsc("asc,desc"); + + // 调用自定义Mapper方法 + Page page = baseMapper.selectPrintTemplatePage(pageQuery.build(), bo); + return TableDataInfo.build(page); + } + + /** + * 查询符合条件的打印模板列表 + * + * @param bo 查询条件 + * @return 打印模板列表 + */ + @Override + public List queryList(PrintTemplateBo bo) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + // 非管理员只能查看自己创建的 + if (userId != null && userId != 1) { + bo.setCreateBy(userId); + } + // 调用自定义Mapper方法,无分页 + return baseMapper.selectPrintTemplateList(bo); + } + + private LambdaQueryWrapper buildQueryWrapper(PrintTemplateBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(PrintTemplate::getId); + lqw.eq(bo.getCreateBy() != null, PrintTemplate::getCreateBy, bo.getCreateBy()); + lqw.like(StringUtils.isNotBlank(bo.getPrintTemplateName()), PrintTemplate::getPrintTemplateName, bo.getPrintTemplateName()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), PrintTemplate::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增打印模板 + * + * @param bo 打印模板 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(PrintTemplateBo bo) { + PrintTemplate add = MapstructUtils.convert(bo, PrintTemplate.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改打印模板 + * + * @param bo 打印模板 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(PrintTemplateBo bo) { + PrintTemplate update = MapstructUtils.convert(bo, PrintTemplate.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(PrintTemplate 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/ProductServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ProductServiceImpl.java new file mode 100644 index 0000000..d63e6f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ProductServiceImpl.java @@ -0,0 +1,241 @@ +package org.dromara.zhishu.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.model.LoginUser; +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.ShopWarehouseAuto; +import org.dromara.zhishu.domain.SinglePrint; +import org.dromara.zhishu.domain.bo.SinglePrintBo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IProductService; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.IShopWarehouseAutoService; +import org.dromara.zhishu.util.DateUtilsUtils; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class ProductServiceImpl implements IProductService { + + private final IShopService shopService; + + + + private final IShopWarehouseAutoService shopWarehouseAutoService; + + /** + * 获取用户仓库信息 + */ + @Override + public Map getMappingList(){ + + String mappingListStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getNewWarehouse(), + "/api/warehouse/mapping_list", + new HashMap<>() + ); + + Map map = JsonUtil.transferToObj(mappingListStr,Map.class); + + return map; + } + + @Override + public TableDataInfo queryPageList(Map bo) { + + String userId = bo.get("aboutId").toString(); + String warehouseId = bo.get("warehouseId").toString(); + String page = bo.get("pageNum").toString(); + String pageSize = bo.get("pageSize").toString(); + + Map params = new HashMap<>(); + params.put("page", page); + params.put("page_size", pageSize); + params.put("user_id",userId); + params.put("warehouse_id",warehouseId); + + if (bo.get("barcode") != null){ + params.put("barcode",bo.get("barcode").toString()); + } + if (bo.get("name") != null){ + params.put("name",bo.get("name").toString()); + } + if (bo.get("appearance") != null){ + params.put("appearance",bo.get("appearance").toString()); + } + // 库存 + if (bo.get("stockOperator") != null && bo.get("stockValue") != null){ + params.put("stock_operator",bo.get("stockOperator").toString()); + params.put("stock_value", bo.get("stockValue").toString()); + } + // 价格 + if (bo.get("salepriceOperator") != null && bo.get("salepriceValue") != null){ + params.put("saleprice_operator",bo.get("salepriceOperator").toString()); + // 换算金额 + String saleprice_value = new BigDecimal( bo.get("salepriceValue").toString()).multiply(new BigDecimal(100)).toString(); + params.put("saleprice_value",saleprice_value); + } + // 创建日期 + if (bo.get("startCreatedAt") != null){ + params.put("start_created_at", DateUtilsUtils.dateStringToTimestamp10(bo.get("startCreatedAt").toString(),"yyyy-MM-dd HH:mm:ss")); + } + if (bo.get("endCreatedAt") != null){ + params.put("end_created_at", DateUtilsUtils.dateStringToTimestamp10(bo.get("endCreatedAt").toString(),"yyyy-MM-dd HH:mm:ss")); + } + + String productListStr = InterfaceUtils.getInterfaceGetWithParams( + UrlUtil.getNewWarehouse(), + "/api/product/distribution_list", + params + ); + Map dataMap = JsonUtil.transferToObj(productListStr, Map.class); + Map data = (Map) dataMap.get("data"); + + List productList = (List) data.get("list"); + int total = (int) data.get("total"); + + Page result = new Page<>(Integer.parseInt(page), Integer.parseInt(pageSize), total); + result.setRecords(productList); + return TableDataInfo.build(result); + } + + /** + * 发布商品 + * @param map + * @return + */ + @Override + public void releaseGoods(Map map){ + + // 获取仓库id + Long userId = Long.parseLong(map.get("userId").toString()); + // 店铺id数组 + String[] shopIdArr = map.get("shopIds").toString().split(","); + // 转换成数值类型 + Long[] shopIdLongArr = new Long[shopIdArr.length]; + // 店铺类型数组 + Long[] shopTypeArr = new Long[shopIdArr.length]; + for (int i=0;i tableDataInfo = queryPageList(params); + List productList = tableDataInfo.getRows(); + if (productList == null || productList.isEmpty()){ + // 当查不到数据的时候退出循环 + break; + }else{ + // 存在数据时 + pageNum++; + // 提取id并转换为String数组 + String[] productIdArray = productList.stream() + .map(productMap -> productMap.get("id").toString()) // 将id转换为String + .toArray(String[]::new); // 转换为String数组 + + // 转换成数值类型 + productIdLongArr = Arrays.stream(productIdArray) + .map(String::trim) + .map(Long::valueOf) + .toArray(Long[]::new); + + + // 封装数据 + JSONObject jsonObject = new JSONObject(); + jsonObject.put("user_id",userId); + jsonObject.put("shop_ids",shopIdLongArr); + jsonObject.put("shop_types",shopTypeArr); + jsonObject.put("product_ids",productIdLongArr); + // 调用发布接口 + InterfaceUtils.postJson(UrlUtil.getNewWarehouse(),"/api/product/batchPush",jsonObject.toJSONString()); + // 清空商品 + productIdLongArr = null; + } + } + } + } + + /** + * 自动发布接口 + * @param map + */ + @Override + public void releaseGoodsAuto(Map map){ + // 用户id + Long userId = Long.parseLong(map.get("userId").toString()); + // 仓库id + Long warehouseId = Long.parseLong(map.get("warehouseId").toString()); + // 根据用户id和仓库id查询关联店铺 + ShopWarehouseAuto shopWarehouseAuto = new ShopWarehouseAuto(); + shopWarehouseAuto.setUserId(userId); + shopWarehouseAuto.setWarehouseId(warehouseId); + List shopWarehouseAutoList = shopWarehouseAutoService.queryList(shopWarehouseAuto); + if (!shopWarehouseAutoList.isEmpty()){ + List shopIds = shopWarehouseAutoList.stream() + .map(ShopWarehouseAuto::getShopId) + .toList(); + + List shopVoList = shopService.selectByIds(shopIds); + + String idsStr = shopVoList.stream() + .map(ShopVo::getId) + .map(String::valueOf) + .collect(Collectors.joining(",")); + Map data = new HashMap(); + data.put("userId",userId.toString()); + data.put("shopIds",idsStr); + data.put("oneClick","0"); + data.put("productIds",map.get("productId").toString()); + releaseGoods(data); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningLogFileServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningLogFileServiceImpl.java new file mode 100644 index 0000000..d8ab74f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningLogFileServiceImpl.java @@ -0,0 +1,139 @@ +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.RunningLogFileBo; +import org.dromara.zhishu.domain.vo.RunningLogFileVo; +import org.dromara.zhishu.domain.RunningLogFile; +import org.dromara.zhishu.mapper.RunningLogFileMapper; +import org.dromara.zhishu.service.IRunningLogFileService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 程序运行日志表Service业务层处理 + * + * @author yxy + * @date 2025-06-12 + */ +@RequiredArgsConstructor +@Service +public class RunningLogFileServiceImpl implements IRunningLogFileService { + + private final RunningLogFileMapper baseMapper; + + /** + * 查询程序运行日志表 + * + * @param id 主键 + * @return 程序运行日志表 + */ + @Override + public RunningLogFileVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + @Override + public String selectMaxFileOrderByFileTypeAndCreateBy(String fileType,String userId){ + return baseMapper.selectMaxFileOrderByFileTypeAndCreateBy(fileType,userId); + } + + /** + * 分页查询程序运行日志表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 程序运行日志表分页列表 + */ + @Override + public TableDataInfo queryPageList(RunningLogFileBo 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(RunningLogFileBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(RunningLogFileBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(RunningLogFile::getId); + lqw.like(StringUtils.isNotBlank(bo.getFileName()), RunningLogFile::getFileName, bo.getFileName()); + lqw.eq(StringUtils.isNotBlank(bo.getFileOrder()), RunningLogFile::getFileOrder, bo.getFileOrder()); + lqw.eq(StringUtils.isNotBlank(bo.getFileType()), RunningLogFile::getFileType, bo.getFileType()); + lqw.eq(StringUtils.isNotBlank(bo.getFileSize()), RunningLogFile::getFileSize, bo.getFileSize()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), RunningLogFile::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增程序运行日志表 + * + * @param bo 程序运行日志表 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(RunningLogFileBo bo) { + RunningLogFile add = MapstructUtils.convert(bo, RunningLogFile.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改程序运行日志表 + * + * @param bo 程序运行日志表 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(RunningLogFileBo bo) { + RunningLogFile update = MapstructUtils.convert(bo, RunningLogFile.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(RunningLogFile 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/RunningTaskByShopServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningTaskByShopServiceImpl.java new file mode 100644 index 0000000..5a61a47 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningTaskByShopServiceImpl.java @@ -0,0 +1,568 @@ +package org.dromara.zhishu.service.impl; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import org.dromara.zhishu.domain.dto.RunningTaskShopGoodsDto; +import org.dromara.zhishu.domain.dto.SuccessDataKfz; +import org.springframework.data.redis.core.StringRedisTemplate; +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import lombok.RequiredArgsConstructor; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.domain.dto.ErpGoodsDto; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.vo.RunningTaskNumVo; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsVo; +import org.dromara.zhishu.mapper.RunningTaskByShopMapper; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.service.IRunningTaskByShopService; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; // 检查集合是否为空 + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 执行的任务Service业务层处理 + * + * @author yxy + * @date 2025-08-5 + */ +@RequiredArgsConstructor +@Service +public class RunningTaskByShopServiceImpl implements IRunningTaskByShopService { + + private final RunningTaskByShopMapper baseMapper; + + private final ShopMapper shopMapper; + private final StringRedisTemplate stringRedisTemplate; + + @DS("slave") + @Override + public List selectGetShopGoodsList(String tableName,String isOnsale,String isbn,String priceDown,String priceUp,String startDate,String endDate, Long pageNum, Long pageSize,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode) { + + Long priceUpLong = null; + Long priceDownLong = null; + if (priceUp != null && StringUtils.isNotEmpty(priceUp)){ + priceUpLong = Long.parseLong(new BigDecimal(priceUp).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + if (priceDown != null && StringUtils.isNotEmpty(priceDown)){ + priceDownLong = Long.parseLong(new BigDecimal(priceDown).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + + + return baseMapper.selectGetShopGoodsList(tableName,isOnsale,isbn,priceDownLong,priceUpLong,startDate,endDate, pageNum, pageSize, goodsName, stockDown, stockUp, trilateralId, goodsCode, skuCode); + } + + @DS("slave") + @Override + public int selectGetShopGoodsListCount(String tableName,String isOnsale,String isbn,String priceDown,String priceUp,String startDate,String endDate,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode) { + + Long priceUpLong = null; + Long priceDownLong = null; + if (priceUp != null && StringUtils.isNotEmpty(priceUp)){ + priceUpLong = Long.parseLong(new BigDecimal(priceUp).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + if (priceDown != null && StringUtils.isNotEmpty(priceDown)){ + priceDownLong = Long.parseLong(new BigDecimal(priceDown).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + + return baseMapper.selectGetShopGoodsListCount(tableName,isOnsale,isbn,priceDownLong,priceUpLong,startDate,endDate, goodsName, stockDown, stockUp, trilateralId, goodsCode, skuCode); + } + + @DS("slave") + @Override + public List selectGetShopGoodsListByDto(RunningTaskShopGoodsDto runningTaskShopGoodsDto){ + Long priceUpLong = null; + Long priceDownLong = null; + if (runningTaskShopGoodsDto.getPriceUp() != null){ + priceUpLong = Long.parseLong(new BigDecimal(runningTaskShopGoodsDto.getPriceUp()).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + if (runningTaskShopGoodsDto.getPriceDown() != null){ + priceDownLong = Long.parseLong(new BigDecimal(runningTaskShopGoodsDto.getPriceDown()).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + runningTaskShopGoodsDto.setPriceUp(priceUpLong); + runningTaskShopGoodsDto.setPriceDown(priceDownLong); + return baseMapper.selectGetShopGoodsListByDto(runningTaskShopGoodsDto); + } + + @DS("slave") + @Override + public int selectNumByIsbn(String tableName, String isbn){ + return baseMapper.selectNumByIsbn(tableName,isbn); + } + + + @DS("slave") + @Override + public int selectGetShopGoodsNum(String tableName,String isOnSale,String isbn,String priceDown,String priceUp,String startDate,String endDate,String goodsName,String stockDown,String stockUp,String trilateralId,String goodsCode,String skuCode) { + Long priceUpLong = null; + Long priceDownLong = null; + if (priceUp != null && StringUtils.isNotEmpty(priceUp)){ + priceUpLong = Long.parseLong(new BigDecimal(priceUp).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + if (priceDown != null && StringUtils.isNotEmpty(priceDown)){ + priceDownLong = Long.parseLong(new BigDecimal(priceDown).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + return baseMapper.selectGetShopGoodsNum(tableName,isOnSale,isbn,priceDownLong,priceUpLong,startDate,endDate, goodsName, stockDown, stockUp, trilateralId, goodsCode, skuCode); + } + + @DS("slave") + @Override + public int delShopGoods(String tableName,String isOnSale,String isbn,String priceDown,String priceUp,String startDate,String endDate){ + Long priceUpLong = null; + Long priceDownLong = null; + if (priceUp != null && StringUtils.isNotEmpty(priceUp)){ + priceUpLong = Long.parseLong(new BigDecimal(priceUp).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + if (priceDown != null && StringUtils.isNotEmpty(priceDown)){ + priceDownLong = Long.parseLong(new BigDecimal(priceDown).multiply(new BigDecimal(100)).toBigInteger().toString()); + } + return baseMapper.delShopGoods(tableName,isOnSale,isbn,priceDownLong,priceUpLong,startDate,endDate); + } + + @DS("slave") + @Override + public int selectByTrilateralId(String tableName, String trilateralId) { + return baseMapper.selectByTrilateralId(tableName, trilateralId); + } + + @DS("slave") + @Override + public RunningTask selectVoByTrilateralId(String tableName,String trilateralId){ + return baseMapper.selectVoByTrilateralId(tableName,trilateralId); + } + + @DS("slave") + @Override + public String selectLastFinishTime(String tableName){ + return baseMapper.selectLastFinishTime(tableName); + } + + @DS("slave") + @Override + public List selectByIsbn(String tableName,String isbn){ + return baseMapper.selectByIsbn(tableName,isbn); + } + + @DS("slave") + @Override + public List selectTaskShopNum(String tableName,Long taskId) { + return baseMapper.selectTaskShopNum(tableName,taskId); + } + + @DS("slave") + @Override + public int selectGetShopGoodsNumByTasKId(String tableName, String taskId) { + return baseMapper.selectGetShopGoodsNumByTasKId(tableName, taskId); + } + + @DS("slave") + @Override + public String selectStatus(String tableName) { + int num = checkTableExists(tableName); + if (num == 0) { + return "3"; + } + String status = baseMapper.selectStatus(tableName); + if (status == null || StringUtils.isEmpty(status) || status.equals("3")) { + return "3"; + } else { + return status; + } + } + + @DS("slave") + @Override + public List selectRepeatNoPage(String tableName){ + List mapList = baseMapper.selectRepeat(tableName); + // 按ISBN分组,计算每个ISBN需要保留的记录数 + Map isbnCounts = mapList.stream() + .collect(Collectors.groupingBy( + m -> m.getIsbn().toString(), + Collectors.counting() + )); + + // 收集需要保留的记录 + Map keptCounts = new HashMap<>(); + List result = new ArrayList<>(); + + for (SuccessDataItemDto item : mapList) { + String isbn = item.getIsbn().toString(); + long total = isbnCounts.get(isbn); + int kept = keptCounts.getOrDefault(isbn, 0); + + if (kept < total - 1) { // 保留n-1条 + result.add(item); + keptCounts.put(isbn, kept + 1); + } + } + return result; + } + + @DS("slave") + @Override + public List selectShopGoodsList(ErpGoodsDto erpGoodsDto){ + if (erpGoodsDto.getPriceUp() != null && StringUtils.isNotEmpty(erpGoodsDto.getPriceUp())){ + erpGoodsDto.setPriceUp(new BigDecimal(erpGoodsDto.getPriceUp()).multiply(new BigDecimal(100)).toString()); + } + if (erpGoodsDto.getPriceDown() != null && StringUtils.isNotEmpty(erpGoodsDto.getPriceDown())){ + erpGoodsDto.setPriceDown(new BigDecimal(erpGoodsDto.getPriceDown()).multiply(new BigDecimal(100)).toString()); + } + return baseMapper.selectShopGoodsList(erpGoodsDto); + } + + /** + * kfz专用导出店铺商品数据 + * @param erpGoodsDto + * @return + */ + @DS("slave") + @Override + public List selectKfzShopGoodsList(ErpGoodsDto erpGoodsDto){ + if (erpGoodsDto.getPriceUp() != null && StringUtils.isNotEmpty(erpGoodsDto.getPriceUp())){ + erpGoodsDto.setPriceUp(new BigDecimal(erpGoodsDto.getPriceUp()).multiply(new BigDecimal(100)).toString()); + } + if (erpGoodsDto.getPriceDown() != null && StringUtils.isNotEmpty(erpGoodsDto.getPriceDown())){ + erpGoodsDto.setPriceDown(new BigDecimal(erpGoodsDto.getPriceDown()).multiply(new BigDecimal(100)).toString()); + } + return baseMapper.selectKfzShopGoodsList(erpGoodsDto); + } + + @DS("slave") + @Override + public Page selectRepeat(String tableName,Long pageNum,Long pageSize){ + Page page = new Page<>(pageNum, pageSize); + List mapList = baseMapper.selectRepeat(tableName); + if (CollectionUtils.isEmpty(mapList)) { + return page; + } + + // 按ISBN分组,计算每个ISBN需要保留的记录数 + Map isbnCounts = mapList.stream() + .collect(Collectors.groupingBy( + m -> m.getIsbn().toString(), + Collectors.counting() + )); + + // 收集需要保留的记录 + Map keptCounts = new HashMap<>(); + List result = new ArrayList<>(); + + for (SuccessDataItemDto item : mapList) { + String isbn = item.getIsbn().toString(); + long total = isbnCounts.get(isbn); + int kept = keptCounts.getOrDefault(isbn, 0); + + if (kept < total - 1) { // 保留n-1条 + result.add(item); + keptCounts.put(isbn, kept + 1); + } + } + + // 使用MyBatis-Plus的Page对象 + page.setTotal(result.size()); + + int fromIndex = (pageNum.intValue() - 1) * pageSize.intValue(); + int toIndex = Math.min(fromIndex + pageSize.intValue(), result.size()); + + if (fromIndex > result.size()) { + page.setRecords(Collections.emptyList()); + } else { + page.setRecords(result.subList(fromIndex, toIndex)); + } + + return page; + } + + @DS("slave") + @Override + public int checkTableExists(String tableName) { + return baseMapper.checkTableExists(tableName); + } + + @DS("slave") + @Override + public void createTable(String tableName) { + baseMapper.createTable(tableName); + } + + @DS("slave") + @Override + public void insert(String tableName, RunningTask task) { + baseMapper.insert(tableName, task); + } + + @DS("slave") + @Override + public void update(String tableName, RunningTask task) { + baseMapper.update(tableName, task); + } + + @DS("slave") + @Override + public void batchInsert(String tableName, List list) { + baseMapper.batchInsert(tableName, list); + } + + + @DS("slave") + @Override + public void updateStatus(String tableName) { + baseMapper.updateStatus(tableName); + } + + @DS("slave") + @Override + public void deleteAll(String tableName) { + baseMapper.deleteAll(tableName); + } + + @DS("slave") + @Override + public void deleteByStatus(String tableName,String status){ + baseMapper.deleteByStatus(tableName,status); + } + + @DS("slave") + @Override + public void deleteByTaskId(String tableName,String taskId){ + baseMapper.deleteByTaskId(tableName,taskId); + } + + @DS("slave") + @Override + public void deleteByGoodsId(String tableName, String goodsId) { + baseMapper.deleteByGoodsId(tableName, goodsId); + } + + @DS("slave") + @Override + public List selectOnSaleGoodsId(String tableName) { + return baseMapper.selectOnSaleGoodsId(tableName); + } + + @DS("slave") + @Override + public List selectByGoodsId(String tableName, String trilateralId) { + return baseMapper.selectByGoodsId(tableName, trilateralId); + } + + @DS("slave") + @Override + public void updateSuccessDataById( String tableName, String id, String successDataJsonStr) { + baseMapper.updateSuccessDataById(tableName, id, successDataJsonStr); + } + @DS("slave") + @Override + public List getShopGoodsList(String tableName) { + return baseMapper.getShopGoodsList(tableName); + } + @DS("slave") + @Override + public Integer getShopGoodsTotalNum(String tableName) { + return baseMapper.getShopGoodsTotalNum(tableName); + } + + @DS("slave") + @Override + public Integer getShopGoodsTotalNumByTaskId(String tableName,Long taskId){ + return baseMapper.getShopGoodsTotalNumByTaskId(tableName,taskId); + } + + @DS("slave") + @Override + public Map batchCheckGoodsIdExists(String tableName, List goodsIds) { + if (goodsIds.isEmpty()) { + return new HashMap<>(); + } + + // 分批处理,避免IN条件过长 + List> batches = Lists.partition(goodsIds, 1000); + Map result = new ConcurrentHashMap<>(); + + batches.parallelStream().forEach(batch -> { + List> existsList = baseMapper.batchCheckExists(tableName, batch); + existsList.forEach(item -> { + String goodsId = item.get("goods_id").toString(); + Boolean exists = "1".equals(item.get("exists_flag").toString()); + result.put(goodsId, exists); + }); + }); + + return result; + } + + @Override + @DS("slave") + public List selectGetShopGoodsListAll(String tableName, String isOnsale, Long pageNum, Long pageSize) { + return baseMapper.selectGetShopGoodsListAll(tableName,isOnsale, pageNum, pageSize); + } + + @DS("slave") + @Override + public Integer countAll(String tableName) { + return baseMapper.countAll(tableName); + } + + /** + * 批量查询goods_id是否存在,返回存在的goods_id列表 + * @param tableName + * @param goodsIds + * @return + */ + @DS("slave") + @Override + public List batchSelectExistsByGoodsIds(String tableName,List goodsIds){ + return baseMapper.batchSelectExistsByGoodsIds(tableName,goodsIds); + } + + @DS("slave") + @Override + public Map selectTodayGoods(List shopId) { + + /** 等待修改读取缓存中的数据 */ + + Map resMap = new HashMap<>(); + + if (CollectionUtils.isEmpty(shopId)) { + System.out.println("用户无关联店铺,返回空数据"); + resMap.put("todayPublishGoods", 0); + resMap.put("todayUpdateGoods", 0); + resMap.put("todayDeleteGoods", 0); + return resMap; + } + + String startTime = LocalDate.now().atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + String endTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + + // 初始化统计变量 + int todayPublishGoods = 0; + int todayEditGoodsTotal = 0; + int todayDelGoodsTotal = 0; + + int processedTables = 0; + int skippedTables = 0; + + long startTimeMs = System.currentTimeMillis(); + + for (String shopIdStr : shopId) { + String tableName = "t_running_task_" + shopIdStr; + + try { + int checkMark = baseMapper.checkTableExists(tableName); + if (checkMark == 0) { + skippedTables++; + continue; + } + + Map res = baseMapper.selectTodayGoods(tableName, startTime, endTime); + processedTables++; + + // 安全转换每个店铺的结果 + if (res != null) { + todayPublishGoods += safeConvertToInt(res.get("todayPublishGoods")); + todayEditGoodsTotal += safeConvertToInt(res.get("todayEditGoods")); + todayDelGoodsTotal += safeConvertToInt(res.get("todayDelGoods")); + } + } catch (Exception e) { + System.out.printf("查询店铺今日商品数据异常,店铺ID: %d, 表名: %s, 异常信息: %s", + Long.parseLong(shopIdStr), tableName, e.getMessage()); + } + } + + long endTimeMs = System.currentTimeMillis(); + + // 将统计结果放入返回map + resMap.put("todayPublishGoods", todayPublishGoods); + resMap.put("todayUpdateGoods", todayEditGoodsTotal); + resMap.put("todayDeleteGoods", todayDelGoodsTotal); + + // 添加性能统计信息(可选) + resMap.put("_stats", Map.of( + "processedTables", processedTables, + "skippedTables", skippedTables, + "queryTimeMs", endTimeMs - startTimeMs + )); + + System.out.printf("今日商品数据查询完成: 发布=%d, 修改=%d, 删除=%d, 处理表=%d, 跳过表=%d, 耗时=%dms%n", + todayPublishGoods, todayEditGoodsTotal, todayDelGoodsTotal, + processedTables, skippedTables, endTimeMs - startTimeMs); + + return resMap; + } + + // 安全类型转换方法 + private int safeConvertToInt(Object value) { + if (value == null) return 0; + if (value instanceof Integer) return (Integer) value; + if (value instanceof Long) return ((Long) value).intValue(); + if (value instanceof BigDecimal) return ((BigDecimal) value).intValue(); + if (value instanceof BigInteger) return ((BigInteger) value).intValue(); + if (value instanceof Number) return ((Number) value).intValue(); + try { + return Integer.parseInt(value.toString()); + } catch (NumberFormatException e) { + return 0; + } + } + + @DS("slave") + @Override + public Map selectTodaySales(List shopId) { + Map resMap = new HashMap<>(); + + if (CollectionUtils.isEmpty(shopId)) { + System.out.println("用户无关联店铺,返回空数据"); + resMap.put("todayOrder", 0); + resMap.put("turnover", 0); + return resMap; + } + + String todayDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + + int todayOrderTotal = 0; + double profitTotal = 0.0; + + for (String shopIdStr : shopId) { + try { + String orderCountKey = "order_count_" + todayDate + "_" + shopIdStr; + String orderAmountKey = "order_amount_" + todayDate + "_" + shopIdStr; + + String orderCountStr = stringRedisTemplate.opsForValue().get(orderCountKey); + String orderAmountStr = stringRedisTemplate.opsForValue().get(orderAmountKey); + + if (StringUtils.isNotEmpty(orderCountStr)) { + todayOrderTotal += Integer.parseInt(orderCountStr); + } + + // 累加订单金额(利润) + if (StringUtils.isNotEmpty(orderAmountStr)) { + profitTotal += Double.parseDouble(orderAmountStr); + } + + } catch (Exception e) { + System.out.printf("读取Redis数据异常,店铺ID: %s, 异常信息: %s%n", shopIdStr, e.getMessage()); + } + } + + // 将统计结果放入返回map + resMap.put("todayOrder", todayOrderTotal); + resMap.put("turnover", profitTotal); + + System.out.printf("今日销售数据查询完成: 订单数=%d, 利润=%.2f%n", todayOrderTotal, profitTotal); + + return resMap; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningTaskServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningTaskServiceImpl.java new file mode 100644 index 0000000..169a5a8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/RunningTaskServiceImpl.java @@ -0,0 +1,200 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.apache.ibatis.annotations.Param; +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.zhishu.domain.vo.RunningTaskNumVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.util.InterfaceUtils; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.RunningTaskBo; +import org.dromara.zhishu.domain.vo.RunningTaskVo; +import org.dromara.zhishu.domain.RunningTask; +import org.dromara.zhishu.mapper.RunningTaskMapper; +import org.dromara.zhishu.service.IRunningTaskService; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 执行的任务Service业务层处理 + * + * @author yxy + * @date 2025-07-23 + */ +@RequiredArgsConstructor +@Service +public class RunningTaskServiceImpl implements IRunningTaskService { + + private final RunningTaskMapper baseMapper; + + private final IShopService shopService; + + + @DS("slave") + @Override + public List selectGetShopGoodsList(Long shopId,Long pageNum,Long pageSize){ + return baseMapper.selectGetShopGoodsList(shopId,pageNum,pageSize); + } + + + @DS("slave") + @Override + public List> selectLogByTaskId(Long taskId){ + return baseMapper.selectLogByTaskId(taskId); + } + + @DS("slave") + @Override + public Long selectGetShopGoodsNum(Long shopId){ + return baseMapper.selectGetShopGoodsNum(shopId); + } + + @DS("slave") + @Override + public Map selectTaskStatus(){ + return baseMapper.selectTaskStatus(); + } + + @DS("slave") + @Override + public List selectTaskAllNum(Long taskId){ + return baseMapper.selectTaskAllNum(taskId); + } + + @DS("slave") + @Override + public Long selectTaskIsRunning(Long taskId){ + return baseMapper.selectTaskIsRunning(taskId); + } + + @DS("slave") + @Override + public Long selectShopTaskByGetShopGoods(Long shopId){ + return baseMapper.selectShopTaskByGetShopGoods(shopId); + } + + @DS("slave") + @Override + public Long selectTaskStatusByTaskType(Long shopId,String taskType){ + return baseMapper.selectTaskStatusByTaskType(shopId,taskType); + } + + @DS("slave") + @Override + public Long selectTaskStatusByTaskTypeAndIsbn(Long shopId, String taskType, String isbn) { + return baseMapper.selectTaskStatusByTaskTypeAndIsbn(shopId,taskType,isbn); + + } + + @DS("slave") + @Override + public Long selectTaskStatusRunningCount(){ + return baseMapper.selectTaskStatusRunningCount(); + } + + @DS("slave") + @Override + public List selectTaskByGroupShopMd5(){ + return baseMapper.selectTaskByGroupShopMd5(); + } + + @DS("slave") + @Override + public List selectTaskGroupShop(String taskType){ + return baseMapper.selectTaskGroupShop(taskType); + } + + @DS("slave") + @Override + public List selectTaskShopNum(Long taskId,Long shopId){ + return baseMapper.selectTaskShopNum(taskId,shopId); + } + + /** + * 新增执行的任务 + * + * @param bo 执行的任务 + * @return 是否新增成功 + */ + @DS("slave") + @Override + public Boolean insert(RunningTask runningTask) { + return baseMapper.insert(runningTask) > 0; + } + + @DS("slave") + @Override + public Boolean batchInsert(List list){ + return baseMapper.batchInsert(list) > 0; + } + + /** + * 修改执行的任务 暂停/恢复/中止 + * @param runningTask + * @return + */ + @DS("slave") + @Override + public Boolean update(RunningTask runningTask) { + return baseMapper.update(runningTask) > 0; + } + + + @Override + public Map getJavaTaskPool(String ip,String host,String url){ + + Map javaTaskPoolStatusMap = new HashMap(); + + try{ + String javaTaskPool = InterfaceUtils.getInterfaceGetShort("http://"+ip+":"+host,url); + Map map = JsonUtil.transferToObj(javaTaskPool, Map.class); + Map data = (Map) map.get("data"); + + //活跃线程数 + int active = (int) data.get("active"); + //提交任务数 + int submitted = (int) data.get("submitted"); + //完成任务数 + int completed = (int) data.get("completed"); + String shopMd5 = data.get("shopMd5").toString(); + javaTaskPoolStatusMap.put("ip",ip); + javaTaskPoolStatusMap.put("host",host); + javaTaskPoolStatusMap.put("active",active); + javaTaskPoolStatusMap.put("submitted",submitted); + javaTaskPoolStatusMap.put("completed",completed); + javaTaskPoolStatusMap.put("shopMd5",shopMd5); + }catch (Exception e){ + javaTaskPoolStatusMap.put("ip",ip); + javaTaskPoolStatusMap.put("host",host); + javaTaskPoolStatusMap.put("active",-1); + javaTaskPoolStatusMap.put("submitted",-1); + javaTaskPoolStatusMap.put("completed",-1); + javaTaskPoolStatusMap.put("shopMd5","连接中断"); + } + return javaTaskPoolStatusMap; + } + + /** + * 修改拉取的任务 2变3 + * @param shopId + * @return + */ + @DS("slave") + @Override + public Boolean updataStatus(Long shopId,Long taskId) { + return baseMapper.updataStatus("t_running_task_"+shopId,taskId); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopContextServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopContextServiceImpl.java new file mode 100644 index 0000000..70ff8f4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopContextServiceImpl.java @@ -0,0 +1,137 @@ +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.ShopContextBo; +import org.dromara.zhishu.domain.vo.ShopContextVo; +import org.dromara.zhishu.domain.ShopContext; +import org.dromara.zhishu.mapper.ShopContextMapper; +import org.dromara.zhishu.service.IShopContextService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 店铺设置商品描述Service业务层处理 + * + * @author yxy + * @date 2025-09-30 + */ +@RequiredArgsConstructor +@Service +public class ShopContextServiceImpl implements IShopContextService { + + private final ShopContextMapper baseMapper; + + /** + * 查询店铺设置商品描述 + * + * @param id 主键 + * @return 店铺设置商品描述 + */ + @Override + public ShopContextVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + @Override + public ShopContextVo selectByShopId(Long shopId){ + return baseMapper.selectByShopId(shopId); + } + + /** + * 分页查询店铺设置商品描述列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺设置商品描述分页列表 + */ + @Override + public TableDataInfo queryPageList(ShopContextBo 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(ShopContextBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(ShopContextBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(ShopContext::getId); + lqw.eq(bo.getShopId() != null, ShopContext::getShopId, bo.getShopId()); + lqw.eq(StringUtils.isNotBlank(bo.getContext()), ShopContext::getContext, bo.getContext()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ShopContext::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增店铺设置商品描述 + * + * @param bo 店铺设置商品描述 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ShopContextBo bo) { + ShopContext add = MapstructUtils.convert(bo, ShopContext.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改店铺设置商品描述 + * + * @param bo 店铺设置商品描述 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ShopContextBo bo) { + ShopContext update = MapstructUtils.convert(bo, ShopContext.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ShopContext 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/ShopDetailServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopDetailServiceImpl.java new file mode 100644 index 0000000..4de3170 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopDetailServiceImpl.java @@ -0,0 +1,362 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import org.dromara.zhishu.domain.ShopWarehouseAuto; +import org.dromara.zhishu.service.IShopWarehouseAutoService; +import org.dromara.zhishu.util.HttpUtils; +import org.dromara.zhishu.util.JsonObjUtil; +import org.dromara.common.core.exception.ServiceException; +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.oss.core.OssClient; +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.zhishu.domain.bo.ShopContextBo; +import org.dromara.zhishu.domain.bo.ShopWarehouseBo; +import org.dromara.zhishu.domain.vo.ShopContextVo; +import org.dromara.zhishu.domain.vo.ShopWarehouseVo; +import org.dromara.zhishu.mapper.ShopContextMapper; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.service.IShopContextService; +import org.dromara.zhishu.service.IShopWarehouseService; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.ShopDetailBo; +import org.dromara.zhishu.domain.vo.ShopDetailVo; +import org.dromara.zhishu.domain.ShopDetail; +import org.dromara.zhishu.mapper.ShopDetailMapper; +import org.dromara.zhishu.service.IShopDetailService; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.LinkedHashMap; +import java.util.Collection; +import java.util.stream.Collectors; +import java.util.HashMap; + +/** + * 商品详情Service业务层处理 + * + * @author yxy + * @date 2025-03-13 + */ +@RequiredArgsConstructor +@Service +public class ShopDetailServiceImpl implements IShopDetailService { + + private final ShopDetailMapper baseMapper; + + private final IShopContextService shopContextService; + + private final IShopWarehouseService shopWarehouseService; + + private final IShopWarehouseAutoService shopWarehouseAutoService; + + /** + * 查询商品详情 + * + * @param id 主键 + * @return 商品详情 + */ + @Override + public ShopDetailVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + @Override + public ShopDetailVo queryByShopId(Long shopId) { + ShopDetailVo shopDetailVo = baseMapper.selectVoByShopId(shopId); + + shopDetailVo.setWarehouseList( + shopWarehouseService.queryListByShopId(shopId) + .stream() + .map(ShopWarehouseVo::getUserId) + .collect(Collectors.toList()) + ); + shopDetailVo.setMappingList( + shopWarehouseAutoService.queryListByShopId(shopId) + .stream() + .map(item -> item.getUserId()+"-"+item.getWarehouseId()) + .collect(Collectors.toList()) + ); + + ShopContextVo shopContextVo = shopContextService.selectByShopId(shopId); + if(shopContextVo != null){ + shopDetailVo.setContext(shopContextVo.getContext()); + } + return shopDetailVo; + } + + /** + * 分页查询商品详情列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品详情分页列表 + */ + @Override + public TableDataInfo queryPageList(ShopDetailBo 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(ShopDetailBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(ShopDetailBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(ShopDetail::getId); + lqw.eq(bo.getShopId() != null, ShopDetail::getShopId, bo.getShopId()); + lqw.eq(bo.getTemplateId() != null, ShopDetail::getTemplateId, bo.getTemplateId()); + lqw.eq(bo.getHighPrice() != null, ShopDetail::getHighPrice, bo.getHighPrice()); + lqw.eq(bo.getLowPrice() != null, ShopDetail::getLowPrice, bo.getLowPrice()); + lqw.eq(bo.getSaleTemplateId() != null, ShopDetail::getSaleTemplateId, bo.getSaleTemplateId()); + lqw.eq(StringUtils.isNotBlank(bo.getSevenDays()), ShopDetail::getSevenDays, bo.getSevenDays()); + lqw.eq(StringUtils.isNotBlank(bo.getIsSecondHand()), ShopDetail::getIsSecondHand, bo.getIsSecondHand()); + lqw.eq(StringUtils.isNotBlank(bo.getCarouselNum()), ShopDetail::getCarouselNum, bo.getCarouselNum()); + lqw.eq(StringUtils.isNotBlank(bo.getIsDetailsImg()), ShopDetail::getIsDetailsImg, bo.getIsDetailsImg()); + lqw.eq(StringUtils.isNotBlank(bo.getIsCatalogueDetails()), ShopDetail::getIsCatalogueDetails, bo.getIsCatalogueDetails()); + lqw.eq(StringUtils.isNotBlank(bo.getIsInformationImg()), ShopDetail::getIsInformationImg, bo.getIsInformationImg()); + lqw.eq(StringUtils.isNotBlank(bo.getTitlePrefix()), ShopDetail::getTitlePrefix, bo.getTitlePrefix()); + lqw.eq(StringUtils.isNotBlank(bo.getTitleSuffix()), ShopDetail::getTitleSuffix, bo.getTitleSuffix()); + lqw.eq(StringUtils.isNotBlank(bo.getTitleFilter()), ShopDetail::getTitleFilter, bo.getTitleFilter()); + lqw.eq(StringUtils.isNotBlank(bo.getItemNumberPrefix()), ShopDetail::getItemNumberPrefix, bo.getItemNumberPrefix()); + lqw.eq(StringUtils.isNotBlank(bo.getTitleConsistOf()), ShopDetail::getTitleConsistOf, bo.getTitleConsistOf()); + lqw.eq(StringUtils.isNotBlank(bo.getSpaceCharacter()), ShopDetail::getSpaceCharacter, bo.getSpaceCharacter()); + lqw.eq(StringUtils.isNotBlank(bo.getAutoTruncation()), ShopDetail::getAutoTruncation, bo.getAutoTruncation()); + lqw.eq(StringUtils.isNotBlank(bo.getMySetUp()), ShopDetail::getMySetUp, bo.getMySetUp()); + lqw.eq(StringUtils.isNotBlank(bo.getSystemSetUp()), ShopDetail::getSystemSetUp, bo.getSystemSetUp()); + lqw.eq(StringUtils.isNotBlank(bo.getFilterSuit()), ShopDetail::getFilterSuit, bo.getFilterSuit()); + lqw.eq(StringUtils.isNotBlank(bo.getIsDelProtect()), ShopDetail::getIsDelProtect, bo.getIsDelProtect()); + lqw.eq(StringUtils.isNotBlank(bo.getIsRemoveProtect()), ShopDetail::getIsRemoveProtect, bo.getIsRemoveProtect()); + lqw.eq(StringUtils.isNotBlank(bo.getBootPrice()), ShopDetail::getBootPrice, bo.getBootPrice()); + lqw.eq(StringUtils.isNotBlank(bo.getOwnPictures()), ShopDetail::getOwnPictures, bo.getOwnPictures()); + return lqw; + } + + /** + * 新增商品详情 + * + * @param bo 商品详情 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ShopDetailBo bo) { + ShopDetail add = MapstructUtils.convert(bo, ShopDetail.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + + +// String url = "http://localhost:30200/api/updateSourceTable"; + String url = "http://localhost:9099/api/updateSourceTable"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ShopID", bo.getShopId().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("调用updateShopDetail接口成功,响应: " + response); + } catch (Exception e) { + System.err.println("调用updateShopDetail接口失败: " + e.getMessage()); + e.printStackTrace(); + } + +// insertShopDetialIntoRedis(bo); + } + return flag; + } + + /** + * 向redis,db7中添加数据 + * @param bo + */ +// public void insertShopDetialIntoRedis(ShopDetailBo bo){ +// if (ObjectUtil.isEmpty(bo) || bo.getShopId() == null) { +// return; +// } +// +// try { +// String redisKey = bo.getShopId().toString(); +// // 构建shop_detail数据结构 +// Map shopDetailData = new LinkedHashMap<>(); +// shopDetailData.put("source_table", "t_shop_detail"); +// shopDetailData.put("data", bo); +// String shopDetailJson = JsonObjUtil.objectToJsonWithSnakeKeys(shopDetailData); +// +// // 获取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_detail".equals(itemMap.get("source_table"))) { +// redisList.set(i, shopDetailJson); +// updated = true; +// break; +// } +// } +// +// // 如果没有找到对应数据,则添加新元素 +// if (!updated) { +// redisList.add(shopDetailJson); +// } +// +// } catch (Exception e) { +// System.out.println(e.getMessage()); +// } +// } + + + /** + * 修改商品详情 + * + * @param bo 商品详情 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ShopDetailBo bo) { + ShopDetail update = MapstructUtils.convert(bo, ShopDetail.class); + validEntityBeforeSave(update); + + // 修改关联的仓库id + shopWarehouseService.deleteByShopId(bo.getShopId()); + for(Long warehouseId : bo.getWarehouseList()){ + ShopWarehouseBo shopWarehouseBo = new ShopWarehouseBo(); + shopWarehouseBo.setUserId(warehouseId); + shopWarehouseBo.setShopId(bo.getShopId()); + shopWarehouseService.insertByBo(shopWarehouseBo); + } + + // 修改关联的进销存仓库 + shopWarehouseAutoService.deleteByShopId(bo.getShopId()); + for (String data : bo.getMappingList()){ + String[] ids = data.split("-"); + String userId = ids[0]; + String warehouseId = ids[1]; + ShopWarehouseAuto shopWarehouseAuto = new ShopWarehouseAuto(); + shopWarehouseAuto.setShopId(bo.getShopId()); + shopWarehouseAuto.setUserId(Long.parseLong(userId)); + shopWarehouseAuto.setWarehouseId(Long.parseLong(warehouseId)); + shopWarehouseAutoService.insertByBo(shopWarehouseAuto); + } + + ShopContextVo shopContextVo = shopContextService.selectByShopId(bo.getShopId()); + if(shopContextVo != null){ + //修改 + ShopContextBo shopContextBo = new ShopContextBo(); + shopContextBo.setId(shopContextVo.getId()); + shopContextBo.setContext(bo.getContext()); + shopContextService.updateByBo(shopContextBo); + }else{ + ShopContextBo shopContextBo = new ShopContextBo(); + shopContextBo.setShopId(bo.getShopId()); + shopContextBo.setContext(bo.getContext()); + shopContextService.insertByBo(shopContextBo); + } + boolean flag = baseMapper.updateById(update) > 0; + if (flag) { + // 修改成功后更新shopDetail的redis数据 + +// String url = "http://localhost:30200/api/updateSourceTable"; + String url = "http://localhost:9099/api/updateSourceTable"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ShopID", bo.getShopId().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("调用updateShopDetail接口成功,响应: " + response); + } catch (Exception e) { + System.err.println("调用updateShopDetail接口失败: " + e.getMessage()); + e.printStackTrace(); + } +// insertShopDetialIntoRedis(bo); + } + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ShopDetail 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 UploadResult upload(MultipartFile file) { + String originalfileName = file.getOriginalFilename(); + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + OssClient storage = OssFactory.instance(); + UploadResult uploadResult; + try { + uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType()); + } catch (IOException e) { + throw new ServiceException(e.getMessage()); + } + + return uploadResult; + } + + @Override + public String selectSaleTemplateIdByShopId(Long shopId) { + return baseMapper.selectSaleTemplateIdByShopId(shopId); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsPublishedLogServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsPublishedLogServiceImpl.java new file mode 100644 index 0000000..5c267b6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsPublishedLogServiceImpl.java @@ -0,0 +1,34 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; +import org.dromara.zhishu.mapper.ShopGoodsPublishedLogMapper; +import org.dromara.zhishu.service.ShopGoodsPublishedLogService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class ShopGoodsPublishedLogServiceImpl extends ServiceImpl implements ShopGoodsPublishedLogService { + + private final ShopGoodsPublishedLogMapper shopGoodsPublishedLogMapper; + + @Override + public ShopGoodsPublishedLog queryPublishedLogByOrderSn(String platformId, String aboutId, Integer platformType, Integer logType, Integer operationType) { + List list = new LambdaQueryChainWrapper<>(shopGoodsPublishedLogMapper) + .eq(ShopGoodsPublishedLog::getDelFlag, "0") + .eq(ShopGoodsPublishedLog::getPlatformId, platformId) + .eq(ShopGoodsPublishedLog::getAboutId, aboutId) + .eq(ShopGoodsPublishedLog::getPlatformType, platformType) + .eq(ShopGoodsPublishedLog::getLogType, logType) + .eq(ShopGoodsPublishedLog::getOperationType, operationType) + .list(); + if (!list.isEmpty()) + return list.get(0); + return null; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsRejectionServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsRejectionServiceImpl.java new file mode 100644 index 0000000..d84ecfa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopGoodsRejectionServiceImpl.java @@ -0,0 +1,100 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.apache.ibatis.annotations.Param; +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.ShopGoodsPublished; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; +import org.dromara.zhishu.domain.ShopGoodsRejection; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.mapper.ShopGoodsPublishedLogMapper; +import org.dromara.zhishu.mapper.ShopGoodsRejectionMapper; +import org.dromara.zhishu.service.IShopService; +import org.dromara.zhishu.service.ShopGoodsPublishedLogService; +import org.dromara.zhishu.service.ShopGoodsRejectionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.awt.print.Pageable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +@RequiredArgsConstructor +public class ShopGoodsRejectionServiceImpl extends ServiceImpl implements ShopGoodsRejectionService { + + @Autowired + private ShopGoodsRejectionMapper shopGoodsRejectionMapper; + + private final IShopService shopService; + @Override + @Transactional + public boolean save(ShopGoodsRejection shopGoodsRejection) { + if (shopGoodsRejection.getCreateTime() == null) { + shopGoodsRejection.setCreateTime(new java.util.Date()); + } + return shopGoodsRejectionMapper.insert(shopGoodsRejection) > 0; + } + + @Override + @Transactional + public boolean delete(Long id) { + return shopGoodsRejectionMapper.deleteById(id) > 0; + } + + @Override + @Transactional + public boolean update(ShopGoodsRejection shopGoodsRejection) { + return shopGoodsRejectionMapper.update(shopGoodsRejection) > 0; + } + + @Override + public ShopGoodsRejection findById(Long id) { + return shopGoodsRejectionMapper.selectById(id); + } + + @Override + public List findAll() { + return shopGoodsRejectionMapper.selectAll(); + } + + @Override + public List findByShopId(String shopId) { + return shopGoodsRejectionMapper.selectByShopId(shopId); + } + + @Override + public List findByPlatformId(String platformId) { + return shopGoodsRejectionMapper.selectByPlatformId(platformId); + } + + @Override + public List search(ShopGoodsRejection condition) { + return shopGoodsRejectionMapper.selectByCondition(condition); + } + + @Override + public TableDataInfo searchWithPage(ShopGoodsRejection bo, PageQuery pageQuery) { + Long userId = LoginHelper.getUserId(); + if(userId != 1){ + bo.setUserId(userId); + } + Page result =shopGoodsRejectionMapper.selectByConditionWithPage(pageQuery.build(),bo); + for (ShopGoodsRejection shopGoodsRejection : result.getRecords()){ + ShopVo shopVo = shopService.queryById(shopGoodsRejection.getShopId()); + shopGoodsRejection.setShopName(shopVo.getShopName()); + } + return TableDataInfo.build(result); + } + + @Override + public int count(ShopGoodsRejection condition) { + return shopGoodsRejectionMapper.countByCondition(condition); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopWarehouseServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopWarehouseServiceImpl.java new file mode 100644 index 0000000..86167e4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ShopWarehouseServiceImpl.java @@ -0,0 +1,93 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.dromara.zhishu.domain.bo.ShopWarehouseBo; +import org.dromara.zhishu.domain.vo.ShopWarehouseVo; +import org.dromara.zhishu.domain.ShopWarehouse; +import org.dromara.zhishu.mapper.ShopWarehouseMapper; +import org.dromara.zhishu.service.IShopWarehouseService; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.stream.Collectors; + +/** + * 店铺与仓库自动发布关联Service业务层处理 + * + * @author yxy + * @date 2025-12-28 + */ +@RequiredArgsConstructor +@Service +public class ShopWarehouseServiceImpl implements IShopWarehouseService { + + private final ShopWarehouseMapper baseMapper; + + /** + * 查询店铺与仓库自动发布关联 + * + * @param id 主键 + * @return 店铺与仓库自动发布关联 + */ + @Override + public ShopWarehouseVo queryById(Long id) { + ShopWarehouse shopWarehouse = baseMapper.selectById(id); + return MapstructUtils.convert(shopWarehouse, ShopWarehouseVo.class); + } + + /** + * 根据店铺ID查询关联列表 + * + * @param shopId 店铺ID + * @return 关联列表 + */ + @Override + public List queryListByShopId(Long shopId) { + List list = baseMapper.selectByShopId(shopId); + return list.stream() + .map(item -> MapstructUtils.convert(item, ShopWarehouseVo.class)) + .collect(Collectors.toList()); + } + + /** + * 新增店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ShopWarehouseBo bo) { + ShopWarehouse add = MapstructUtils.convert(bo, ShopWarehouse.class); + return baseMapper.insert(add) > 0; + } + + /** + * 修改店铺与仓库自动发布关联 + * + * @param bo 店铺与仓库自动发布关联 + * @return 是否修改成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean updateByBo(ShopWarehouseBo bo) { + ShopWarehouse update = MapstructUtils.convert(bo, ShopWarehouse.class); + return baseMapper.update(update) > 0; + } + + /** + * 根据店铺删除关联信息 + * @param shopId 店铺ID + * @return 是否删除成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + 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/SignGeneratorServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SignGeneratorServiceImpl.java new file mode 100644 index 0000000..1ae2acc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SignGeneratorServiceImpl.java @@ -0,0 +1,43 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.service.SignGeneratorService; +import org.springframework.stereotype.Service; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +@RequiredArgsConstructor +@Service +public class SignGeneratorServiceImpl implements SignGeneratorService { + + @Override + public String generateCallbackSign(String loginCode, long timestamp, String secret) { + try { + // 签名算法:SHA256(loginCode + timestamp + secret) + String signStr = loginCode + timestamp + secret; + + // 计算SHA256 + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] hashed = digest.digest(signStr.getBytes()); + + // 转换为十六进制字符串 + return bytesToHex(hashed); + + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-256 algorithm not found", e); + } + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder hexString = new StringBuilder(); + for (byte b : bytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SpecServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SpecServiceImpl.java new file mode 100644 index 0000000..dbf118d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/SpecServiceImpl.java @@ -0,0 +1,246 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONUtil; +import org.dromara.zhishu.util.HttpUtils; +import org.dromara.zhishu.util.JsonObjUtil; +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.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.SpecBo; +import org.dromara.zhishu.domain.vo.SpecVo; +import org.dromara.zhishu.domain.Spec; +import org.dromara.zhishu.mapper.SpecMapper; +import org.dromara.zhishu.service.ISpecService; + +import java.util.*; + +/** + * 自定义规格设置Service业务层处理 + * + * @author yxy + * @date 2025-03-27 + */ +@RequiredArgsConstructor +@Service +public class SpecServiceImpl implements ISpecService { + + private final SpecMapper baseMapper; + + /** + * 查询自定义规格设置 + * + * @param id 主键 + * @return 自定义规格设置 + */ + @Override + public SpecVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + @Override + public SpecVo selectVoByShopId(Long shopId) { + return baseMapper.selectVoByShopId(shopId); + } + + /** + * 分页查询自定义规格设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 自定义规格设置分页列表 + */ + @Override + public TableDataInfo queryPageList(SpecBo 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(SpecBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(SpecBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(Spec::getId); + lqw.eq(StringUtils.isNotBlank(bo.getSpecTypeId()), Spec::getSpecTypeId, bo.getSpecTypeId()); + lqw.like(StringUtils.isNotBlank(bo.getSpecTypeName()), Spec::getSpecTypeName, bo.getSpecTypeName()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecCompose()), Spec::getSpecCompose, bo.getSpecCompose()); + lqw.like(StringUtils.isNotBlank(bo.getSpecName()), Spec::getSpecName, bo.getSpecName()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecPrefix()), Spec::getSpecPrefix, bo.getSpecPrefix()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecSuffix()), Spec::getSpecSuffix, bo.getSpecSuffix()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecCodeCompose()), Spec::getSpecCodeCompose, bo.getSpecCodeCompose()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecCodePrefix()), Spec::getSpecCodePrefix, bo.getSpecCodePrefix()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecCodeSuffix()), Spec::getSpecCodeSuffix, bo.getSpecCodeSuffix()); + lqw.eq(StringUtils.isNotBlank(bo.getSpecSyUrl()), Spec::getSpecSyUrl, bo.getSpecSyUrl()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Spec::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增自定义规格设置 + * + * @param bo 自定义规格设置 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(SpecBo bo) { + Spec add = MapstructUtils.convert(bo, Spec.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + // 新增成功后添加到Redis + + //更新Redis +// String specUrl = "http://localhost:30200/api/updateSourceTable"; + String specUrl = "http://localhost:9099/api/updateSourceTable"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ShopID", bo.getShopId().toString()); + + // 设置请求头 + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + try { + // 将请求对象转换为JSON字符串 + String jsonBody = HttpUtils.convertObjectToJson(requestBody); + + // 发送POST请求 + String response = HttpUtils.sendPost(specUrl, headers, jsonBody); + System.out.println("调用updateShopHandler接口成功,响应: " + requestBody); + } catch (Exception e) { + System.err.println("调用updateShopHandler接口失败: " + e.getMessage()); + e.printStackTrace(); + } +// insertSpecIntoRedis(bo); + } + return flag; + } + + /** + * 修改自定义规格设置 + * + * @param bo 自定义规格设置 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(SpecBo bo) { + Spec update = MapstructUtils.convert(bo, Spec.class); + validEntityBeforeSave(update); + boolean flag = baseMapper.updateById(update) > 0; + if (flag) { + // 更新成功后更新Redis中的spec数据 + + + //更新Redis +// String specUrl = "http://localhost:30200/api/updateSourceTable"; + String specUrl = "http://localhost:9099/api/updateSourceTable"; + + // 创建请求体,包含ID参数 + Map requestBody = new HashMap<>(); + requestBody.put("ShopID", bo.getShopId().toString()); + + // 设置请求头 + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json"); + + try { + // 将请求对象转换为JSON字符串 + String jsonBody = HttpUtils.convertObjectToJson(requestBody); + + // 发送POST请求 + String response = HttpUtils.sendPost(specUrl, headers, jsonBody); + System.out.println("调用updateShopHandler接口成功,响应: " + requestBody); + } catch (Exception e) { + System.err.println("调用updateShopHandler接口失败: " + e.getMessage()); + e.printStackTrace(); + } +// insertSpecIntoRedis(bo); + } + return flag; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(Spec entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除自定义规格设置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 向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_specd数据结构 +// 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()); +// } +// } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/StockChangeLogServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/StockChangeLogServiceImpl.java new file mode 100644 index 0000000..dafb2b3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/StockChangeLogServiceImpl.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.domain.vo.StockChangeLogVo; +import org.dromara.zhishu.mapper.StockChangeLogMapper; +import org.dromara.zhishu.mapper.TaskMapper; +import org.dromara.zhishu.service.StockChangeLogService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class StockChangeLogServiceImpl implements StockChangeLogService { + + private final StockChangeLogMapper baseMapper; + @Override + public List selectShopStockLogbyCreateBy(String id,String aboutId) { + return baseMapper.selectByShopGoodsIdAndCreateBy(id ,aboutId); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TAuditServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TAuditServiceImpl.java new file mode 100644 index 0000000..98e0469 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TAuditServiceImpl.java @@ -0,0 +1,233 @@ +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.zhishu.domain.NewUserInfo; +import org.dromara.zhishu.domain.TBookAudit; +import org.dromara.zhishu.domain.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.TAuditBo; +import org.dromara.zhishu.domain.vo.TAuditVo; +import org.dromara.zhishu.domain.TAudit; +import org.dromara.zhishu.mapper.TAuditMapper; +import org.dromara.zhishu.service.ITAuditService; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; +import org.springframework.http.ResponseEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 审核Service业务层处理 + * + * @author Lion Li + * @date 2025-04-01 + */ +@RequiredArgsConstructor +@Service +public class TAuditServiceImpl implements ITAuditService { + + private static final Logger log = LoggerFactory.getLogger(TAuditServiceImpl.class); + + @Autowired + private final TAuditMapper baseMapper; + + @Autowired + private RestTemplate restTemplate; + + /** + * 查询审核 + * + * @param id 主键 + * @return 审核 + */ + @Override + public TAuditVo queryById(Long id) { + TAuditVo tAuditVo = baseMapper.selectVoById(id); + NewUserInfo infor = baseMapper.selectUserList(id); + tAuditVo.setCompanyName(infor.getCompanyName()); + tAuditVo.setCompanyType(infor.getCompanyType()); + tAuditVo.setContactPerson(infor.getContactPerson()); + tAuditVo.setContactPhone(infor.getContactPhone()); + tAuditVo.setEmail(infor.getEmail()); + tAuditVo.setLicense(infor.getLicense()); + tAuditVo.setRemark(infor.getRemark()); + tAuditVo.setLicenseNumber(infor.getLicenseNumber()); + tAuditVo.setLicenseName(infor.getLicenseName()); + tAuditVo.setCardIdentity(infor.getCardIdentity()); + tAuditVo.setLicenseTime(infor.getLicenseTime()); + tAuditVo.setBusinessLicense(infor.getBusinessLicense()); + tAuditVo.setBusinessLicenseTime(infor.getBusinessLicenseTime()); + tAuditVo.setAdress(infor.getAdress()); + return tAuditVo; + } + + /** + * 分页查询审核列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 审核分页列表 + */ + @Override + public TableDataInfo queryPageList(TAuditBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); +// Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + Page result = baseMapper.selectPageVo(pageQuery.build(), bo); +// //获取result.getRecords()数据,并将里面内容进行赋值 + // 遍历result.getRecords() + for (int i = 0; i < result.getRecords().size(); i++) { + // 获取当前行的id + Long id = result.getRecords().get(i).getAuditId(); + // 获取当前行的用户名称 + TAudit tAudit = baseMapper.selectId(id); + if (tAudit != null) { + String name = baseMapper.selectUserName(tAudit.getUserId()); + + result.getRecords().get(i).setUserName(name); + result.getRecords().get(i).setAdminId(tAudit.getAdminId()); +// result.getRecords().get(i).setUserId(tAudit.getUserId()); + result.getRecords().get(i).setStatus(tAudit.getStatus()); + result.getRecords().get(i).setId(tAudit.getId()); + } + + } + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的审核列表 + * + * @param bo 查询条件 + * @return 审核列表 + */ + @Override + public List queryList(TAuditBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + + private LambdaQueryWrapper buildQueryWrapper(TAuditBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByDesc(TAudit::getId); + lqw.eq(bo.getUserId() != null, TAudit::getUserId, bo.getUserId()); + lqw.eq(bo.getAdminId() != null, TAudit::getAdminId, bo.getAdminId()); +// lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), TAudit::getCompanyName, bo.getCompanyName()) + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TAudit::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增审核 + * + * @param bo 审核 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(TAuditBo bo) { + TAudit add = MapstructUtils.convert(bo, TAudit.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { +// bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改审核 + * + * @param bo 审核 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TAuditBo bo) { + // 修改用户信息 + bo.setStatus("2"); + TAudit update = MapstructUtils.convert(bo, TAudit.class); + NewUserInfo newUserInfo = new NewUserInfo(); + newUserInfo.setCompanyName(bo.getCompanyName()); + newUserInfo.setCompanyType(bo.getCompanyType()); + newUserInfo.setContactPerson(bo.getContactPerson()); + newUserInfo.setContactPhone(bo.getContactPhone()); + newUserInfo.setEmail(bo.getEmail()); + newUserInfo.setLicense(bo.getLicense()); + newUserInfo.setRemark(bo.getRemark()); + newUserInfo.setAuditId(update.getId()); + baseMapper.updateByUser(newUserInfo); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TAudit entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除审核信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Transactional + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + baseMapper.deleteUser(ids); + } + return baseMapper.deleteByIds(ids) > 0; + } + + + @Override + public int updateByStatus(TAuditBo bo) { + //获取用户id + Long userId = baseMapper.selectUserId(bo.getId()); + if (bo.getStatus().equals("0")) { + //删除当前用户角色(游客) + Integer message = baseMapper.deleteUserRole(userId, 1906216348137664514L); + //新增角色(入驻书店) + Integer message1 = baseMapper.insertUserRole(userId, 1905510246538407937L); +// 1906216348137664514 --->Visitor +// 1905510246538407937--->Settled + + // 调用外部接口添加会员 + try { + String url = "https://newadmin.buzhiyushu.cn/settledMember/record/addMember?userId=" + userId; + ResponseEntity response = restTemplate.postForEntity(url, null, String.class); + log.info("调用添加会员接口结果: {}", response.getBody()); + } catch (Exception e) { + log.error("调用添加会员接口失败: {}", e.getMessage(), e); + } + } + +//修改审核状态 + return baseMapper.updateStatus(bo); + } + + @Override + public Integer InsertLog(TAuditBo bo) { + Integer message = baseMapper.insertAuditLog(bo); + return message; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TBookAuditServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TBookAuditServiceImpl.java new file mode 100644 index 0000000..6ad259b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TBookAuditServiceImpl.java @@ -0,0 +1,159 @@ +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.ZhishuShopGoods; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.TBookAuditBo; +import org.dromara.zhishu.domain.vo.TBookAuditVo; +import org.dromara.zhishu.domain.TBookAudit; +import org.dromara.zhishu.mapper.TBookAuditMapper; +import org.dromara.zhishu.service.ITBookAuditService; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 图书审核管理Service业务层处理 + * + * @author Lion Li + * @date 2025-04-18 + */ +@RequiredArgsConstructor +@Service +public class TBookAuditServiceImpl implements ITBookAuditService { + + private final TBookAuditMapper baseMapper; + + /** + * 查询图书审核管理 + * + * @param id 主键 + * @return 图书审核管理 + */ + @Override + public TBookAuditVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询图书审核管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 图书审核管理分页列表 + */ + @Override + public TableDataInfo queryPageList(TBookAuditBo bo, PageQuery pageQuery) { + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的图书审核管理列表 + * + * @param bo 查询条件 + * @return 图书审核管理列表 + */ + @Override + public List queryList(TBookAuditBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TBookAuditBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(TBookAudit::getId); + lqw.eq(StringUtils.isNotBlank(bo.getProductId()), TBookAudit::getProductId, bo.getProductId()); + lqw.like(StringUtils.isNotBlank(bo.getGoodsName()), TBookAudit::getGoodsName, bo.getGoodsName()); + lqw.eq(StringUtils.isNotBlank(bo.getIsbn()), TBookAudit::getIsbn, bo.getIsbn()); + lqw.eq(StringUtils.isNotBlank(bo.getArtNo()), TBookAudit::getArtNo, bo.getArtNo()); + lqw.eq(StringUtils.isNotBlank(bo.getConditionCode()), TBookAudit::getConditionCode, bo.getConditionCode()); + lqw.eq(StringUtils.isNotBlank(bo.getItemNumber()), TBookAudit::getItemNumber, bo.getItemNumber()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TBookAudit::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增图书审核管理 + * + * @param bo 图书审核管理 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(TBookAuditBo bo) { + TBookAudit add = MapstructUtils.convert(bo, TBookAudit.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { +// bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改图书审核管理 + * + * @param bo 图书审核管理 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TBookAuditBo bo) { + TBookAudit update = MapstructUtils.convert(bo, TBookAudit.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TBookAudit entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除图书审核管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 修改图书审核管理状态 + * + * @param bo 图书审核管理 + * @return 是否修改成功 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public Boolean updateStatus(TBookAuditBo bo) { + if(bo.getStatus().equals("0")){ + TBookAudit tBookAudit = baseMapper.selectGoods(bo.getId()); + baseMapper.deleteById(bo.getId()); + }else { + baseMapper.deleteById(bo.getId()); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TDepotServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TDepotServiceImpl.java new file mode 100644 index 0000000..8732ab9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TDepotServiceImpl.java @@ -0,0 +1,384 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.collection.ConcurrentHashSet; +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.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.TLogisticsVo; +import org.dromara.zhishu.domain.vo.TShelvesVo; +import org.dromara.zhishu.mapper.TDepotMapper; +import org.dromara.zhishu.mapper.TShelvesMapper; +import org.dromara.zhishu.service.ITDepotService; +import org.dromara.zhishu.service.ITLogisticsService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 仓库信息设置Service业务层处理 + * + * @author Lion Li + * @date 2025-03-26 + */ +@RequiredArgsConstructor +@Service +public class TDepotServiceImpl implements ITDepotService { + + private final TDepotMapper baseMapper; + private final TShelvesMapper shelvesMapper; + private final ITLogisticsService tLogisticsService; + + private static final char FIRST_LETTER = 'A'; + private static final char LAST_LETTER = 'Z'; + private static final Set usedCodes = new ConcurrentHashSet<>(); + + /** + * 查询仓库信息设置 + * + * @param id 主键 + * @return 仓库信息设置 + */ + @Override + public TDepotVo queryById(Long id) { + TDepotVo record = baseMapper.selectVoById(id); +// 通过record.getTemplateId获取到对应的name + TLogisticsVo tLogisticsVo = tLogisticsService.queryById(record.getTemplateId()); + if (tLogisticsVo != null) { + record.setTemplateName(tLogisticsVo.getTemplateName()); + } + return record; + } + + /** + * 根据仓库code查询仓库信息 + * + * @param code + * @return + */ + @Override + public TDepotVo selectDepotByCode(String artNo) { + return baseMapper.selectDepotByCode(artNo); + } + + /** + * 分页查询仓库信息设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 仓库信息设置分页列表 + */ + @Override + public TableDataInfo queryPageList(TDepotBo bo, PageQuery pageQuery) { + Long userId = LoginHelper.getUserId(); + String userName = baseMapper.selectByName(userId); + bo.setUserId(userId); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVo1(pageQuery.build(), bo); + // 动态添加当前用户信息 + if (result != null) { + result.getRecords().forEach(vo -> { + if (vo.getInventory() == null) { + vo.setInventory(0L); + } + vo.setName(vo.getName() + vo.getUnit()); + vo.setUserId(userId); + vo.setUserName(userName); + vo.setLevel(1); + String temName = baseMapper.selectTemName(vo.getTemplateId()); + vo.setTemplateName(temName); + List list = baseMapper.selectByShe(vo.getId()); + if (!list.isEmpty()) { + vo.setHasChildren(true); + } else { + vo.setHasChildren(false); + } + }); + } + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的仓库信息设置列表 + * + * @param bo 查询条件 + * @return 仓库信息设置列表 + */ + @Override + public List queryList(TDepotBo bo) { + // 查询当前用户id并查询出昵称,赋值给bo中的userId + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List list = baseMapper.selectVoList(lqw); + //获取当前用户id并查询出昵称,赋值给list中userName + + list.forEach(vo -> { + vo.setName(vo.getName() + vo.getUnit()); + Long sheNumber = baseMapper.selectSheCount(vo.getId()); + vo.setSheNumber(sheNumber); + vo.setUserName(baseMapper.selectByName(userId)); + }); + return list; + } + + @Override + public List selectList(TDepotBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List list = baseMapper.selectVoList(lqw); + return list; + } + + private LambdaQueryWrapper buildQueryWrapper(TDepotBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getCode()), TDepot::getCode, bo.getCode()); + lqw.eq(bo.getUserId() != null, TDepot::getUserId, bo.getUserId()); + lqw.like(StringUtils.isNotBlank(bo.getName()), TDepot::getName, bo.getName()); + lqw.eq(StringUtils.isNotBlank(bo.getAddress()), TDepot::getAddress, bo.getAddress()); + lqw.eq(StringUtils.isNotBlank(bo.getManager()), TDepot::getManager, bo.getManager()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TDepot::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增仓库信息设置 + * + * @param bo 仓库信息设置 + * @return 是否新增成功 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public Boolean insertByBo(TDepotBo bo) { + TDepot add = MapstructUtils.convert(bo, TDepot.class); + validEntityBeforeSave(add); + //查询仓库code是否存在 +// Long userId = LoginHelper.getUserId(); + Long userId = bo.getUserId() != null ? bo.getUserId() : LoginHelper.getUserId(); + add.setUserId(userId); + add.setTenantId("000000"); +// 将字母变成大写 + String depotCode = add.getCode().toUpperCase(); + add.setCode(depotCode); + + if (StringUtils.isEmpty(bo.getName())) { + throw new RuntimeException("请稍后重试"); + } + + //查询是否存在仓库名称 + Integer message = baseMapper.selectByUser(userId, null, bo.getName()); + if (message != 0) { + throw new RuntimeException("仓库名称重复"); +// return false; + } + //查询是否存在仓库编码 + Integer message1 = baseMapper.selectByUser(userId, add.getCode(), null); + if (message1 != 0) { + throw new RuntimeException("仓库编码已存在"); + } + //查询是否存在仓库名称和编码 + Integer code = baseMapper.selectByUser(userId, add.getCode(), bo.getName()); + if (code != 0) { + throw new RuntimeException("仓库名称和编码已存在"); + } else { + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + } + +// // 生成A-Z或0-9的随机字符 +// public static String generateRandomChar() { +// int randomChoice = ThreadLocalRandom.current().nextInt(36); // 0-35 +// if (randomChoice < 26) { +// // 生成A-Z(ASCII码65-90) +// String str = String.valueOf((char)(randomChoice + 65)); +//// String str=Integer.toString(randomChoice + 65); +// System.out.println(str); +// return str; +// } else { +// // 生成0-9(ASCII码48-57),或直接数字转字符 +// String str=String.valueOf((char)(randomChoice - 26 + 48)); +//// Integer.toString(randomChoice - 26 + 48); +// System.out.println(str); +// return str; +// } +// } + + /** + * 修改仓库信息设置 + * + * @param bo 仓库信息设置 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TDepotBo bo) { + TDepot update = MapstructUtils.convert(bo, TDepot.class); + validEntityBeforeSave(update); + + Long userId = bo.getUserId() != null ? bo.getUserId() : LoginHelper.getUserId(); + + // 检查名称是否重复,排除当前正在修改的仓库 + Integer message = baseMapper.selectByUserAndExcludeCurrent(userId, update.getName(), update.getId()); + if (message != 0) { + throw new RuntimeException("仓库名称重复"); + } + + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TDepot 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) { + if (isValid) { + Long userId = LocalUserId != null ? LocalUserId : LoginHelper.getUserId(); + //查询仓库下是否有书品 + Integer message = baseMapper.selectCount(userId, ids); + + + //查询仓库code +// List codeList=baseMapper.selectByCodes(userId,ids); + //查询仓库中是否有商品,有商品则不删除货位 +// Integer message1=baseMapper.selectCounts(userId,codeList); + //通过shelist查询货位中是否存在货号 + //判断message是否为空,为空则进行删除操作,否则不进行删除操作 + if (message == 0) { + List sheList = baseMapper.selectByids(ids); + //删除货位中的货号 + if (!sheList.isEmpty()) { + baseMapper.deleteByIdFre(sheList); + //删除货位 + baseMapper.deleteByIdShe(ids); + } + baseMapper.deleteByIds(ids); + } else { + throw new RuntimeException("货区下有书品,请先删除书品"); + } + } + return true; + + } + + @Override + public List queryNameList(String phoneNumber) { + Long userId = LoginHelper.getUserId(); + String status = "0"; + return baseMapper.nameList(userId, phoneNumber, status); + } + + @Override + public List querySheNameList(String depotId) { + return baseMapper.querySheNameList(depotId); + } + + @Override + public List queryFreNameList(String sheId) { + return baseMapper.queryFreNameList(sheId); + } + + @Override + public Map getIds(String depotName, String freightName, String shelvesName) { + return baseMapper.getIdsByNames(depotName, freightName, shelvesName); + } + + @Override + public List queryShelvesList(Long id) { + List list = baseMapper.selectSheList(id); + if (list.size() > 0) { + for (int i = 0; i < list.size(); i++) { +// Integer message= baseMapper.selectFreCount(list.get(i).getId()); + if (list.get(i).getInventory() == null) { + list.get(i).setInventory(0L); + } + if (list.get(i).getSheNumber() > 0) { + list.get(i).setHasChildren(true); + } else { + list.get(i).setHasChildren(false); + } + list.get(i).setLevel(2); + } + } + return list; + } + + @Override + public List queryTFreightList(Long id) { + List list = baseMapper.selectFreList(id); + if (list.size() > 0) { + for (int i = 0; i < list.size(); i++) { + if (list.get(i).getInventory() == null) { + list.get(i).setInventory(0L); + } +// //通过货位id查询货架数据 +// List shelvesList = new LambdaQueryChainWrapper<>(shelvesMapper).eq(ObjectUtil.isNotNull(list.get(i).getId()), TShelves::getId, list.get(i).getShelvesId()).list(); +// //通过货架id查询仓库信息 +// if(!shelvesList.isEmpty()){ +// List depotList = new LambdaQueryChainWrapper<>(baseMapper).eq(ObjectUtil.isNotNull(list.get(i)), TDepot::getId, shelvesList.get(0).getDepotId()).list(); +// if(!depotList.isEmpty()){ +// String artNo=depotList.get(0).getCode()+shelvesList.get(0).getCode()+list.get(i).getCode(); +// Long message=baseMapper.selectGoodsCount(artNo,depotList.get(0).getUserId()); +// list.get(i).setSheNumber(message); +// }else{ +// list.get(i).setSheNumber(0L); +// } +// }else{ +// list.get(i).setSheNumber(0L); +// } +// //根据artNo查询商品数量 +// list.get(i).setName(list.get(i).getName()+list.get(i).getUnit()); + list.get(i).setLevel(3); + } + } + return list; + } + + @Override + public List queryListAll() { + List tDepotVos = baseMapper.selectVoList(); + return tDepotVos; + } + + @Override + public List selectDepotIdByUserIdAndCode(Long userId, String code) { + return baseMapper.selectDepotIdByUserIdAndCode(userId, code); + } + + @Override + public List selectArtNoLists(Long userId) { + return baseMapper.selectArtNoLists(userId); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TDistrictServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TDistrictServiceImpl.java new file mode 100644 index 0000000..c6f2488 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TDistrictServiceImpl.java @@ -0,0 +1,235 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +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.zhishu.domain.TDistrict; +import org.dromara.zhishu.domain.bo.TDistrictBo; +import org.dromara.zhishu.domain.vo.DistrictsVo; +import org.dromara.zhishu.domain.vo.TDistrictVo; +import org.dromara.zhishu.enums.MunicipalityEnum; +import org.dromara.zhishu.mapper.TDistrictMapper; +import org.dromara.zhishu.service.ITDistrictService; +import org.springframework.beans.BeanUtils; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +@RequiredArgsConstructor +@Service +public class TDistrictServiceImpl implements ITDistrictService { + + private final TDistrictMapper baseMapper; + + /** + * 查询【请填写功能名称】 + * + * @param id 主键 + * @return 【请填写功能名称】 + */ + @Override + public TDistrictVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询【请填写功能名称】列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 【请填写功能名称】分页列表 + */ + @Override + public TableDataInfo queryPageList(TDistrictBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @Override + public List queryList(TDistrictBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + /** + * 查询符合条件的【请填写功能名称】列表 + * + * @param bo 查询条件 + * @return 【请填写功能名称】列表 + */ + + + private LambdaQueryWrapper buildQueryWrapper(TDistrictBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(TDistrict::getId); + lqw.eq(bo.getPid() != null, TDistrict::getPid, bo.getPid()); + lqw.eq(StringUtils.isNotBlank(bo.getCode()), TDistrict::getCode, bo.getCode()); + lqw.like(StringUtils.isNotBlank(bo.getName()), TDistrict::getName, bo.getName()); + lqw.eq(bo.getStatus() != null, TDistrict::getStatus, bo.getStatus()); + lqw.eq(bo.getLevel() != null, TDistrict::getLevel, bo.getLevel()); + return lqw; + } + + /** + * 新增【请填写功能名称】 + * + * @param bo 【请填写功能名称】 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(TDistrictBo bo) { + TDistrict add = MapstructUtils.convert(bo, TDistrict.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改【请填写功能名称】 + * + * @param bo 【请填写功能名称】 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TDistrictBo bo) { + TDistrict update = MapstructUtils.convert(bo, TDistrict.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TDistrict 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 selectList(){ + return baseMapper.selectDistrictList(); + } + + @Override + public List selectDistrictByPid(String pid){ + return baseMapper.selectDistrictByPid(pid); + } + + @Override + public List selectCityList(TDistrictVo vo) { + return baseMapper.selectCityList(vo); + } + + @Override + public List selectAreaList(TDistrictVo vo) { + return baseMapper.selectAreaList(vo); + } + + /** + * 查询地址数据 + * + * @param vo + * @return + */ + @Override + public List selectDistricts(TDistrictVo vo) { + // 查询所有省级区划 + List districtList = baseMapper.selectDistrictList(); + // 查询所有区级区划 + List cityList = baseMapper.selectCityList(vo); + // 直辖市ID集合 + List municipalityIdList = new ArrayList<>(); + municipalityIdList.add(MunicipalityEnum.BEIJING.getId()); + municipalityIdList.add(MunicipalityEnum.SHANGHAI.getId()); + municipalityIdList.add(MunicipalityEnum.TIANJIN.getId()); + municipalityIdList.add(MunicipalityEnum.CHONGQING.getId()); + // 单独查出直辖市下的区级区划 + List municipalityAreaList = baseMapper.selectMunicipalityAreaList(municipalityIdList); + + // 省级区划响应集合 + List provinceVoList = new ArrayList<>(); + + // 循环将省级区划信息插曲到省级区划响应集合 + for (TDistrictVo tDistrictVo : districtList) { + DistrictsVo provinceDistrictsVo = new DistrictsVo(); + provinceDistrictsVo.setLabel(tDistrictVo.getName()); + provinceDistrictsVo.setValue(tDistrictVo.getName()); + provinceDistrictsVo.setId(tDistrictVo.getCode()); + // + List childrenList = new ArrayList<>(); + // 循环将市级区划信息插曲到市级区划响应集合 + cityList.forEach(city -> { + if (city.getPid().equals(tDistrictVo.getId())) { + DistrictsVo cityDistrictsVo = new DistrictsVo(); + cityDistrictsVo.setLabel(city.getName()); + cityDistrictsVo.setValue(city.getName()); + cityDistrictsVo.setId(city.getCode()); + // 将查出的直辖市下区级区划信息循环插入到市级区划信息中 + if (municipalityIdList.contains(city.getId())) { + List municipalityAreaVoList = new ArrayList<>(); + for (TDistrictVo municipalityArea : municipalityAreaList) { + if (municipalityArea.getPid().equals(city.getId())) { + DistrictsVo municipalityAreaVo = new DistrictsVo(); + municipalityAreaVo.setLabel(municipalityArea.getName()); + municipalityAreaVo.setValue(municipalityArea.getName()); + municipalityAreaVo.setId(municipalityArea.getCode()); + municipalityAreaVoList.add(municipalityAreaVo); + } + } + if (!municipalityAreaVoList.isEmpty()) { + cityDistrictsVo.setChildren(municipalityAreaVoList); + } + } + childrenList.add(cityDistrictsVo); + } + }); + if (!childrenList.isEmpty()) { + provinceDistrictsVo.setChildren(childrenList); + } + provinceVoList.add(provinceDistrictsVo); + } + return provinceVoList; + } + + @Override + public List queryListByName(List districtNames) { + return new LambdaQueryChainWrapper<>(baseMapper) + .eq(TDistrict::getStatus, 0) + .in(TDistrict::getName, districtNames) + .list().stream().map(o -> { + TDistrictVo tDistrictVo = new TDistrictVo(); + BeanUtils.copyProperties(o, tDistrictVo); + return tDistrictVo; + }).toList(); + } + + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TFreightServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TFreightServiceImpl.java new file mode 100644 index 0000000..256e888 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TFreightServiceImpl.java @@ -0,0 +1,382 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import org.apache.ibatis.annotations.Param; +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.TFreight; +import org.dromara.zhishu.domain.bo.TDepotBo; +import org.dromara.zhishu.domain.bo.TFreightBo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TFreightVo; +import org.dromara.zhishu.domain.vo.TShelvesVo; +import org.dromara.zhishu.mapper.TFreightMapper; +import org.dromara.zhishu.mapper.TShelvesMapper; +import org.dromara.zhishu.service.ITDepotService; +import org.dromara.zhishu.service.ITFreightService; +import org.dromara.zhishu.service.ITShelvesService; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.springframework.stereotype.Service; + + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 三级货区管理Service业务层处理 + * + * @author Lion Li + * @date 2025-04-19 + */ +@RequiredArgsConstructor +@Service +public class TFreightServiceImpl implements ITFreightService { + + private final TFreightMapper baseMapper; + + private final TShelvesMapper tShelvesMapper; + + private final ITShelvesService shelvesService; + + private final ITDepotService depotService; + + private final IZhishuShopGoodsService zhishuShopGoodsService; + + + @Override + public List selectDepotTree(){ + Long userId = LoginHelper.getUserId(); + TDepotBo depotBo = new TDepotBo(); + depotBo.setUserId(userId); + List depotTree = new ArrayList<>(); + //获取一级货区 + List depotVoList = depotService.selectList(depotBo); + for (TDepotVo depotVo : depotVoList){ + Map depotMap = new HashMap(); + depotMap.put("value",depotVo.getId()); + depotMap.put("label","货架编号:"+depotVo.getCode()+";货架名称"+depotVo.getName()); + List depotChildren = new ArrayList<>(); + //获取二级货区 + List shelvesVoList = shelvesService.selectShelvesByDepotId(depotVo.getId().toString()); + for (TShelvesVo shelvesVo : shelvesVoList){ + Map shelvesMap = new HashMap(); + shelvesMap.put("value",shelvesVo.getId()); + shelvesMap.put("label","货架编号:"+shelvesVo.getCode()+";货架名称"+shelvesVo.getName()); + + List shelvesChildren = new ArrayList<>(); + //获取三级货区 + List freightVoList = selectByShelvesId(shelvesVo.getId()); + for (TFreightVo freightVo : freightVoList){ + Map freightMap = new HashMap(); + freightMap.put("value",freightVo.getId()); + freightMap.put("label","货架编号:"+freightVo.getCode()+";货架名称"+freightVo.getName()); + shelvesChildren.add(freightMap); + } + shelvesMap.put("children",shelvesChildren); + depotChildren.add(shelvesMap); + } + depotMap.put("children",depotChildren); + depotTree.add(depotMap); + } + return depotTree; + } + + @Override + public List selectByShelvesId(Long shelvesId){ + return baseMapper.selectByShelvesId(shelvesId); + } + + @Override + public Map selectByFreightId(Long freightId){ + return baseMapper.selectByFreightId(freightId); + } + + /** + * 查询三级货区管理 + * + * @param id 主键 + * @return 三级货区管理 + */ + @Override + public TFreightVo queryById(Long id){ + TFreightVo vo=baseMapper.selectVoById(id); + TFreight shelvesVo=baseMapper.selectSheName(id); + vo.setShelvesName(shelvesVo.getName()); + vo.setShelvesCode(shelvesVo.getCode()); + return vo; + } + + /** + * 分页查询三级货区管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 三级货区管理分页列表 + */ + @Override + public TableDataInfo queryPageList(TFreightBo bo, PageQuery pageQuery) { + Long userId = LoginHelper.getUserId(); + List depotids=baseMapper.selectV(userId); + + Page result = new Page<>(); + if(!depotids.isEmpty()){ + List sheIds=baseMapper.selectShe(depotids); + if(!sheIds.isEmpty()){ + result =baseMapper.selectVo(pageQuery.build(), bo,sheIds); + for (int i = 0; i < result.getRecords().size(); i++) { + Long id = result.getRecords().get(i).getId(); + String unit = result.getRecords().get(i).getUnit(); + String name = result.getRecords().get(i).getName(); + result.getRecords().get(i).setName(name+unit); + TShelvesVo vo = baseMapper.setShelvesName1(id); + String depotCode =baseMapper.selectDepotCode(vo.getDepotId()); + result.getRecords().get(i).setComcode(depotCode+vo.getCode()+result.getRecords().get(i).getCode()); + result.getRecords().get(i).setShelvesName(vo.getName()+vo.getUnit()); + } + + } + } + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的三级货区管理列表 + * + * @param bo 查询条件 + * @return 三级货区管理列表 + */ + @Override + public List queryList(TFreightBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Long userId = LoginHelper.getUserId(); + //获取三级货区 + List vo=new ArrayList<>(); + //获取当前用户下的一级货区id + List depotids=baseMapper.selectV(userId); + //判断是否为空 + if(!depotids.isEmpty()){ + //通过一级货区id查询出二级货区id + List sheIds=baseMapper.selectShe(depotids); + //判断二级货区是否为空 + if(!sheIds.isEmpty()) { + //查询出二级货区下的所有三级货区 + vo=baseMapper.selectVoLists(sheIds); + for (int i = 0; i < vo.size(); i++) { + //设置三级货区名称 + vo.get(i).setName(vo.get(i).getName()+vo.get(i).getUnit()); + //查询二级货区名称和单位 + TShelvesVo vo1 = baseMapper.setShelvesName1(vo.get(i).getId()); + //设置二级货区名称 + vo.get(i).setShelvesName(vo1.getName()+vo1.getUnit()); + } + } + } + + + return vo; + } + + private LambdaQueryWrapper buildQueryWrapper(TFreightBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(TFreight::getId); + lqw.eq(bo.getShelvesId() != null, TFreight::getShelvesId, bo.getShelvesId()); + lqw.eq(StringUtils.isNotBlank(bo.getCode()), TFreight::getCode, bo.getCode()); + lqw.like(StringUtils.isNotBlank(bo.getName()), TFreight::getName, bo.getName()); + lqw.eq(bo.getCapMax() != null, TFreight::getCapMax, bo.getCapMax()); + lqw.eq(StringUtils.isNotBlank(bo.getArtNo()), TFreight::getArtNo, bo.getArtNo()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TFreight::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增三级货区管理 + * + * @param bo 三级货区管理 + * @return 是否新增成功 + */ + @Override + public TFreightBo insertByBo(TFreightBo bo) { +// Long userId = LoginHelper.getUserId(); + Long userId = bo.getUserId() != null ? bo.getUserId() : LoginHelper.getUserId(); + TFreight add = MapstructUtils.convert(bo, TFreight.class); + validEntityBeforeSave(add); + add.setTenantId("000000"); + // 获取货架编码 + String sheCode = baseMapper.selectByCode(add.getShelvesId()); + // 获取货架的depotId + Long depotId = tShelvesMapper.selectDepotIdByShelvesId(add.getShelvesId()); + // 获取仓库编码 + String depotCode = null; + if (depotId != null) { + depotCode = baseMapper.selectDepotCode(String.valueOf(depotId)); + } + + // 判断shelvesCode和depotCode相加是否为四位 + if (sheCode != null && depotCode != null && (sheCode + depotCode).length() == 4) { + // 如果是四位,判断用户输入的code是否为两位 + if (add.getCode() != null && add.getCode().length() >= 2) { + throw new RuntimeException("货架编码错误,请输入正确的货架编码"); + } + } + + if(sheCode != null && sheCode.length()==1){ + if(add.getCode().length()==1&& Character.isDigit(add.getCode().charAt(0))) { + add.setCode("0" + add.getCode()); // 补零 + }else if(add.getCode().matches("[a-zA-Z][0-9]")){ + add.setCode(add.getCode().toUpperCase()); + }else{ + add.setCode(add.getCode()); + } + } + + if (StringUtils.isEmpty(add.getName())) { + throw new RuntimeException("请稍后重试"); + } + + Integer message1 = baseMapper.selectFreName(add.getName(), add.getShelvesId(), null); + Integer message2 = baseMapper.selectFreName(null, add.getShelvesId(), add.getCode()); + if(message1!=0 || message2!=0){ + throw new RuntimeException("货区编码或名称已存在"); + } + boolean flag = baseMapper.insertFre(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return bo; + } + + /** + * 修改三级货区管理 + * + * @param bo 三级货区管理 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TFreightBo bo) { + TFreight update = MapstructUtils.convert(bo, TFreight.class); + validEntityBeforeSave(update); + Integer message = baseMapper.selectByExcludeCurrent(bo.getName(), bo.getShelvesId(), bo.getId()); + if (message != 0) { + throw new RuntimeException("货区名称重复"); + } + + /** + * 如果修改了是否开启分销,则将该货架上的商品全部修改 + */ + if(StringUtils.isNotEmpty(bo.getAllowDistribution())){ + TFreightVo vo = queryById(bo.getId()); + if(!bo.getAllowDistribution().equals(vo.getAllowDistribution())){ + Long userId = LoginHelper.getUserId(); + Long limitNum = 1000L; + /** + * 确认 分销 状态 修改 + */ + //获取货号 + TShelvesVo shelvesVo = shelvesService.queryById(vo.getShelvesId()); + TDepotVo depotVo = depotService.queryById(Long.parseLong(shelvesVo.getDepotId())); + //拼接货号前缀 + String artNoPrefix = depotVo.getCode() + shelvesVo.getCode() + vo.getCode(); + //根据货号前缀,将所有这个前缀的商品分销状态修改 + while (true){ + int num = zhishuShopGoodsService.updateByArtNoPrefix(bo.getAllowDistribution(),artNoPrefix,userId,limitNum); + if (num == 0){ + break; + } + } + } + } + return baseMapper.updateBydate(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TFreight entity){ + //TODO 做一些数据校验,如唯一约束 + if (StringUtils.isEmpty(entity.getName())) { + throw new RuntimeException("请稍后重试"); + } + } + + /** + * 校验并批量删除三级货区管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid,Long LocalUserId) { + Long userId = LocalUserId != null ? LocalUserId : LoginHelper.getUserId(); + + List list=baseMapper.selectListVo(ids,userId); + if(!list.isEmpty()){ + for (int i = 0; i < list.size(); i++) { + if(list.get(i).getSheNumber()>0){ + throw new RuntimeException("货区下有书品,请先删除书品"); + }else{ + baseMapper.deleteByIds(ids); // 主表删除 + return true; + } + } + } + +// // 2. 批量查询货架编码(空值保护) +// List codes = baseMapper.selectCode(ids); +// if (CollectionUtils.isEmpty(codes)) { +//// log.warn(" 未查询到有效货架编码: ids={}", ids); +// return false; +// } +// // 4. 批量校验占用状态(优化数据库交互) +// Map occupiedMap = codes.stream() +// .collect(Collectors.toMap( +// code -> code, +// code -> code.length() == 2 ? +// baseMapper.selectByCount2(userId, code) : +// baseMapper.selectByCount1(userId, code) +// )); +// // 5. 统一决策(全部未被占用才允许删除) +// boolean allUnoccupied = occupiedMap.values().stream() +// .allMatch(count -> count == 0); +// if (allUnoccupied) { +// baseMapper.deleteByIds(ids); // 主表删除 +// return true; +// } + return false; + } + + @Override + public List querySheNameList() { + //获取当前用户id + Long userId = LoginHelper.getUserId(); + List depotIdList = baseMapper.selectDepotId(userId); + List list=new ArrayList<>(); + if(!depotIdList.isEmpty()){ + list= baseMapper.selectByList(depotIdList); + for (TShelvesVo vo:list){ + vo.setLevel(3); + } + } + return list; + } + + /** + * 根据三级获取名称获取获取信息 + * @param freightName + * @param shelvesId + * @return + */ + @Override + public TFreightVo selectByFreightName(String freightName, Long shelvesId){ + return baseMapper.selectByFreightName(freightName,shelvesId); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TInviteCodeServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TInviteCodeServiceImpl.java new file mode 100644 index 0000000..c51c31d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TInviteCodeServiceImpl.java @@ -0,0 +1,200 @@ +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.apache.commons.lang3.RandomStringUtils; +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.zhishu.domain.TInviteCode; +import org.dromara.zhishu.domain.TInviteRelation; +import org.dromara.zhishu.domain.bo.InviteCodeBo; +import org.dromara.zhishu.domain.vo.InviteCodeVo; +import org.dromara.zhishu.mapper.TInviteCodeMapper; +import org.dromara.zhishu.mapper.TInviteRelationMapper; +import org.dromara.zhishu.service.ITInviteCodeService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +/** + * 邀请码 Service 实现 + */ +@Service +@RequiredArgsConstructor +public class TInviteCodeServiceImpl implements ITInviteCodeService { + + private final TInviteCodeMapper inviteCodeMapper; + private final TInviteRelationMapper inviteRelationMapper; + + @Value("${invite.url.prefix:https://erp.buzhiyushu.cn/register?code=}") + private String inviteUrlPrefix; + + @Value("${invite.code.expireDays:30}") + private int defaultExpireDays; + + /** + * 查询邀请码 + * + * @param id 邀请码主键 + * @return 邀请码 + */ + @Override + public InviteCodeVo queryById(Long id) { + return MapstructUtils.convert(inviteCodeMapper.selectById(id), InviteCodeVo.class); + } + + /** + * 查询邀请码列表 + * + * @param userId 用户ID + * @return 邀请码列表 + */ + @Override + public List queryListByUserId(Long userId) { + return inviteCodeMapper.selectListByUserId(userId); + } + + /** + * 查询邀请码分页列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 邀请码分页列表 + */ + @Override + public TableDataInfo queryPageList(InviteCodeBo bo, PageQuery pageQuery) { + Page page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()); + page = inviteCodeMapper.selectPageList(page, bo.getUserId(), bo.getCode(), bo.getUsed()); + return TableDataInfo.build(page); + } + + /** + * 生成邀请码 + * + * @param bo 邀请码信息 + * @return 邀请码 + */ + @Override + public int generateInviteCode(InviteCodeBo bo) { + TInviteCode inviteCode = new TInviteCode(); + inviteCode.setUserId(bo.getUserId()); + + // 生成随机邀请码 + String code = generateUniqueCode(); + inviteCode.setCode(code); + + // 生成邀请链接 + inviteCode.setInviteUrl(inviteUrlPrefix + code); + + // 设置为永不过期(使用非常远的未来日期) + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.YEAR, 100); // 100年后过期,实际上相当于永不过期 + inviteCode.setExpireTime(calendar.getTime()); + + // 设置未使用状态 + inviteCode.setUsed(false); + inviteCode.setCreatedAt(new Date()); + // 3. 转换为 VO 对象并返回 + return inviteCodeMapper.insertGenerateInviteCode(inviteCode); + } + + /** + * 验证邀请码 + * + * @param code 邀请码 + * @return 邀请码信息,如果无效则返回null + */ + @Override + public TInviteCode validateInviteCode(String code) { + return inviteCodeMapper.validateInviteCode(code); + } + + /** + * 使用邀请码 + * + * @param code 邀请码 + * @param inviteeId 被邀请人ID + * @return 是否使用成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public boolean useInviteCode(String code, Long inviteeId) { + // 验证邀请码是否有效 + TInviteCode inviteCode = validateInviteCode(code); + if (inviteCode == null) { + return false; + } + + // 检查用户是否已被邀请 + LambdaQueryWrapper checkWrapper = Wrappers.lambdaQuery(); + checkWrapper.eq(TInviteRelation::getInviteeId, inviteeId); + if (inviteRelationMapper.selectCount(checkWrapper) > 0) { + return false; // 用户已经被邀请过 + } + + // 创建邀请关系 + TInviteRelation relation = new TInviteRelation(); + relation.setInviterId(inviteCode.getUserId()); + relation.setInviteeId(inviteeId); + relation.setInviteCode(code); + relation.setInviteTime(new Date()); + inviteRelationMapper.insert(relation); + + return true; + } + + /** + * 构建查询条件 + * + * @param bo 查询条件 + * @return 构建好的查询条件 + */ + private LambdaQueryWrapper buildQueryWrapper(InviteCodeBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getUserId() != null, TInviteCode::getUserId, bo.getUserId()); + lqw.eq(StringUtils.isNotBlank(bo.getCode()), TInviteCode::getCode, bo.getCode()); + lqw.eq(bo.getUsed() != null, TInviteCode::getUsed, bo.getUsed()); + return lqw; + } + + /** + * 生成唯一邀请码 + * + * @return 唯一邀请码 + */ + private String generateUniqueCode() { + String code; + boolean exists; + do { + // 生成8位字母数字混合邀请码 + code = RandomStringUtils.randomAlphanumeric(8); + + // 检查邀请码是否已存在 + LambdaQueryWrapper checkWrapper = Wrappers.lambdaQuery(); + checkWrapper.eq(TInviteCode::getCode, code); + exists = inviteCodeMapper.selectCount(checkWrapper) > 0; + } while (exists); + + return code; + } + + /** + * 获取过期时间 + * + * @param days 过期天数 + * @return 过期时间 + */ + private Date getExpireTime(int days) { + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.DAY_OF_MONTH, days); + return calendar.getTime(); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TInviteRelationsServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TInviteRelationsServiceImpl.java new file mode 100644 index 0000000..dbeb2e2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TInviteRelationsServiceImpl.java @@ -0,0 +1,32 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.domain.TInviteRelations; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.mapper.TInviteRelationsMapper; +import org.dromara.zhishu.service.ITInviteRelationsService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@RequiredArgsConstructor +@Service +public class TInviteRelationsServiceImpl implements ITInviteRelationsService { + + private final TInviteRelationsMapper relationsMapper ; + private final ShopMapper shopMapper ; + + + @Override + public List selectByInviterId(Long inviterId) { + return relationsMapper.selectByInviterId(inviterId); + } + + @Override + public List selectUserShopList(Long userId) { + + return shopMapper.selectByUserId(userId); + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TLogisticsServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TLogisticsServiceImpl.java new file mode 100644 index 0000000..ece4494 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TLogisticsServiceImpl.java @@ -0,0 +1,225 @@ +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.ExcelTask; +import org.dromara.zhishu.domain.Printer; +import org.dromara.zhishu.domain.TLogistics; +import org.dromara.zhishu.domain.bo.TLogisticsBo; +import org.dromara.zhishu.domain.vo.ExcelTaskVo; +import org.dromara.zhishu.domain.vo.TDepotVo; +import org.dromara.zhishu.domain.vo.TLogisticsVo; +import org.dromara.zhishu.mapper.TLogisticsMapper; +import org.dromara.zhishu.service.IFastMailService; +import org.dromara.zhishu.service.ITLogisticsService; +import org.springframework.stereotype.Service; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.stream.Collectors; + +/** + * 物流管理Service业务层处理 + * + * @author Lion Li + * @date 2025-04-22 + */ +@RequiredArgsConstructor +@Service +public class TLogisticsServiceImpl implements ITLogisticsService { + + private final TLogisticsMapper baseMapper; + + /** + * 查询物流管理 + * + * @param id 主键 + * @return 物流管理 + */ + @Override + public TLogisticsVo queryById(Long id){ + TLogisticsVo vo = baseMapper.selectByLId(id); + return vo; + } + + /** + * 分页查询物流管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 物流管理分页列表 + */ + @Override + public TableDataInfo queryPageList(TLogisticsBo bo, PageQuery pageQuery) { + Long userId; + if (bo.getUserId() != null){ + userId = bo.getUserId(); + }else{ + userId = LoginHelper.getUserId(); + } + + bo.setUserId(userId); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + // 物流类型转换 + if(bo.getShipping()!=null){ + if(bo.getShipping().equals("物流")){ + bo.setShipping("1"); + }else if(bo.getShipping().equals("快递")){ + bo.setShipping("0"); + } + } + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的物流管理列表 + * + * @param bo 查询条件 + * @return 物流管理列表 + */ + @Override + public List queryList(TLogisticsBo bo) { + // 获取当前用户id + Long userId; + if (bo.getUserId() != null){ + userId = bo.getUserId(); + }else{ + userId = LoginHelper.getUserId(); + } + // 获取白名单 + if (userId != 1) { + bo.setCreateBy(userId); + } + + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List vo=baseMapper.selectVoList(lqw); + for (int i = 0; i < vo.size(); i++) { + Long depotId = vo.get(i).getWarehouseId(); + if (depotId != null) { + TDepotVo vo1= baseMapper.selectDepotName(depotId); + vo.get(i).setWarehouseName(vo1.getName()+vo1.getUnit()); + } + } + return vo; + } + + private LambdaQueryWrapper buildQueryWrapper(TLogisticsBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(TLogistics::getId); +// 管理员可以查看所有信息 +// if (bo.getUserId() != null && !Long.valueOf(1).equals(bo.getUserId())) { +// lqw.eq(TLogistics::getCreateBy, bo.getUserId()); +// } + lqw.eq(bo.getCreateBy() != null, TLogistics::getCreateBy, bo.getCreateBy()); + lqw.eq(bo.getUserId()!=null, TLogistics::getCreateBy, bo.getUserId()); + lqw.like(StringUtils.isNotBlank(bo.getTemplateName()), TLogistics::getTemplateName, bo.getTemplateName()); + lqw.eq(StringUtils.isNotBlank(bo.getDeliveryProvince()), TLogistics::getDeliveryProvince, bo.getDeliveryProvince()); + lqw.eq(StringUtils.isNotBlank(bo.getDeliveryCity()), TLogistics::getDeliveryCity, bo.getDeliveryCity()); + lqw.eq(StringUtils.isNotBlank(bo.getDeliveryArea()), TLogistics::getDeliveryArea, bo.getDeliveryArea()); + lqw.eq(StringUtils.isNotBlank(bo.getShippingRange()), TLogistics::getShippingRange, bo.getShippingRange()); + lqw.eq(bo.getWarehouseId() != null, TLogistics::getWarehouseId, bo.getWarehouseId()); + return lqw; + } + + /** + * 新增物流管理 + * + * @param bo 物流管理 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(TLogisticsBo bo) { + TLogistics add = MapstructUtils.convert(bo, TLogistics.class); + validEntityBeforeSave(add); + String are = baseMapper.selectByArea(bo.getDeliveryArea(), bo.getDeliveryCity()); + String city = baseMapper.selectByCity(bo.getDeliveryCity(), bo.getDeliveryProvince()); + String province = baseMapper.selectByProvince(bo.getDeliveryProvince()); + add.setDeliveryProvince(province); + add.setDeliveryCity(city); + add.setDeliveryArea(are); + if (city == null) { + add.setDeliveryAddress(province + "/" + are); + } else { + add.setDeliveryAddress(province + "/" + city + "/" + are); + } + add.setStatus("1"); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + } + return flag; + } + + /** + * 修改物流管理 + * + * @param bo 物流管理 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TLogisticsBo bo) { + TLogistics update = MapstructUtils.convert(bo, TLogistics.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TLogistics entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除物流管理信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteIds(ids) > 0; + } + + @Override + public List queryNameList() { + //获取当前用户id + Long userId = LoginHelper.getUserId(); + //通过userid查询所有仓库id +// List depotIds = baseMapper.selectDepotId(userId); + List list = baseMapper.selectUserId(userId); +// List list=new ArrayList<>(); +// if(depotIds.isEmpty()){ +// return list; +// }else{ +// list= baseMapper.nameList(depotIds); +// } + return list; + } + + @Override + public List getList(Long userId){ + return baseMapper.selectUserId(userId); + } + + @Override + public List queryNameListByXcx(Long userId) { + return baseMapper.selectUserId(userId); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopDepotAotuServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopDepotAotuServiceImpl.java new file mode 100644 index 0000000..b59a85a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopDepotAotuServiceImpl.java @@ -0,0 +1,68 @@ +package org.dromara.zhishu.service.impl; + +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 lombok.RequiredArgsConstructor; +import org.dromara.zhishu.mapper.TShopDepotAotuMapper; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.TShopDepotAotuBo; +import org.dromara.zhishu.domain.vo.TShopDepotAotuVo; +import org.dromara.zhishu.service.ITShopDepotAotuService; + +import java.util.ArrayList; +import java.util.List; + +/** + * 店铺自动发布仓库关联Service业务层处理 + * + * @author Lion Li + * @date 2025-09-05 + */ +@RequiredArgsConstructor +@Service +public class TShopDepotAotuServiceImpl implements ITShopDepotAotuService { + + private final TShopDepotAotuMapper baseMapper; + + /** + * 查询店铺自动发布仓库关联 + * + * @param id 主键 + * @return 店铺自动发布仓库关联 + */ + @Override + public TShopDepotAotuVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询店铺自动发布仓库关联列表 + * 联表查询获取店铺名称和仓库名称,支持按名称搜索 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 店铺自动发布仓库关联分页列表 + */ + @Override + public TableDataInfo queryPageList(TShopDepotAotuBo bo, PageQuery pageQuery) { + + System.out.println(bo.getDepotName()); + Page result = baseMapper.selectVoPageByCondition(pageQuery.build(), bo); + return TableDataInfo.build(result); + } + + /** + * 查询所有店铺自动发布仓库关联列表 + * 联表查询获取店铺名称和仓库名称,支持按名称搜索 + * + * @param bo 查询条件 + * @return 店铺自动发布仓库关联列表 + */ + @Override + public List queryList(TShopDepotAotuBo bo) { + System.out.println(bo.getDepotName()); + return baseMapper.selectVoListByCondition(bo); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopGoodsPublishedServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopGoodsPublishedServiceImpl.java new file mode 100644 index 0000000..917d6b0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopGoodsPublishedServiceImpl.java @@ -0,0 +1,279 @@ +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.TShopGoodsPublishedDto; +import org.dromara.zhishu.mapper.TShopGoodsPublishedMapper; +import org.dromara.zhishu.service.TShopGoodsPublishedService; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +/** + * 已发布商品信息Service实现类 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class TShopGoodsPublishedServiceImpl implements TShopGoodsPublishedService { + + private final TShopGoodsPublishedMapper tShopGoodsPublishedMapper; + + // ==================== 表管理 ==================== + + @DS("slave") + @Override + public boolean checkTableExists() { + try { + int count = tShopGoodsPublishedMapper.checkTableExists(); + return count > 0; + } catch (Exception e) { + log.error("检查表是否存在失败", e); + return false; + } + } + + @DS("slave") + @Override + public void createTable() { + try { + tShopGoodsPublishedMapper.createTable(); + log.info("创建表成功"); + } catch (Exception e) { + log.error("创建表失败", e); + throw new RuntimeException("创建表失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public void initTable() { + if (!checkTableExists()) { + createTable(); + log.info("初始化表成功"); + } else { + log.info("表已存在"); + } + } + + // ==================== 插入操作 ==================== + + @DS("slave") + @Override + public int insert(TShopGoodsPublishedDto dto) { + if (dto == null) { + throw new IllegalArgumentException("已发布商品信息不能为空"); + } + try { + return tShopGoodsPublishedMapper.insert(dto); + } catch (Exception e) { + log.error("插入已发布商品失败", e); + throw new RuntimeException("插入已发布商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int batchInsert(List list) { + if (CollectionUtils.isEmpty(list)) { + log.warn("批量插入已发布商品列表为空"); + return 0; + } + try { + return tShopGoodsPublishedMapper.batchInsert(list); + } catch (Exception e) { + log.error("批量插入已发布商品失败, size: {}", list.size(), e); + throw new RuntimeException("批量插入已发布商品失败: " + e.getMessage(), e); + } + } + + // ==================== 删除操作 ==================== + + @DS("slave") + @Override + public int deleteById(Long id) { + if (id == null) { + throw new IllegalArgumentException("ID不能为空"); + } + try { + return tShopGoodsPublishedMapper.deleteById(id); + } catch (Exception e) { + log.error("根据ID删除已发布商品失败, id: {}", id, e); + throw new RuntimeException("删除已发布商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int deleteByCondition(Long erpShopId, Long shopId, Long productId, Long warehouseId) { + try { + return tShopGoodsPublishedMapper.deleteByCondition(erpShopId, shopId, productId, warehouseId); + } catch (Exception e) { + log.error("根据条件删除已发布商品失败", e); + throw new RuntimeException("删除已发布商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int batchDeleteByIds(List ids) { + if (CollectionUtils.isEmpty(ids)) { + log.warn("批量删除已发布商品ID列表为空"); + return 0; + } + try { + return tShopGoodsPublishedMapper.batchDeleteByIds(ids); + } catch (Exception e) { + log.error("批量删除已发布商品失败, ids: {}", ids, e); + throw new RuntimeException("批量删除已发布商品失败: " + e.getMessage(), e); + } + } + + @DS("slave") + @Override + public int deleteAll() { + try { + return tShopGoodsPublishedMapper.deleteAll(); + } catch (Exception e) { + log.error("删除所有已发布商品失败", e); + throw new RuntimeException("删除所有已发布商品失败: " + e.getMessage(), e); + } + } + + // ==================== 更新操作 ==================== + + @DS("slave") + @Override + public int updateById(TShopGoodsPublishedDto dto) { + if (dto == null) { + throw new IllegalArgumentException("已发布商品信息不能为空"); + } + if (dto.getId() == null) { + throw new IllegalArgumentException("ID不能为空"); + } + try { + return tShopGoodsPublishedMapper.updateById(dto); + } catch (Exception e) { + log.error("根据ID更新已发布商品失败, id: {}", dto.getId(), e); + throw new RuntimeException("更新已发布商品失败: " + e.getMessage(), e); + } + } + + // ==================== 查询操作 ==================== + + @DS("slave") + @Override + public TShopGoodsPublishedDto selectById(Long id) { + if (id == null) { + return null; + } + try { + return tShopGoodsPublishedMapper.selectById(id); + } catch (Exception e) { + log.error("根据ID查询已发布商品失败, id: {}", id, e); + return null; + } + } + + @DS("slave") + @Override + public List selectByErpShopId(Long erpShopId) { + if (erpShopId == null) { + return List.of(); + } + try { + return tShopGoodsPublishedMapper.selectByErpShopId(erpShopId); + } catch (Exception e) { + log.error("根据ERP店铺ID查询已发布商品失败, erpShopId: {}", erpShopId, e); + return List.of(); + } + } + + @DS("slave") + @Override + public List selectByShopId(Long shopId) { + if (shopId == null) { + return List.of(); + } + try { + return tShopGoodsPublishedMapper.selectByShopId(shopId); + } catch (Exception e) { + log.error("根据平台店铺ID查询已发布商品失败, shopId: {}", shopId, e); + return List.of(); + } + } + + @DS("slave") + @Override + public TShopGoodsPublishedDto selectByProductId(Long productId) { + if (productId == null) { + return null; + } + try { + return tShopGoodsPublishedMapper.selectByProductId(productId); + } catch (Exception e) { + log.error("根据商品ID查询已发布商品失败, productId: {}", productId, e); + return null; + } + } + + @DS("slave") + @Override + public List selectByCondition(TShopGoodsPublishedDto dto) { + try { + return tShopGoodsPublishedMapper.selectByCondition(dto); + } catch (Exception e) { + log.error("分页条件查询已发布商品失败", e); + return List.of(); + } + } + + @DS("slave") + @Override + public int selectCountByCondition(TShopGoodsPublishedDto dto) { + try { + return tShopGoodsPublishedMapper.selectCountByCondition(dto); + } catch (Exception e) { + log.error("条件查询已发布商品总数失败", e); + return 0; + } + } + + @DS("slave") + @Override + public List selectAll() { + try { + return tShopGoodsPublishedMapper.selectAll(); + } catch (Exception e) { + log.error("查询所有已发布商品失败", e); + return List.of(); + } + } + + @DS("slave") + @Override + public int countAll() { + try { + return tShopGoodsPublishedMapper.countAll(); + } catch (Exception e) { + log.error("统计总记录数失败", e); + return 0; + } + } + + @DS("slave") + @Override + public TShopGoodsPublishedDto selectByErpShopIdAndProductId(Long erpShopId, Long productId) { + if (erpShopId == null || productId == null) { + return null; + } + try { + return tShopGoodsPublishedMapper.selectByErpShopIdAndProductId(erpShopId, productId); + } catch (Exception e) { + log.error("根据ERP店铺ID和商品ID查询失败, erpShopId: {}, productId: {}", erpShopId, productId, e); + return null; + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopMessageSubscribeServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopMessageSubscribeServiceImpl.java new file mode 100644 index 0000000..c1def00 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopMessageSubscribeServiceImpl.java @@ -0,0 +1,57 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +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.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.dromara.zhishu.domain.TShopMessageSubscribe; +import org.dromara.zhishu.domain.vo.MessageSubscribeVo; +import org.dromara.zhishu.mapper.TShopMessageSubscribeMapper; +import org.dromara.zhishu.service.TShopMessageSubscribeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +public class TShopMessageSubscribeServiceImpl implements TShopMessageSubscribeService { + + @Autowired + private TShopMessageSubscribeMapper tShopMessageSubscribeMapper; + + @Override + public void insertOrUpdate(List messageSubscribeVo, Long id) { + // 查询库中是否存在该店铺的消息订阅记录 + List tShopMessageSubscribeList = new LambdaQueryChainWrapper<>(tShopMessageSubscribeMapper) + .eq(TShopMessageSubscribe::getDelFlag, "0") + .eq(TShopMessageSubscribe::getShopId, id) + .list(); + ObjectMapper mapper = new ObjectMapper(); + try { + if (ObjectUtil.isEmpty(tShopMessageSubscribeList)) { + // 没有则插入 + TShopMessageSubscribe tShopMessageSubscribe = new TShopMessageSubscribe(); + tShopMessageSubscribe.setShopId(id); + + // tShopMessageSubscribe.setSubscribeDetail(JSONObject.toJSONString(messageSubscribeVo)); + tShopMessageSubscribe.setSubscribeDetail(mapper.writeValueAsString(messageSubscribeVo)); + tShopMessageSubscribeMapper.insert(tShopMessageSubscribe); + } else { + // 有则更新 + new LambdaUpdateChainWrapper<>(tShopMessageSubscribeMapper) + .eq(TShopMessageSubscribe::getDelFlag, "0") + .eq(TShopMessageSubscribe::getShopId, id) + // .set(TShopMessageSubscribe::getSubscribeDetail, JSONObject.toJSONString(messageSubscribeVo)) + .set(TShopMessageSubscribe::getSubscribeDetail, mapper.writeValueAsString(messageSubscribeVo)) + .update(); + } + } catch (JsonProcessingException e) { + log.info("json转换异常"); + throw new RuntimeException(e); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopOrderDetailServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopOrderDetailServiceImpl.java new file mode 100644 index 0000000..a40db60 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TShopOrderDetailServiceImpl.java @@ -0,0 +1,211 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.google.gson.*; +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.zhishu.enums.PddOrderDetailEnum; +import org.dromara.zhishu.enums.PddOrderEnum; +import org.dromara.zhishu.util.JsonObjUtil; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.TShopOrderDetailBo; +import org.dromara.zhishu.domain.vo.TShopOrderDetailVo; +import org.dromara.zhishu.domain.TShopOrderDetail; +import org.dromara.zhishu.mapper.TShopOrderDetailMapper; +import org.dromara.zhishu.service.ITShopOrderDetailService; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 订单详情Service业务层处理 + * + * @author Lion Li + * @date 2025-03-13 + */ +@RequiredArgsConstructor +@Service +public class TShopOrderDetailServiceImpl implements ITShopOrderDetailService { + + private final TShopOrderDetailMapper baseMapper; + + /** + * 查询订单详情 + * + * @param id 主键 + * @return 订单详情 + */ + @Override + public TShopOrderDetailVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询订单详情列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 订单详情分页列表 + */ + @Override + public TableDataInfo queryPageList(TShopOrderDetailBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + lqw.orderByDesc(TShopOrderDetail::getCreateTime); + lqw.orderByDesc(TShopOrderDetail::getId); +// Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + Page result = baseMapper.customPageList(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的订单详情列表 + * + * @param bo 查询条件 + * @return 订单详情列表 + */ + @Override + public List queryList(TShopOrderDetailBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TShopOrderDetailBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(TShopOrderDetail::getId); + lqw.eq(StringUtils.isNotBlank(bo.getShopId()), TShopOrderDetail::getShopId, bo.getShopId()); + lqw.like(StringUtils.isNotBlank(bo.getShopName()), TShopOrderDetail::getShopName, bo.getShopName()); + lqw.eq(bo.getGoodsCount() != null, TShopOrderDetail::getOrderId, bo.getOrderId()); + lqw.eq(bo.getGoodsCount() != null, TShopOrderDetail::getGoodsCount, bo.getGoodsCount()); + lqw.eq(StringUtils.isNotBlank(bo.getGoodsId()), TShopOrderDetail::getGoodsId, bo.getGoodsId()); + lqw.eq(StringUtils.isNotBlank(bo.getGoodsImg()), TShopOrderDetail::getGoodsImg, bo.getGoodsImg()); + lqw.like(StringUtils.isNotBlank(bo.getGoodsName()), TShopOrderDetail::getGoodsName, bo.getGoodsName()); + lqw.eq(StringUtils.isNotBlank(bo.getGoodsPrice()), TShopOrderDetail::getGoodsPrice, bo.getGoodsPrice()); + lqw.eq(StringUtils.isNotBlank(bo.getGoodsSpec()), TShopOrderDetail::getGoodsSpec, bo.getGoodsSpec()); + lqw.eq(StringUtils.isNotBlank(bo.getOuterGoodsId()), TShopOrderDetail::getOuterGoodsId, bo.getOuterGoodsId()); + lqw.eq(StringUtils.isNotBlank(bo.getOuterId()), TShopOrderDetail::getOuterId, bo.getOuterId()); + lqw.eq(StringUtils.isNotBlank(bo.getSkuId()), TShopOrderDetail::getSkuId, bo.getSkuId()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), TShopOrderDetail::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增订单详情 + * + * @param bo 订单详情 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(TShopOrderDetailBo bo) { + TShopOrderDetail add = MapstructUtils.convert(bo, TShopOrderDetail.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改订单详情 + * + * @param bo 订单详情 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TShopOrderDetailBo bo) { + TShopOrderDetail update = MapstructUtils.convert(bo, TShopOrderDetail.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(TShopOrderDetail entity) { + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除订单详情信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + + /** + * 校验并批量删除订单详情信息 + * + + * @return 是否删除成功 + */ + @Override + public void insertBatchOrderDetail(String itemList, String orderSn, Long orderId) { + + Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create(); + JsonArray jsonArray = gson.fromJson(itemList, JsonArray.class); + + QueryWrapper queryWrapper =new QueryWrapper<>(); + queryWrapper.lambda().eq(TShopOrderDetail::getOrderSn,orderSn); + baseMapper.delete(queryWrapper); + + + for (Object o : jsonArray) { + + JsonObject orderObject = gson.fromJson(o.toString(), JsonObject.class); + + TShopOrderDetail detail = new TShopOrderDetail(); + detail.setOrderId(orderId); + detail.setOrderSn(orderSn); + + Long goodsCount = JsonObjUtil.getLong(orderObject, PddOrderDetailEnum.GOODS_COUNT.getCode()); + Integer count = goodsCount.intValue(); + detail.setGoodsCount(count); + + String goodsImg = JsonObjUtil.getString(orderObject, PddOrderDetailEnum.GOODS_IMG.getCode()); + detail.setGoodsImg(goodsImg); + String goodsName = JsonObjUtil.getString(orderObject, PddOrderDetailEnum.GOODS_NAME.getCode()); + detail.setGoodsName(goodsName); + BigDecimal goodsPrice = JsonObjUtil.getDecimal(orderObject, PddOrderDetailEnum.GOODS_PRICE.getCode()); + detail.setGoodsPrice(goodsPrice); + String goodsSpec = JsonObjUtil.getString(orderObject, PddOrderDetailEnum.GOODS_SPEC.getCode()); + detail.setGoodsSpec(goodsSpec); + String outerGoodsId = JsonObjUtil.getString(orderObject, PddOrderDetailEnum.OUTER_GOODS_ID.getCode()); + detail.setOuterGoodsId(outerGoodsId); + String outerId = JsonObjUtil.getString(orderObject, PddOrderDetailEnum.OUTER_ID.getCode()); + detail.setOuterId(outerId); + String skuId = JsonObjUtil.getString(orderObject, PddOrderDetailEnum.SKU_ID.getCode()); + detail.setSkuId(skuId); + + String goodsId = JsonObjUtil.getString(orderObject, PddOrderDetailEnum.GOODS_ID.getCode()); + detail.setGoodsId(goodsId); + + + baseMapper.insert(detail); + + + } + + + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TUserPlatformServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TUserPlatformServiceImpl.java new file mode 100644 index 0000000..77627f7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TUserPlatformServiceImpl.java @@ -0,0 +1,21 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.dromara.zhishu.domain.TUserPlatform; +import org.dromara.zhishu.mapper.TShopOrderMapper; +import org.dromara.zhishu.mapper.TUserPlatformMapper; +import org.dromara.zhishu.service.ITUserPlatformService; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +@Log4j2 +public class TUserPlatformServiceImpl implements ITUserPlatformService { + + private final TUserPlatformMapper baseMapper; + + public void insertTUserPlatform(TUserPlatform userPlatform){ + baseMapper.insertTUserPlatform(userPlatform); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TaskServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TaskServiceImpl.java new file mode 100644 index 0000000..96aef7f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/TaskServiceImpl.java @@ -0,0 +1,1175 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.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.PddGoodsSkuPriceUpdateRequest; +import com.pdd.pop.sdk.http.api.pop.response.PddGoodsSkuPriceUpdateResponse; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.pqc.math.linearalgebra.BigEndianConversions; +import org.dromara.common.core.domain.R; +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.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.system.domain.SysOss; +import org.dromara.system.service.ISysConfigService; +import org.dromara.zhishu.domain.*; +import org.dromara.zhishu.domain.bo.*; +import org.dromara.zhishu.domain.dto.BookPriceInfoDto; +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.dromara.zhishu.domain.dto.request.GoodsSaleStatusSetRequest; +import org.dromara.zhishu.domain.dto.request.SoldOutRequest; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.enums.TaskStatusTypeEnum; +import org.dromara.zhishu.enums.TaskTypeEnum; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.service.client.PddClient; +import org.dromara.zhishu.util.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.mapper.TaskMapper; +import org.springframework.web.multipart.MultipartFile; +import software.amazon.awssdk.transfer.s3.model.Upload; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 任务列表Service业务层处理 + * + * @author yxy + * @date 2025-03-21 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class TaskServiceImpl implements ITaskService { + + private final TaskMapper baseMapper; + private final IRunningTaskService runningTaskService; + private final IRunningTaskByShopService runningTaskByShopService; + private final IShopService shopService; + private final IShopDetailService shopDetailService; + private final PddClient pddClient; + private final IPriceTemplateService priceTemplateService; + private final ITaskPauseService taskPauseService; + + @Lazy + @Autowired + private PddServiceImpl pddService; + + + + + /** + * 锁对象 + */ + private final Map lockMap = new HashMap<>(); + private final Map runMap = new HashMap<>(); + @Autowired + private TaskMapper taskMapper; + + /** + * 查询任务列表 + * + * @param id 主键 + * @return 任务列表 + */ + @Override + public TaskVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + @Override + public TaskVo selectByFileName(String fileName) { + return baseMapper.selectByFileName(fileName); + } + + @Override + public List selectRunningTask(Integer pageSize,Integer pageNum){ + return baseMapper.selectRunningTask( pageSize, pageNum); + } + + @Override + public int selectRunningTaskCount(){ + return baseMapper.selectRunningTaskCount(); + } + + /** + * 分页查询任务列表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 任务列表分页列表 + */ + @Override + public TableDataInfo queryPageList(TaskBo bo, PageQuery pageQuery) { + // 当前用户id + Long userId = LoginHelper.getUserId(); + if(userId != 1){ + bo.setCreateBy(userId); + } + // 通过用户id找到店铺id + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + + for (TaskVo record : result.getRecords()) { + if (TaskTypeEnum.SYNC_GOODS_KFZ.getCode().equals(record.getTaskType())||TaskTypeEnum.SYNC_GOODS_WLN.getCode().equals(record.getTaskType())) { + if (TaskStatusTypeEnum.EXECUTED.getCode().equals(record.getTaskStatus())) { + record.setHasSyncFile(false); + } else { + // 判断redis中是否存在未完成的任务 + String lockKey = "ReadExcelKey_" + record.getShopIds(); + String writeExcelLock = RedisUtils.getCacheObject(lockKey); + if (ObjectUtil.isNotEmpty(writeExcelLock)) { + log.info("============正在读取文件:{}=============", writeExcelLock); + record.setHasSyncFile(false); + } else { + // 指定读取需要新增的商品Excel文件路径 + String newGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "New_" + record.getShopIds() + "_0.xlsx").toString(); + log.info("============新增文件:{}=============", newGoodsExcelPath); + // 指定读取需要修改的商品Excel文件路径 + String updateGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "Changed_" + record.getShopIds() + "_0.xlsx").toString(); + log.info("============变更文件:{}=============", updateGoodsExcelPath); + // 若获取存在说明存在读取该文件的线程,则直接返回,不进行后续操作 + record.setHasSyncFile(FileUtil.isFileExists(newGoodsExcelPath) || FileUtil.isFileExists(updateGoodsExcelPath)); + } + } + } + + } + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的任务列表列表 + * + * @param bo 查询条件 + * @return 任务列表列表 + */ + @Override + public List queryList(TaskBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TaskBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByDesc(Task::getCreateTime); + lqw.eq(StringUtils.isNotBlank(bo.getTaskType()), Task::getTaskType, bo.getTaskType()); + lqw.eq(StringUtils.isNotBlank(bo.getShopIds()), Task::getShopIds, bo.getShopIds()); + + lqw.like(StringUtils.isNotBlank(bo.getShopNames()), Task::getShopNames, bo.getShopNames()); + lqw.like(StringUtils.isNotBlank(bo.getFileName()), Task::getFileName, bo.getFileName()); + lqw.eq(bo.getDataNum() != null, Task::getDataNum, bo.getDataNum()); + lqw.eq(bo.getId() != null, Task::getId, bo.getId()); + lqw.eq(StringUtils.isNotBlank(bo.getTaskStatus()), Task::getTaskStatus, bo.getTaskStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Task::getStatus, bo.getStatus()); + lqw.eq(ObjectUtil.isNotNull(bo.getCreateBy()), Task::getCreateBy, bo.getCreateBy()); + return lqw; + } + + /** + * 新增任务列表 + * + * @param bo 任务列表 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(TaskBo bo) { + Task add = MapstructUtils.convert(bo, Task.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + +// @Override +// public void addGoods(Map map, TaskBo taskBo, Long userId) { +// // 图书列表 +// Map data = (Map) map.get("data"); +// Map addMap = new HashMap(); +// addMap.put("shopIds",map.get("shopIds").toString()); +// addMap.put("taskId",taskBo.getId().toString()); +// addMap.put("taskName",taskBo.getFileName()); +// addMap.put("url", data.get("url").toString()); +// addMap.put("imageSelect",map.get("imageSelect").toString()); +// addMap.put("way",map.get("way").toString()); +// //调用接口 +// InterfaceUtils.postForm("http://localhost:16001","/huidiao/pdd/addGoods", addMap); +// } + + + @Override + public void addGoods(Map map, TaskBo taskBo, Long userId) { + String way = taskBo.getWay(); + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + // 图书列表 + Map data = (Map) map.get("data"); + List rawList = null; + try { + rawList = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),SuccessDataItemDto.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + // 获取原始数据并过滤掉所有字段都为空的无效行 + List list = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + + try { + DecryptUtils.decryptDtoList(list); + System.out.println("数据解密成功"); + } catch (Exception e) { + System.err.println("数据解密失败: " + e.getMessage()); + throw new RuntimeException("解密失败", e); + } + + for(String shopId : shopIdsArr){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + // 剩余额度 + Long usageCount = shopService.checkUsageCount(shopVo); + ShopDetailVo shopDetails =shopDetailService.queryByShopId(Long.parseLong(shopId)); + String createResStr = map.get("createResStr").toString(); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + String taskId = createResMap.get("data").toString(); + Map setTaskBodyMap = new HashMap(); + setTaskBodyMap.put("task_id",taskId); + List> bodyList = new ArrayList<>(); + int runNum = 0; + for (SuccessDataItemDto bookVo : list) { + runNum++; + if (shopDetails.getOpenRepeat().equals("1")){ + // 多店过滤 + List ShopVoList = shopService.selectMallIdsById(Long.parseLong(shopId)); + String ids = ShopVoList.stream() + .map(ShopVo::getId) // 提取 id,假设返回类型为 Long 或 String + .map(String::valueOf) // 转换为字符串 + .collect(Collectors.joining(",")); + // 构建请求参数 + Map formData = new HashMap(); + // 注意:接口需要的格式是数组字符串 "[id1,id2,id3]" + String shopIdsArray = "[" + ids + "]"; + formData.put("shopIds", shopIdsArray); + formData.put("isbn", bookVo.getIsbn()); + String res = InterfaceUtils.postForm("http://36.212.20.113:8182","/api/goods/goofish/multipleStores",formData); + Map resMap = JsonUtil.transferToObj(res,Map.class); + Boolean bool = (Boolean) resMap.get("success"); + if (!bool){ + continue; + } + }else if (way.equals("0")){ + Map formData = new HashMap(); + formData.put("shopid",shopId); + formData.put("isbn",bookVo.getIsbn()); + String res = InterfaceUtils.postForm("http://36.212.20.113:8182","/api/goods/simple",formData); + Map resMap = JsonUtil.transferToObj(res,Map.class); + Boolean bool = (Boolean) resMap.get("success"); + if (!bool){ + continue; + } + } + Map body = new HashMap(); + Map bookInfo = new HashMap(); + bookInfo.put("isbn",bookVo.getIsbn()); + bookInfo.put("book_name",bookVo.getTitle()); + if(StringUtils.isNotEmpty(bookVo.getImageBigUrl())){ + JSONObject imageObject = new JSONObject(); + List carouselUrlArray = new ArrayList<>(); + String[] images = bookVo.getImageBigUrl().split(","); + for (String image : images){ + carouselUrlArray.add(image); + } + imageObject.put("carousel_url_array",carouselUrlArray); + bookInfo.put("image_object",imageObject); + } + body.put("book_info",bookInfo); + Map detail = new HashMap(); + BigDecimal totalPrice = new BigDecimal(bookVo.getTotalPrice()); + detail.put("price",totalPrice.longValue()); + detail.put("stock",bookVo.getStock() == null || StringUtils.isEmpty(bookVo.getStock()) ? shopDetails.getStockDeff() : Long.parseLong(bookVo.getStock())); + // 商品编码 + detail.put("out_goods_id",bookVo.getGoodsCode() == null ? "" : bookVo.getGoodsCode()); + // 规格编码 + detail.put("sku_code",bookVo.getSkuCode() == null ? "" : bookVo.getSkuCode()); + // 上下架状态 + String isOnSale = bookVo.getIsOnSale() == null ? "0" : bookVo.getIsOnSale().equals("0") ? "1" : "0"; + detail.put("is_onsale",Long.parseLong(isOnSale)); + body.put("detail",detail); + bodyList.add(body); + if (bodyList.size() % 1000 == 0 || runNum == list.size()){ + String response = InterfaceUtils.postTaskBodyWithSign(UrlUtil.getNewTaskUrl(), "/task/setTaskBody", taskId, bodyList); + System.out.println("新发布任务发布"+bodyList.size()+"条"); + // 清空列表,准备下一批 + bodyList.clear(); + } + + usageCount--; + if (usageCount == 0){ + break; + } + } + // 处理剩余数据 + if (!bodyList.isEmpty()) { + String response = InterfaceUtils.postTaskBodyWithSign(UrlUtil.getNewTaskUrl(), "/task/setTaskBody", taskId, bodyList); + System.out.println("新发布任务发布结束:"+bodyList.size()+"条"); + } + // 更新使用次数 + shopService.updateUsageCount(shopVo,usageCount); + } + } + + + @Override + public void addGoodsCenter(Map map, TaskBo taskBo, Long userId) { + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + // 图书列表 + List list = (List) map.get("data"); + for(String shopId : shopIdsArr){ + ShopDetailVo shopDetails =shopDetailService.queryByShopId(Long.parseLong(shopId)); + //获取价格模板 + PriceTemplateVo priceTemplateVo = priceTemplateService.queryById(shopDetails.getSaleTemplateId()); + BigDecimal lowPrice = new BigDecimal(priceTemplateVo.getLowPrice()).divide(new BigDecimal(100)); + BigDecimal highPrice = new BigDecimal(priceTemplateVo.getHighPrice()).divide(new BigDecimal(100)); + for (Map bookVo : list) { + BigDecimal totalPrice = new BigDecimal(bookVo.get("price").toString()); + Map goMap = new HashMap(); + goMap.put("priority","4"); + goMap.put("retry_count","3"); + goMap.put("isbn", bookVo.get("bookNum") == null ? "" : bookVo.get("bookNum").toString()); + goMap.put("totalPrice", bookVo.get("price") == null ? "" : bookVo.get("price").toString()); + goMap.put("stock", bookVo.get("stock") == null ? "" : bookVo.get("stock").toString()); + goMap.put("bookName", bookVo.get("bookName") == null ? "" : bookVo.get("bookName").toString()); + goMap.put("code", bookVo.get("code") == null ? "" : bookVo.get("code").toString()); + goMap.put("imgBigUrl", bookVo.get("bookImgUrl") == null ? "" : bookVo.get("bookImgUrl").toString()); + goMap.put("artNo", bookVo.get("artNo") == null ? "" : bookVo.get("artNo").toString()); + goMap.put("taskId", taskBo.getId().toString()); + goMap.put("shopId",shopId); + goMap.put("imageSelect", map.get("imageSelect")); //1是官图 2是实拍图 + goMap.put("way",map.get("way")); + /** + * 创建运行任务对象 + */ + 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.setData(JsonUtil.transferToJson(goMap)); + + if(totalPrice.compareTo(highPrice) > 0 || totalPrice.compareTo(lowPrice) < 0){ + runningTask.setStatus("3"); + runningTask.setCallBackData("商品价格不在设置的价格区间"); + }else{ + runningTask.setStatus("0"); + } + runningTask.setTaskType("1"); + runningTaskService.insert(runningTask); + } + } + } + + /** + * 表格更新任务 + */ + @Override + public void editGoodsPrice(Map map, TaskBo taskBo, Long userId) { + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + // 图书列表 + Map data = (Map) map.get("data"); + List rawList = null; + try { + rawList = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),SuccessDataItemDto.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + // 获取原始数据并过滤掉所有字段都为空的无效行 + List list = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + + //根据isbn查询商品信息 + for(String shopId : shopIdsArr){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + Long usageCount = shopService.checkUsageCount(shopVo); + ShopDetailVo shopDetailVo = shopDetailService.queryByShopId(Long.parseLong(shopId)); + PriceTemplateVo priceTemplateVo = priceTemplateService.queryById(shopDetailVo.getSaleTemplateId()); + + String createResStr = map.get("createResStr").toString(); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + String taskId = createResMap.get("data").toString(); + Map setTaskBodyMap = new HashMap(); + setTaskBodyMap.put("task_id",taskId); + List> bodyList = new ArrayList<>(); + int runNum = 0; + for (SuccessDataItemDto bookVo : list) { + + //调用任务池方法,如果正常则继续,如果不正常则休息5秒 + BigDecimal priceL = null; + BigDecimal priceOld = new BigDecimal(bookVo.getTotalPrice()).divide(new BigDecimal(100)); + BigDecimal highPrice = new BigDecimal(priceTemplateVo.getHighPrice()).divide(new BigDecimal(100));; + BigDecimal lowPrice = new BigDecimal(priceTemplateVo.getLowPrice()).divide(new BigDecimal(100)); + + if(priceOld.compareTo(highPrice) > 0 || priceOld.compareTo(lowPrice) < 0){ + //商品价格不在店铺设置的价格区间 + continue; + }else{ + priceL = priceOld; + } + //加价百分比 + BigDecimal proportion = new BigDecimal(0); + //加价价格 + BigDecimal addAmount = new BigDecimal(0); + //获取价格区间 + List priceListMap = JsonUtil.transferToObj(priceTemplateVo.getRangePrice(),List.class); + for (int i=0;i= 0 && priceOld.compareTo(maxPrice) <= 0){ + /** + * 当商品在这个价格区间内时,获取加价百分比喝加价价格 + */ + proportion = new BigDecimal(priceMap.get("adjustPercent").toString()).divide(new BigDecimal(100)); + addAmount = new BigDecimal(priceMap.get("adjustAmount").toString()).divide(new BigDecimal(100)); + break; + } + /** + * 如果执行到这里,则代表没有匹配的价格模板,则使用第一条 + */ + if(i == priceListMap.size() - 1){ + //如果最后一条执行完毕还是没有匹配到,则使用第一条 + priceMap = priceListMap.get(0); + proportion = new BigDecimal(priceMap.get("adjustPercent").toString()).divide(new BigDecimal(100)); + addAmount = new BigDecimal(priceMap.get("adjustAmount").toString()).divide(new BigDecimal(100)); + } + } + //拼单价格 + BigDecimal pricePd = proportion + .multiply(priceL) + .add(priceL) + .add(addAmount) + .multiply(new BigDecimal(100)) + .setScale(0, RoundingMode.DOWN); + + runNum++; + Map body = new HashMap(); + Map bookInfo = new HashMap(); + bookInfo.put("isbn",bookVo.getIsbn()); + bookInfo.put("trilateralId",bookVo.getTrilateralId()); + bookInfo.put("goodsCode",bookVo.getGoodsCode()); + body.put("book_info",bookInfo); + Map detail = new HashMap(); + // 1 上架 2 下架 3 删除 4 修改库存 5 修改价格 + detail.put("status",5); + detail.put("price",pricePd.longValue()); + body.put("detail",detail); + bodyList.add(body); + + if (bodyList.size() % 500 == 0 || runNum == list.size()){ + NewTaskUtils.newTaskPost(taskId,shopVo.getId().toString(),bodyList); + // 清空列表,准备下一批 + bodyList.clear(); + } + + usageCount--; + if (usageCount == 0){ + break; + } + } + // 处理剩余数据 + if (!bodyList.isEmpty()) { + NewTaskUtils.newTaskPost(taskId,shopVo.getId().toString(),bodyList); + } + + + // 更新使用次数 + shopService.updateUsageCount(shopVo,usageCount); + } + } + + @Override + public void editGoodsStock(Map map, TaskBo taskBo, Long userId) { + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + // 图书列表 + Map data = (Map) map.get("data"); + List rawList = null; + try { + rawList = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(), SuccessDataItemDto.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + // 获取原始数据并过滤掉所有字段都为空的无效行 + List list = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + + for(String shopId : shopIdsArr) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + Long usageCount = shopService.checkUsageCount(shopVo); + String createResStr = map.get("createResStr").toString(); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + String taskId = createResMap.get("data").toString(); + Map setTaskBodyMap = new HashMap(); + setTaskBodyMap.put("task_id",taskId); + List> bodyList = new ArrayList<>(); + int runNum = 0; + for (SuccessDataItemDto bookVo : list) { + runNum++; + Map body = new HashMap(); + Map bookInfo = new HashMap(); + bookInfo.put("isbn",bookVo.getIsbn()); + bookInfo.put("trilateralId",bookVo.getTrilateralId()); + bookInfo.put("goodsCode",bookVo.getGoodsCode()); + body.put("book_info",bookInfo); + Map detail = new HashMap(); + // 1 上架 2 下架 3 删除 4 修改库存 5 修改价格 + detail.put("status",4); + detail.put("stock",Long.parseLong(bookVo.getStock())); + body.put("detail",detail); + bodyList.add(body); + + if (bodyList.size() % 500 == 0 || runNum == list.size()){ + NewTaskUtils.newTaskPost(taskId,shopVo.getId().toString(),bodyList); + // 清空列表,准备下一批 + bodyList.clear(); + } + + usageCount--; + if (usageCount == 0){ + break; + } + } + // 处理剩余数据 + if (!bodyList.isEmpty()) { + NewTaskUtils.newTaskPost(taskId,shopVo.getId().toString(),bodyList); + } + // 更新使用次数 + shopService.updateUsageCount(shopVo,usageCount); + } + } + + +// @Override +// public void editTwoPiecesDiscount(Long shopId){ +// ShopVo shopVo = shopService.queryById(shopId); +// List runningTaskList = runningTaskByShopService.selectGetShopGoodsList("t_running_task_"+shopId,"",null,null,null,null,null,0L,100000L); +// for(Map map : runningTaskList){ +// //解析数据 +// Map successData = JsonUtil.transferToObj(map.get("success_data").toString(), Map.class); +// String goodsId = successData.get("trilateralId").toString(); +// String skuId = successData.get("skuId").toString(); +// Map mapData = new HashMap(); +// mapData.put("goodsId",goodsId); +// mapData.put("skuId",skuId); +// mapData.put("token",shopVo.getToken()); +// String clientId = "203c5a7ba8bd4b8488d5e26f93052642"; +// String clientSecret = "892ffaa86e12b7a3d8d2942b669d9aa520ad8179"; +// PopClient client = new PopHttpClient(clientId, clientSecret); +// PddGoodsSkuPriceUpdateRequest request = new PddGoodsSkuPriceUpdateRequest(); +// request.setGoodsId(Long.parseLong(goodsId)); +// List skuPriceList = new ArrayList(); +// PddGoodsSkuPriceUpdateRequest.SkuPriceListItem item = new PddGoodsSkuPriceUpdateRequest.SkuPriceListItem(); +// item.setSkuId(Long.parseLong(skuId)); +// skuPriceList.add(item); +// request.setSkuPriceList(skuPriceList); +// request.setTwoPiecesDiscount(95); +// PddGoodsSkuPriceUpdateResponse response = null; +// while (true) { +// try { +// response = client.syncInvoke(request, shopVo.getToken()); +// // 如果没有错误或者错误不是频率限制错误,则退出循环 +// if (response.getErrorResponse() == null || +// (!response.getErrorResponse().getErrorMsg().contains("调用过于频繁,请调整调用频率") && +// !response.getErrorResponse().getErrorMsg().contains("系统内部异常"))) { +// break; +// } +// } catch (Exception e) { +// System.out.println(e.getMessage()); +// } +// } +// System.out.println(JsonUtil.transferToJson(response)); +// } +// } + + /** + * 表格更新商品上下级状态 + */ + @Override + public void editGoodsIsOnSale(Map map, TaskBo taskBo, Long userId) { + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + // 图书列表 + Map data = (Map) map.get("data"); + List rawList = null; + try { + rawList = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),SuccessDataItemDto.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + // 获取原始数据并过滤掉所有字段都为空的无效行 + List list = rawList.stream() + .filter(dto -> dto.isValidData()) + .collect(Collectors.toList()); + //根据isbn查询商品信息 + for(String shopId : shopIdsArr){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + Long usageCount = shopService.checkUsageCount(shopVo); + // 拼多多 + String createResStr = map.get("createResStr").toString(); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + String taskId = createResMap.get("data").toString(); + Map setTaskBodyMap = new HashMap(); + setTaskBodyMap.put("task_id",taskId); + List> bodyList = new ArrayList<>(); + int runNum = 0; + for (SuccessDataItemDto bookVo : list) { + runNum++; + Map body = new HashMap(); + Map bookInfo = new HashMap(); + bookInfo.put("isbn",bookVo.getIsbn()); + bookInfo.put("trilateralId",bookVo.getTrilateralId()); + bookInfo.put("goodsCode",bookVo.getGoodsCode()); + body.put("book_info",bookInfo); + Map detail = new HashMap(); + // 1 上架 2 下架 + detail.put("status",bookVo.getIsOnSale().equals("0") ? 2 : 1); + body.put("detail",detail); + bodyList.add(body); + if (bodyList.size() % 500 == 0 || runNum == list.size()){ + NewTaskUtils.newTaskPost(taskId,shopVo.getId().toString(),bodyList); + // 清空列表,准备下一批 + bodyList.clear(); + } + usageCount--; + if (usageCount == 0){ + break; + } + } + // 处理剩余数据 + if (!bodyList.isEmpty()) { + NewTaskUtils.newTaskPost(taskId,shopVo.getId().toString(),bodyList); + } + + // 更新使用次数 + shopService.updateUsageCount(shopVo,usageCount); + } + } + + @Override + public void updateGoodsTask(Map map, TaskBo taskBo, Long userId){ + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + // 图书列表 + Map data = (Map) map.get("data"); + List list = null; + try { + list = EasyExcelUtil.readExcelFromUrl(data.get("url").toString(),BookVo.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + for(String shopId : shopIdsArr){ + for (BookVo bookVo : list) { + Map goMap = new HashMap(); + goMap.put("priority","3"); + goMap.put("retry_count","3"); + goMap.put("isbn", bookVo.getBookNum()); + goMap.put("totalPrice", bookVo.getPrice()); + goMap.put("stock", bookVo.getStock()); + goMap.put("bookName", bookVo.getBookName()); + goMap.put("code", bookVo.getCode()); + goMap.put("imgBigUrl", bookVo.getBookImgUrl()); + goMap.put("artNo", bookVo.getArtNo()); + goMap.put("taskId", taskBo.getId().toString()); + goMap.put("shopId",shopId); + goMap.put("imageSelect", map.get("imageSelect")); + goMap.put("imageChoice", map.get("imageChoice")); + goMap.put("way",map.get("way")); + goMap.put("serviceName","UPDATE_GOODS_TASK"); + /** + * 创建运行任务对象 + */ + 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.setData(JsonUtil.transferToJson(goMap)); + runningTask.setTaskType(taskBo.getTaskType()); + runningTask.setStatus("0"); + runningTaskService.insert(runningTask); + } + } + + + } + + /** + * 手动库存同步任务 + * @param map + * @param taskBo + * @param userId + */ + @Override + public void stockSynchronize(Map map,TaskBo taskBo,Long userId){ + + // 记录参数日志 + FileUtil.logParameters("stockSynchronize",map, taskBo, userId); + + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + //转换类型,确保是数值型 + List> stockNumMapList = ((List) map.get("priceAdjustments")) + .stream() + .map(item -> { + Map newItem = new HashMap<>(item); + + // 处理 proportion + if (newItem.containsKey("proportion")) { + Object proportion = newItem.get("proportion"); + if (proportion == null) { + newItem.put("proportion", 100L); // 为空时默认给100 + } else if (proportion instanceof String) { + String proportionStr = ((String) proportion).trim(); + if (proportionStr.isEmpty()) { + newItem.put("proportion", 100L); // 空字符串时默认给100 + } else { + newItem.put("proportion", Long.parseLong(proportionStr)); + } + } else if (proportion instanceof Integer) { + newItem.put("proportion", ((Integer) proportion).longValue()); + } + // 如果是 Long 类型则保持不变 + } else { + newItem.put("proportion", 100L); // 不存在该字段时默认给100 + } + + // 处理 addNum + if (newItem.containsKey("addNum")) { + Object addNum = newItem.get("addNum"); + if (addNum == null) { + newItem.put("addNum", 0L); // 为空时默认给0 + } else if (addNum instanceof String) { + String addNumStr = ((String) addNum).trim(); + if (addNumStr.isEmpty()) { + newItem.put("addNum", 0L); // 空字符串时默认给0 + } else { + newItem.put("addNum", Long.parseLong(addNumStr)); + } + } else if (addNum instanceof Integer) { + newItem.put("addNum", ((Integer) addNum).longValue()); + } + // 如果是 Long 类型则保持不变 + } else { + newItem.put("addNum", 0L); // 不存在该字段时默认给0 + } + + return newItem; + }) + .collect(Collectors.toList()); + + for (String shopId : shopIdsArr){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("taskId",taskBo.getId().toString()); + jsonObject.put("shopId",shopId); + jsonObject.put("token",shopVo.getToken()); + jsonObject.put("shopType",shopVo.getShopType()); + if(shopVo.getShopType().equals("5")){ + //咸鱼 + jsonObject.put("appId", shopVo.getMallId().toString()); + jsonObject.put("shopKey",shopVo.getShopKey()); + } + + jsonObject.put("priceAdjustments",stockNumMapList); + String json = jsonObject.toString(); + Map dataMap = new HashMap(); + dataMap.put("data",json); + InterfaceUtils.postForm("http://36.212.12.247:8115","/api/stockSynchronize",dataMap); +// InterfaceUtils.postForm("http://localhost:8115","/api/stockSynchronize",dataMap); + } + } + + @Override + public void deleteShopGoods(Map map, TaskBo taskBo, Long userId) { + // 店铺ids + String[] shopIdsArr = map.get("shopIds").toString().split(","); + int deleteNum = Integer.parseInt(map.get("deleteNum").toString()); + int numDay = deleteNum / 5000; + int num = deleteNum % 5000; + if(num > 0){ + numDay = numDay + 1; + } + //根据isbn查询商品信息 + for(String shopId : shopIdsArr){ + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + String taskId = taskBo.getId().toString(); + //存储redis + RedisUtils.setCacheObject("deleteGoods_"+taskId,taskId+","+shopId+","+shopVo.getToken(), Duration.ofDays(numDay)); + } + } + + + // 线程暂停 + public void taskWait(String threadId) { + if (runMap.get(threadId)) { + try { + synchronized (lockMap.get(threadId)) { + lockMap.get(threadId).wait(); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public int zanTing(String threadId) { + if (runMap.get(threadId) == null) { + return 0; + } + runMap.put(threadId, true); + return 1; + } + + @Override + public int huanXing(String threadId) { + if (lockMap.get(threadId) == null) { + return 0; + } + synchronized (lockMap.get(threadId)) { + runMap.put(threadId, false); + lockMap.get(threadId).notify(); + } + return 1; + } + + /** + * 修改任务列表 + * + * @param bo 任务列表 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(TaskBo bo) { + Task update = MapstructUtils.convert(bo, Task.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(Task 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 editTaskDataNum(String shopIds, Long dataNum, String taskType) { + baseMapper.editTaskDataNum(shopIds,dataNum,taskType); + } + + + /** + * 处理拉取任务 + */ + @Override + public Map handlePullTask(TaskVo taskVo) { + Map result = new HashMap<>(); + List> shopDataList = new ArrayList<>(); + + long shopId = Long.parseLong(taskVo.getShopIds()); + ShopVo shopVo = shopService.queryById(shopId); + + Map shopData = createShopDataMap(taskVo.getId(), shopVo); + + String tableName = "t_running_task_" + shopId; + if (runningTaskByShopService.checkTableExists(tableName) == 0) { + // 表不存在 + setDefaultCounts(shopData); + } else { + int taskCount = runningTaskByShopService.selectGetShopGoodsNumByTasKId(tableName, taskVo.getId().toString()); + if (taskCount == 0) { + // 不是最新任务 + setDefaultCounts(shopData); + } else { + String status = runningTaskByShopService.selectStatus(tableName); + shopData.put("num", taskCount); + if ("2".equals(status)) { + // 未完成 + shopData.put("successCount", 0); + shopData.put("waitCount", taskCount); + } else { + // 已完成 + shopData.put("successCount", taskCount); + shopData.put("waitCount", 0); + } + } + } + + shopDataList.add(shopData); + + result.put("successCount", shopData.get("successCount")); + result.put("waitCount", shopData.get("waitCount")); + result.put("allData", shopDataList); + + return result; + } + + /** + * 处理其他类型任务 + */ + @Override + public Map handleOtherTask(TaskVo taskVo) { + Map result = new HashMap<>(); + List> shopDataList = new ArrayList<>(); + + // 从文件获取数据 + int allNum = getTaskCountFromFile(taskVo.getId()); + + // 从数据库获取任务数据 + List taskNumList = runningTaskService.selectTaskAllNum(taskVo.getId()); + + // 处理数据库中的任务数据 + processTaskDataFromDatabase(taskNumList, shopDataList); + + // 合并文件数据和数据库数据 + mergeFileAndDatabaseData(allNum, shopDataList); + + // 计算总计 + calculateTotalCounts(result, shopDataList); + + result.put("allData", shopDataList); + return result; + } + + /** + * 从文件获取任务数量 + */ + private int getTaskCountFromFile(Long taskId) { + String fileUrl = "https://book.center.file.buzhiyushu.cn/task_log/task-log-csv/" + + taskId + "/" + taskId + "_count.json"; + + try { + Map numMap = JsonObjUtil.parseJsonFromUrl(fileUrl); + return Integer.parseInt(numMap.get("totalTaskCount").toString()); + } catch (IOException e) { + log.warn("无法从文件获取任务数量: {}", fileUrl, e); + return 0; + } + } + + /** + * 处理数据库中的任务数据 + */ + private void processTaskDataFromDatabase(List taskNumList, + List> shopDataList) { + // 使用Map按shopId分组,避免重复处理 + Map> shopDataMap = new HashMap<>(); + Map shopNameCache = new HashMap<>(); + + for (RunningTaskNumVo vo : taskNumList) { + Long shopId = vo.getShopId(); + + // 获取或创建店铺数据 + Map shopData = shopDataMap.computeIfAbsent(shopId, k -> { + ShopVo shopVo = shopService.queryById(shopId); + shopNameCache.put(shopId, shopVo.getShopName()); + return createShopDataMap(vo.getTaskId(), shopId, shopVo.getShopName()); + }); + + // 更新计数 + updateShopCounts(shopData, vo); + } + + // 添加到结果列表 + shopDataList.addAll(shopDataMap.values()); + } + + /** + * 合并文件和数据库数据 + */ + private void mergeFileAndDatabaseData(int fileTaskCount, List> shopDataList) { + if (fileTaskCount > 0) { + // 这里需要根据实际情况调整合并逻辑 + // 假设文件数据是额外的成功任务 + for (Map shopData : shopDataList) { + int currentSuccess = (int) shopData.get("successCount"); + shopData.put("successCount", currentSuccess + fileTaskCount); + shopData.put("num", (int) shopData.get("num") + fileTaskCount); + } + } + } + + /** + * 计算总计数量 + */ + private void calculateTotalCounts(Map result, List> shopDataList) { + int totalSuccess = 0; + int totalWait = 0; + + for (Map shopData : shopDataList) { + totalSuccess += (int) shopData.get("successCount"); + totalWait += (int) shopData.get("waitCount"); + } + + result.put("successCount", totalSuccess); + result.put("waitCount", totalWait); + } + + /** + * 创建店铺数据Map + */ + private Map createShopDataMap(Long taskId, ShopVo shopVo) { + return createShopDataMap(taskId, shopVo.getId(), shopVo.getShopName()); + } + + private Map createShopDataMap(Long taskId, Long shopId, String shopName) { + Map shopData = new HashMap<>(); + shopData.put("taskId", taskId); + shopData.put("shopId", shopId); + shopData.put("shopName", shopName); + shopData.put("num", 0); + shopData.put("successCount", 0); + shopData.put("waitCount", 0); + return shopData; + } + + /** + * 设置默认计数 + */ + private void setDefaultCounts(Map shopData) { + shopData.put("num", 0); + shopData.put("successCount", 0); + shopData.put("waitCount", 0); + } + + /** + * 更新店铺计数 + */ + private void updateShopCounts(Map shopData, RunningTaskNumVo vo) { + int currentNum = (int) shopData.get("num"); + shopData.put("num", currentNum + vo.getAllNum()); + + if ("3".equals(vo.getStatus()) || "4".equals(vo.getStatus())) { + int currentSuccess = (int) shopData.get("successCount"); + shopData.put("successCount", currentSuccess + vo.getAllNum()); + } else { + int currentWait = (int) shopData.get("waitCount"); + shopData.put("waitCount", currentWait + vo.getAllNum()); + } + } + + @Override + public List getShopsBatch(List ids) { + if (ids == null || ids.isEmpty()) { + return Collections.emptyList(); + } + return taskMapper.selectShopsByIds(ids); + } + @Override + public List getShopDetailsBatch(List ids) { + if (ids == null || ids.isEmpty()) { + return Collections.emptyList(); + } + return taskMapper.selectShopDetailsByIds(ids); + } + + /** + * 暂停任务 + * @param taskId + * @return + */ + @Override + public Boolean taskPause(Long taskId){ + Long userId = LoginHelper.getUserId(); + TaskVo taskVo = taskMapper.selectVoById(taskId); + String[] shopIds = taskVo.getShopIds().split(","); + for(String shopId:shopIds){ + TaskPause taskPause = new TaskPause(); + taskPause.setCreateBy(userId); + taskPause.setTaskId(taskId); + taskPause.setShopId(Long.parseLong(shopId)); + taskPauseService.insert(taskPause); + } + //修改任务的状态为5 + TaskBo bo = new TaskBo(); + bo.setId(taskVo.getId()); + bo.setTaskStatus("5"); + return updateByBo(bo); + } + + /** + * 恢复任务 + * @param taskId + * @return + */ + @Override + public Boolean taskRecover(Long taskId){ + TaskVo taskVo = taskMapper.selectVoById(taskId); + TaskBo bo = new TaskBo(); + bo.setId(taskVo.getId()); + bo.setTaskStatus("0"); + taskPauseService.deleteByTaskId(taskId); + return updateByBo(bo); + } + + @Override + public Task getTaskBoById(String id) { + return this.baseMapper.selectById(id); + } + + @Override + public Task getTaskBoByRelationId(String id) { + return this.baseMapper.getTaskBoByRelationId(id); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserAccountServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserAccountServiceImpl.java new file mode 100644 index 0000000..d632181 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserAccountServiceImpl.java @@ -0,0 +1,154 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +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.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.UserAccountBo; +import org.dromara.zhishu.domain.vo.UserAccountVo; +import org.dromara.zhishu.domain.UserAccount; +import org.dromara.zhishu.mapper.UserAccountMapper; +import org.dromara.zhishu.service.IUserAccountService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 账号管理Service业务层处理 + * + * @author yxy + * @date 2026-02-25 + */ +@RequiredArgsConstructor +@Service +public class UserAccountServiceImpl implements IUserAccountService { + + private final UserAccountMapper baseMapper; + + /** + * 查询账号管理 + * + * @param id 主键 + * @return 账号管理 + */ + @Override + public UserAccountVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询账号管理列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 账号管理分页列表 + */ + @Override + public TableDataInfo queryPageList(UserAccountBo bo, PageQuery pageQuery) { + 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(UserAccountBo bo) { + Long userId = LoginHelper.getUserId(); + if (userId != 1){ + bo.setCreateBy(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + @Override + public List queryListAdmin(UserAccountBo bo){ + bo.setCreateBy(1L); + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(UserAccountBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(UserAccount::getId); + lqw.eq(StringUtils.isNotBlank(bo.getType()), UserAccount::getType, bo.getType()); + lqw.eq(StringUtils.isNotBlank(bo.getAccountType()), UserAccount::getAccountType, bo.getAccountType()); + lqw.like(StringUtils.isNotBlank(bo.getAccountName()), UserAccount::getAccountName, bo.getAccountName()); + lqw.eq(StringUtils.isNotBlank(bo.getAccount()), UserAccount::getAccount, bo.getAccount()); + lqw.eq(StringUtils.isNotBlank(bo.getIsDefault()), UserAccount::getIsDefault, bo.getIsDefault()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), UserAccount::getStatus, bo.getStatus()); + lqw.eq(ObjectUtil.isNotNull(bo.getCreateBy()), UserAccount::getCreateBy, bo.getCreateBy()); + return lqw; + } + + /** + * 新增账号管理 + * + * @param bo 账号管理 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(UserAccountBo bo) { + UserAccount add = MapstructUtils.convert(bo, UserAccount.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改账号管理 + * + * @param bo 账号管理 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(UserAccountBo bo) { + UserAccount update = MapstructUtils.convert(bo, UserAccount.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(UserAccount 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/UserRechargeServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserRechargeServiceImpl.java new file mode 100644 index 0000000..bdebbb0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserRechargeServiceImpl.java @@ -0,0 +1,270 @@ +package org.dromara.zhishu.service.impl; + +import org.dromara.common.core.domain.R; +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.bo.SysUserBo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.system.service.IUserTransferService; +import org.dromara.zhishu.domain.Shop; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.service.IShopService; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.UserRechargeBo; +import org.dromara.zhishu.domain.vo.UserRechargeVo; +import org.dromara.zhishu.domain.UserRecharge; +import org.dromara.zhishu.mapper.UserRechargeMapper; +import org.dromara.zhishu.service.IUserRechargeService; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 用户充值Service业务层处理 + * + * @author yxy + * @date 2025-04-26 + */ +@RequiredArgsConstructor +@Service +public class UserRechargeServiceImpl implements IUserRechargeService { + + private final UserRechargeMapper baseMapper; + private final ISysUserService userService; + private final IShopService shopService; + private final IUserTransferService userTransferService; + + /** + * 查询用户充值 + * + * @param id 主键 + * @return 用户充值 + */ + @Override + public UserRechargeVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 分页查询用户充值列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 用户充值分页列表 + */ + @Override + public TableDataInfo queryPageList(UserRechargeBo bo, PageQuery pageQuery) { + 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(UserRechargeBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(UserRechargeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByDesc(UserRecharge::getCreateTime); + lqw.eq(bo.getUserId() != null, UserRecharge::getUserId, bo.getUserId()); + lqw.eq(StringUtils.isNotBlank(bo.getRechargType()), UserRecharge::getRechargType, bo.getRechargType()); + if(bo.getRechargPrice() != null){ + bo.setRechargPrice(bo.getRechargPrice().multiply(new BigDecimal(100))); + } + lqw.eq(bo.getRechargPrice() != null, UserRecharge::getRechargPrice, bo.getRechargPrice()); + lqw.eq(bo.getSuccessTime() != null, UserRecharge::getSuccessTime, bo.getSuccessTime()); + lqw.between(params.get("beginTime") != null && params.get("endTime") != null, + UserRecharge::getCreateTime, params.get("beginTime"), params.get("endTime")); + lqw.eq(StringUtils.isNotBlank(bo.getAllDataStr()), UserRecharge::getAllDataStr, bo.getAllDataStr()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), UserRecharge::getStatus, bo.getStatus()); + lqw.eq(bo.getCreateBy()!=null, UserRecharge::getCreateBy, bo.getCreateBy()); + lqw.like(bo.getLogTxt() != null, UserRecharge::getLogTxt, bo.getLogTxt()); + return lqw; + } + + /** + * 新增用户充值 + * + * @param bo 用户充值 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(UserRechargeBo bo) { + UserRecharge add = MapstructUtils.convert(bo, UserRecharge.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改用户充值 + * + * @param bo 用户充值 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(UserRechargeBo bo) { + UserRecharge update = MapstructUtils.convert(bo, UserRecharge.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(UserRecharge entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除用户充值信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteByIds(ids) > 0; + } + + /** + * 充值金额到钱包里 + * @return + */ + @Override + public R addUserBalance(UserRechargeBo bo){ + // 获取充值金额 + BigDecimal money = bo.getRechargPrice(); + // 换算成单位 分 + money = money.multiply(new BigDecimal(100)); + // 查询支付订单 + UserRechargeVo userRechargeVo = queryById(bo.getId()); + // 如果 1.不存在支付订单 2.支付订单已完成支付 3.传入的金额与支付订单中的金额不一致 + if(userRechargeVo == null || userRechargeVo.getIsBalance().equals("1") || money.compareTo(new BigDecimal(userRechargeVo.getRechargPrice())) != 0){ + // 返回异常信息 + return R.fail("异常操作"); + }else{ + // 修改支付订单 + UserRechargeBo userRechargeBo = new UserRechargeBo(); + // 支付订单id + userRechargeBo.setId(bo.getId()); + // 支付订单支付状态 + userRechargeBo.setIsBalance("1"); + // 获取登陆人id + Long userId = LoginHelper.getUserId(); + // 获取用户信息 + SysUserVo userVo = userService.selectUserById(userId); + // 充值金额 + BigDecimal newPrice = userVo.getBalance().add(money); + // 创建用户信息 + SysUserBo userBo = new SysUserBo(); + // 用户id + userBo.setUserId(userId); + // 充值金额 + userBo.setBalance(newPrice); + // 原始价格 + userRechargeBo.setOriginalPrice(userVo.getBalance()); + // 更新价格 + userRechargeBo.setUpdatePrice(newPrice); + // 修改用户信息 + userService.updateUser(userBo); + // 修改支付订单的支付状态 + updateByBo(userRechargeBo); + // 返回 + return R.ok(); + } + } + + /** + * 余额支付 + * @param userId + * @param shopId + * @param logType + * @param rechargPrice + * @return + */ + @Override + public R balancePayment(Long userId, Long shopId, int logType, BigDecimal rechargPrice){ + String logTxt = ""; + switch (logType){ + case 1: + logTxt = "孔夫子店铺订阅;"; + break; + case 3: + logTxt = "闲鱼店铺订阅;"; + break; + case 1001: + logTxt = "开通子账号权限;"; + break; + } + if (shopId != null){ + ShopVo shopVo = shopService.queryById(shopId); + logTxt = "店铺名称:"+shopVo.getShopName()+";" + logTxt; + } + + SysUserVo userVo = userService.selectUserById(userId); + BigDecimal balance = userVo.getBalance(); + + if (balance.compareTo(rechargPrice) < 0){ + // 余额不足 + return R.fail("余额不足"); + }else{ + BigDecimal newBalance = balance.subtract(rechargPrice); +// SysUserBo bo = new SysUserBo(); +// bo.setUserId(userId); +// bo.setBalance(newBalance); + userTransferService.updateBalance(userId,newBalance.longValue()); + + UserRechargeBo userRechargeBo = new UserRechargeBo(); + userRechargeBo.setCommission(BigDecimal.ZERO); + userRechargeBo.setRechargPrice(rechargPrice); + userRechargeBo.setRechargType("6"); + userRechargeBo.setStatus("6"); + userRechargeBo.setUserId(userId); + userRechargeBo.setCreateBy(userId); + userRechargeBo.setUpdateBy(userId); + userRechargeBo.setLogTxt(logTxt); + userRechargeBo.setOriginalPrice(balance); + userRechargeBo.setUpdatePrice(newBalance); + insertByBo(userRechargeBo); + + Map returnMap = new HashMap(); + returnMap.put("code",200); + returnMap.put("msg","余额充足"); + returnMap.put("id", userRechargeBo.getId()); + return R.ok(returnMap); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserTAuditServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserTAuditServiceImpl.java new file mode 100644 index 0000000..75e2e07 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/UserTAuditServiceImpl.java @@ -0,0 +1,214 @@ +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.NewUserInfo; +import org.dromara.zhishu.domain.TAudit; +import org.dromara.zhishu.domain.vo.TAuditVo; +import org.dromara.zhishu.mapper.TAuditMapper; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.UserTAuditBo; +import org.dromara.zhishu.domain.vo.UserTAuditVo; +import org.dromara.zhishu.domain.UserTAudit; +import org.dromara.zhishu.mapper.UserTAuditMapper; +import org.dromara.zhishu.service.IUserTAuditService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 列表Service业务层处理 + * + * @author Lion Li + * @date 2025-04-02 + */ +@RequiredArgsConstructor +@Service +public class UserTAuditServiceImpl implements IUserTAuditService { + + private final UserTAuditMapper baseMapper; + private final TAuditMapper userTAuditMapper; + + /** + * 查询列表 + * + * @param id 主键 + * @return 列表 + */ + @Override + public UserTAuditVo queryById(Long id){ + NewUserInfo infor=baseMapper.selectU(id); + // 根据audit_id查询出t_audit_info表中数据 + UserTAuditVo tAuditVo=baseMapper.selectM(infor.getAuditId()); + // 赋值给tAuditVo + tAuditVo.setId(infor.getId()); + tAuditVo.setCompanyName(infor.getCompanyName()); + tAuditVo.setCompanyType(infor.getCompanyType()); + tAuditVo.setContactPerson(infor.getContactPerson()); + tAuditVo.setContactPhone(infor.getContactPhone()); + tAuditVo.setEmail(infor.getEmail()); + tAuditVo.setLicense(infor.getLicense()); + tAuditVo.setRemark(infor.getRemark()); + tAuditVo.setCardIdentity(infor.getCardIdentity()); + tAuditVo.setLicenseName(infor.getLicenseName()); + tAuditVo.setLicenseNumber(infor.getLicenseNumber()); + tAuditVo.setAdress(infor.getAdress()); + tAuditVo.setBusinessLicense(infor.getBusinessLicense()); + tAuditVo.setLicenseTime(infor.getLicenseTime()); + tAuditVo.setBusinessLicenseTime(infor.getBusinessLicenseTime()); + return tAuditVo; + + } + + /** + * 分页查询列表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 列表分页列表 + */ + @Override + public TableDataInfo queryPageList(UserTAuditBo bo, PageQuery pageQuery) { + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + // 根据用户id查询出t_audit_info表中对应id + Long id= baseMapper.selectId(userId); + // 判断id是否为空 + if(id==null){ + return TableDataInfo.build(); + } + //把id和userId赋值给bo,并传入baseMapper + bo.setId(id); + bo.setUserId(userId); + //自定义分页查询 + Page result = baseMapper.customPageList(pageQuery.build(), bo); + + // 遍历result,把id和userId赋值给result + for (int i = 0; i < result.getRecords().size(); i++) { + Long ids = result.getRecords().get(i).getId(); + String status = baseMapper.selectStatus(id); + result.getRecords().get(i).setId(ids); + result.getRecords().get(i).setStatus(status); + String name = baseMapper.selectUserName(userId); + NewUserInfo info = baseMapper.selectUserList(ids); + result.getRecords().get(i).setCompanyName(info.getCompanyName()); + result.getRecords().get(i).setCompanyType(info.getCompanyType()); + result.getRecords().get(i).setContactPerson(info.getContactPerson()); + result.getRecords().get(i).setContactPhone(info.getContactPhone()); + result.getRecords().get(i).setEmail(info.getEmail()); + result.getRecords().get(i).setLicense(info.getLicense()); + result.getRecords().get(i).setRemark(info.getRemark()); + result.getRecords().get(i).setUserName(name); + } + + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的列表列表 + * + * @param bo 查询条件 + * @return 列表列表 + */ + @Override + public List queryList(UserTAuditBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(UserTAuditBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getId() != null, UserTAudit::getAdminId, bo.getId()); + return lqw; + } + + /** + * 新增列表 + * + * @param bo 列表 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(UserTAuditBo bo) { + UserTAudit add = MapstructUtils.convert(bo, UserTAudit.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + } + return flag; + } + + /** + * 修改列表 + * + * @param bo 列表 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(UserTAuditBo bo) { + bo.setStatus("2"); + UserTAudit update = MapstructUtils.convert(bo, UserTAudit.class); + NewUserInfo newUserInfo=new NewUserInfo(); + newUserInfo.setCompanyName(bo.getCompanyName()); + newUserInfo.setCompanyType(bo.getCompanyType()); + newUserInfo.setContactPerson(bo.getContactPerson()); + newUserInfo.setContactPhone(bo.getContactPhone()); + newUserInfo.setEmail(bo.getEmail()); + newUserInfo.setLicense(bo.getLicense()); + newUserInfo.setRemark(bo.getRemark()); + newUserInfo.setId(update.getId()); + newUserInfo.setLicenseName(bo.getLicenseName()); + newUserInfo.setLicenseNumber(bo.getLicenseNumber()); + newUserInfo.setCardIdentity(bo.getCardIdentity()); + newUserInfo.setAdress(bo.getAdress()); + newUserInfo.setLicenseTime(bo.getLicenseTime()); + newUserInfo.setBusinessLicenseTime(bo.getBusinessLicenseTime()); + newUserInfo.setBusinessLicense(bo.getBusinessLicense()); + // 修改t_audit_info表中的数据 + userTAuditMapper.updateByUser(newUserInfo); + //更新时间 + Boolean message= baseMapper.updateUserId(update); + return message; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(UserTAudit entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除列表信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + Long auditId = baseMapper.selectAudit(ids); + Integer message=baseMapper.deleteAudit(auditId); + if(message==0){ + return false; + } + Long message1 = baseMapper.deleteByAudit(ids); + return message1> 0; + } + + @Override + public UserTAuditVo getAuditLog() { + Long userId = LoginHelper.getUserId(); + Long message= baseMapper.selectId(userId); + return baseMapper.getAuditLog(message); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WarehouseSettingsAttributeServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WarehouseSettingsAttributeServiceImpl.java new file mode 100644 index 0000000..f34b76c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WarehouseSettingsAttributeServiceImpl.java @@ -0,0 +1,32 @@ +package org.dromara.zhishu.service.impl; + +import com.pdd.pop.sdk.common.util.JsonUtil; +import lombok.RequiredArgsConstructor; +import org.dromara.zhishu.domain.WarehouseSettingsAttribute; +import org.dromara.zhishu.service.IWarehouseSettingsAttributeService; +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 WarehouseSettingsAttributeServiceImpl implements IWarehouseSettingsAttributeService { + + /** + * 查询规则属性列表 + * + * @param warehouseSettingsAttribute + * @return + */ + @Override + public List selectList(WarehouseSettingsAttribute warehouseSettingsAttribute){ + Map params = new HashMap<>(); + String warehouseSettingsAttributeListStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/warehouseSettingAttribute/getList",params); + List warehouseSettingsAttributeList = JsonUtil.transferToObj(warehouseSettingsAttributeListStr,List.class); + return warehouseSettingsAttributeList; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WarehouseSettingsServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WarehouseSettingsServiceImpl.java new file mode 100644 index 0000000..c87a075 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WarehouseSettingsServiceImpl.java @@ -0,0 +1,144 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.apache.commons.beanutils.BeanUtils; +import org.dromara.common.core.utils.StringUtils; +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.WarehouseSettings; +import org.dromara.zhishu.domain.dto.OrderExternalGoodsDto; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.WarehouseSettingsBo; +import org.dromara.zhishu.domain.vo.WarehouseSettingsVo; +import org.dromara.zhishu.service.IWarehouseSettingsService; + +import java.util.HashMap; +import java.util.List; +import java.util.Collection; +import java.util.Map; + +/** + * 设置Service业务层处理 + * + * @author yxy + * @date 2025-12-19 + */ +@RequiredArgsConstructor +@Service +public class WarehouseSettingsServiceImpl implements IWarehouseSettingsService { + + /** + * 查询设置 + * + * @param id 主键 + * @return 设置 + */ + @Override + public WarehouseSettingsVo queryById(Long id){ + String WarehouseSettingsStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/warehouseSetting/"+id,new HashMap<>()); + WarehouseSettingsVo WarehouseSettings = JsonUtil.transferToObj(WarehouseSettingsStr,WarehouseSettingsVo.class); + return WarehouseSettings; + } + + /** + * 分页查询设置列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 设置分页列表 + */ + @Override + public TableDataInfo queryPageList(WarehouseSettingsBo bo, PageQuery pageQuery) { + + Map params = new HashMap<>(); + params.put("pageNum",pageQuery.getPageNum()); + params.put("pageSize",pageQuery.getPageSize()); + params.put("delFlag",0); + String WarehouseSettingsListStr = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/warehouseSetting/getList",params); + Map dataMap = JsonUtil.transferToObj(WarehouseSettingsListStr,Map.class); + List WarehouseSettingsList = (List) dataMap.get("data"); + int total = (int) dataMap.get("total"); + Page result = new Page<>(pageQuery.getPageNum(),pageQuery.getPageSize(),total); + result.setRecords(WarehouseSettingsList); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的设置列表 + * + * @param bo 查询条件 + * @return 设置列表 + */ + @Override + public List queryList(WarehouseSettingsBo bo) { + return null; + } + + + + /** + * 新增设置 + * + * @param bo 设置 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(WarehouseSettingsBo bo) { + bo.setCreateBy(LoginHelper.getUserId()); + bo.setUpdateBy(LoginHelper.getUserId()); + Map map = new HashMap(); + map.put("warehouseSettingsStr",JsonUtil.transferToJson(bo)); + InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/warehouseSetting/add",map); + return true; + } + + /** + * 修改设置 + * + * @param bo 设置 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(WarehouseSettingsBo bo) { + bo.setUpdateBy(LoginHelper.getUserId()); + Map map = new HashMap(); + map.put("warehouseSettingsStr",JsonUtil.transferToJson(bo)); + InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/warehouseSetting/edit",map); + return true; + } + + /** + * 修改启用状态 + * @param bo + * @return + */ + @Override + public Boolean updateStatus(WarehouseSettingsBo bo){ + bo.setUpdateBy(LoginHelper.getUserId()); + Map map = new HashMap(); + map.put("warehouseSettingsStr",JsonUtil.transferToJson(bo)); + InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/warehouseSetting/editStatus",map); + return true; + } + + /** + * 校验并批量删除设置信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + + for (Long id:ids){ + InterfaceUtils.postForm(UrlUtil.getOrderServiceUrl(),"/api/warehouseSetting/deleteById/"+id,new HashMap<>()); + } + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WaveDetailServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WaveDetailServiceImpl.java new file mode 100644 index 0000000..c27e075 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/WaveDetailServiceImpl.java @@ -0,0 +1,155 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.dromara.zhishu.domain.WaveDetail; +import org.dromara.zhishu.domain.dto.WaveDetailRequestDto; +import org.dromara.zhishu.domain.vo.EmployeeInfoVo; +import org.dromara.zhishu.mapper.WaveDetailMapper; +import org.dromara.zhishu.service.IWaveDetailService; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 波次信息Service业务层处理 + * + * @author Lion Li + * @date 2026-01-22 + */ +@RequiredArgsConstructor +@Service +public class WaveDetailServiceImpl implements IWaveDetailService { + + private final WaveDetailMapper waveDetailMapper; + + /** + * 新增波次信息 + * + * @param requestDto 波次信息请求DTO + * @return 是否新增成功 + */ + @Override + public Boolean insertWaveDetail(String userId, WaveDetailRequestDto requestDto) { + // 获取当前时间戳 + long currentTime = System.currentTimeMillis() / 1000; + + // 遍历ISBN列表,创建WaveDetail实体并保存 + List waveDetailList = new ArrayList<>(); + for (WaveDetailRequestDto.IsbnDto isbnDto : requestDto.getIsbnList()) { + + // 获取仓库id + String shipmentId = requestDto.getShipmentId(); + Long stockId = parseShipmentId(userId, shipmentId); + + WaveDetail waveDetail = new WaveDetail(); + waveDetail.setUserId(Long.valueOf(userId)); + waveDetail.setWaveId(requestDto.getWaveId()); + waveDetail.setIsbn(isbnDto.getIsbn()); + waveDetail.setQuality(isbnDto.getQuality()); + waveDetail.setStockId(stockId); + // shipmentId作为stockNum存储 + waveDetail.setStockNum(requestDto.getShipmentId()); + waveDetail.setCreatedTime(currentTime); + waveDetail.setUpdatedTime(currentTime); + waveDetail.setIsDel(0L); // 默认未删除 + waveDetailList.add(waveDetail); + } + + // 批量插入数据库 + if (!waveDetailList.isEmpty()) { + return waveDetailMapper.insertBatch(waveDetailList) > 0; + } + + return false; + } + + @Override + public Long getWaveID() { + return waveDetailMapper.getWaveId(); + } + + @Override + public String getEmployeeId(String name, String userId) { + return waveDetailMapper.getEmployeeId(name, userId); + } + + @Override + public Boolean countVerWave(String waveId, String employeeId, Integer submitCount) { + + Long timestamp = System.currentTimeMillis() / 1000; + + // 从wave_employee表查询员工姓名 + Map staffInfo = waveDetailMapper.getWaveEmployeeName(employeeId); + + + // 插入employeeInfo记录 + EmployeeInfoVo employeeInfo = new EmployeeInfoVo(); + + String name = staffInfo.get("name"); + String userId = staffInfo.get("user_id"); + + + employeeInfo.setEmployeeId(employeeId); // 设置员工ID + employeeInfo.setName(name); // 使用从wave_employee表获取的员工姓名 + employeeInfo.setUserId(Long.valueOf(staffInfo.get("user_id").toString())); + employeeInfo.setWave(waveId); + employeeInfo.setCount(submitCount); + employeeInfo.setCreatedTime(timestamp); + employeeInfo.setUpdatedTime(timestamp); + employeeInfo.setDelFlag(0); + + long insertResult = waveDetailMapper.insertEmployeeInfo(employeeInfo); + if (insertResult <= 0) { + return false; + } + + // 从employeeInfo表统计count的和 + Long countSum = waveDetailMapper.getEmployeeInfoCountSum(userId, waveId); + if (countSum == null) { + countSum = 0L; + } + + // 检查wave表中是否存在记录 + int exists = waveDetailMapper.checkWaveExists(employeeId, userId); + if (exists > 0) { + // 如果存在,更新count + int updateResult = waveDetailMapper.updateWaveCount(employeeId, userId, countSum, timestamp); + return updateResult > 0; + } else { + // 如果不存在,新增一条数据 + int insertWaveResult = waveDetailMapper.insertWave(employeeId, name, employeeId, countSum, timestamp, timestamp); + return insertWaveResult > 0; + } + } + + /** + * 解析shipmentId,获取一、二、三级货区号 + * @param shipmentId 货号 + */ + private Long parseShipmentId(String userId, String shipmentId) { + if (shipmentId != null && shipmentId.length() == 5) { + // 一级货区:前2位 + String firstLevel = shipmentId.substring(0, 2); + + char thirdChar = shipmentId.charAt(2); + String secondLevel; + String thirdLevel; + + if (Character.isDigit(thirdChar)) { + // 第三位是数字:第三位是二级货区,第四五位是三级货区 + secondLevel = shipmentId.substring(2, 3); + thirdLevel = shipmentId.substring(3, 5); + } else { + // 第三位是字母:第三四位是二级货区,第五位是三级货区 + secondLevel = shipmentId.substring(2, 4); + thirdLevel = shipmentId.substring(4, 5); + } + + return waveDetailMapper.getFreightId(userId, firstLevel, secondLevel, thirdLevel); + } + return null; + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XianYvQueryShopImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XianYvQueryShopImpl.java new file mode 100644 index 0000000..5209e15 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XianYvQueryShopImpl.java @@ -0,0 +1,111 @@ +package org.dromara.zhishu.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.util.*; + +@Slf4j +@Service +public class XianYvQueryShopImpl { + + private final RestTemplate restTemplate; + + @Autowired + public XianYvQueryShopImpl(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + public R>> XianYvQueryShop(String appId, String appSecret) { + try { + String url = "http://119.45.237.193:9102/xianyv/getShopList"; + log.info("开始调用咸鱼API: {}", url); + + // 设置请求头 - 使用表单格式 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + // 创建表单参数 + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("appId", appId); + formData.add("appSecret", appSecret); + + HttpEntity> entity = new HttpEntity<>(formData, headers); + + // 使用POST请求 + ResponseEntity response = restTemplate.exchange( + url, HttpMethod.POST, entity, String.class); + + log.info("咸鱼API响应状态: {}", response.getStatusCode()); + log.info("咸鱼API响应内容: {}", response.getBody()); + + if (response.getStatusCode().value() == 200) { + JSONObject jsonObject = JSON.parseObject(response.getBody()); + + if (jsonObject.getInteger("code") == 0) { + JSONObject data = jsonObject.getJSONObject("data"); + if (data == null) { + log.warn("咸鱼API返回data为空"); + return R.ok(Collections.emptyList()); + } + + JSONArray list = data.getJSONArray("list"); + if (list == null || list.isEmpty()) { + log.info("咸鱼店铺列表为空"); + return R.ok(Collections.emptyList()); + } + + List> shopList = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + JSONObject item = list.getJSONObject(i); + String userName = item.getString("user_name"); + String shopName = item.getString("shop_name"); + String expirationTime = item.getString("valid_end_time"); + + // 创建一个Map来存储用户名称和店铺名称 + Map shopInfo = new HashMap<>(); + if (userName != null && !userName.trim().isEmpty()) { + shopInfo.put("user_name", userName); + } + if (shopName != null && !shopName.trim().isEmpty()) { + shopInfo.put("shop_name", shopName); + } + if (expirationTime != null && !expirationTime.trim().isEmpty()) { + shopInfo.put("expiration_time", expirationTime); + } + + // 只有当至少有一个字段不为空时才添加到结果列表 + if (!shopInfo.isEmpty()) { + shopList.add(shopInfo); + log.info("找到店铺 - 用户名称: {}, 店铺名称: {}", userName, shopName); + } + } + + log.info("成功获取咸鱼店铺数量: {}", shopList.size()); + return R.ok(shopList); + } else { + String errorMsg = jsonObject.getString("msg"); + log.error("咸鱼API业务异常: {}", errorMsg); + return R.fail("咸鱼API返回错误: " + errorMsg); + } + } else { + log.error("咸鱼API请求失败,状态码: {}", response.getStatusCode().value()); + return R.fail("咸鱼API请求失败,状态码: " + response.getStatusCode().value()); + } + + } catch (Exception e) { + log.error("调用咸鱼API异常: {}", e.getMessage(), e); + return R.fail("调用咸鱼API异常: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XyBindServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XyBindServiceImpl.java new file mode 100644 index 0000000..482e76b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XyBindServiceImpl.java @@ -0,0 +1,125 @@ +package org.dromara.zhishu.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +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 lombok.extern.slf4j.Slf4j; +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.Shop; +import org.dromara.zhishu.domain.XyBind; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.mapper.XyBindMapper; +import org.dromara.zhishu.service.IXyBindService; + +import org.dromara.zhishu.domain.bo.XyBindBo; +import org.dromara.zhishu.domain.vo.XyBindVo; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; + +import static com.baomidou.mybatisplus.extension.toolkit.Db.update; + +@RequiredArgsConstructor +@Service +@Slf4j +public class XyBindServiceImpl implements IXyBindService { + + private final XyBindMapper baseMapper; + private final ShopMapper shopMapper; + + @Override + public XyBindVo queryById(String token) { + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(XyBind::getToken, token); + return baseMapper.selectVoOne(wrapper); + } + + @Override + public TableDataInfo queryPageList(XyBindBo 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); + } + + private LambdaQueryWrapper buildQueryWrapper(XyBindBo bo) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(XyBind::getId); + + // 只保留常用搜索条件 + lqw.eq(bo.getCreateBy() != null, XyBind::getCreateBy, bo.getCreateBy()); + lqw.eq(StringUtils.isNotBlank(bo.getAppName()), XyBind::getAppName, bo.getAppName()); + lqw.like(bo.getMallId() != null, XyBind::getMallId, bo.getMallId()); + lqw.eq(StringUtils.isNotBlank(bo.getToken()), XyBind::getToken, bo.getToken()); + return lqw; + } + + @Override + public Boolean insertByBo(XyBindBo bo) { + XyBind xyBind = new XyBind(); + xyBind.setAppName(bo.getAppName()); + xyBind.setMallId(bo.getMallId()); + xyBind.setToken(bo.getToken()); + xyBind.setCreateBy(bo.getCreateBy()); + // 执行插入操作 + return baseMapper.insert(xyBind) > 0; + } + + @Override + public Boolean updateByBo(XyBindBo bo) { + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(XyBind::getToken, bo.getToken()) + .set(XyBind::getAppName, bo.getAppName()) + .set(XyBind::getUpdateBy, bo.getUpdateBy()) + .set(XyBind::getUpdateTime, new Date()); + + return baseMapper.update(updateWrapper) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean deleteByToken(String token) { + // 获取当前登录用户ID + Long userId = LoginHelper.getUserId(); + + // 1. 逻辑删除xy_bind表中的数据 + LambdaUpdateWrapper xyBindUpdateWrapper = new LambdaUpdateWrapper<>(); + xyBindUpdateWrapper.eq(XyBind::getToken, token) + .set(XyBind::getDelFlag, 1) + .set(XyBind::getUpdateTime, new Date()) + .set(userId != null, XyBind::getUpdateBy, userId); + + int xyBindResult = baseMapper.update(null, xyBindUpdateWrapper); + + LambdaUpdateWrapper shopUpdateWrapper = new LambdaUpdateWrapper<>(); + shopUpdateWrapper.eq(Shop::getToken, token) + .set(Shop::getDelFlag, 1) + .set(Shop::getUpdateTime, new Date()) + .set(userId != null, Shop::getUpdateBy, userId); + + int shopResult = shopMapper.update(null, shopUpdateWrapper); + + + log.info("删除操作完成 - xy_bind表影响行数: {}, t_shop表影响行数: {}", xyBindResult, shopResult); + + // 只要xy_bind表删除成功就返回true,或者您可以根据业务需求调整 + return xyBindResult > 0; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XyCategoryServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XyCategoryServiceImpl.java new file mode 100644 index 0000000..7f89e17 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/XyCategoryServiceImpl.java @@ -0,0 +1,23 @@ +package org.dromara.zhishu.service.impl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.zhishu.domain.vo.XyCategoryVo; +import org.dromara.zhishu.mapper.XyCategoryMapper; +import org.dromara.zhishu.service.IXyCategoryService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@RequiredArgsConstructor +@Service +@Slf4j +public class XyCategoryServiceImpl implements IXyCategoryService { + + private final XyCategoryMapper xyCategoryMapper; + + @Override + public List selectXyCategoryList() { + return xyCategoryMapper.selectXyCategoryList(); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsAopServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsAopServiceImpl.java new file mode 100644 index 0000000..7debf23 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsAopServiceImpl.java @@ -0,0 +1,180 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.annotations.Param; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.zhishu.annotation.LogRecord; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.dto.request.UpdateArtNoRequest; +import org.dromara.zhishu.domain.dto.request.ZhishuShopGoodsRequest; +import org.dromara.zhishu.domain.vo.FreightGoodsCountVo; +import org.dromara.zhishu.domain.vo.SaveGoodsVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.enums.TaskTypeEnum; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.dromara.zhishu.service.ZhishuShopGoodsAopService; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.util.CnumberUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +@Slf4j +@RequiredArgsConstructor +@Service +public class ZhishuShopGoodsAopServiceImpl implements ZhishuShopGoodsAopService { + + @Autowired + private ZhishuShopGoodsMapper baseMapper; + + @Autowired + private KfzClient kfzClient; + + @Autowired + @Lazy + private IZhishuShopGoodsService zhishuShopGoodsService; + + @Override + @LogRecord(logResult = true) + public void insertNewDataList( + @Param("data") ZhishuShopGoodsRequest data, @Param("userId") Long userId, + @Param("freightGoodsCountList") List freightGoodsCountList, + @Param("saveGoodsVo") SaveGoodsVo saveGoodsVo, + @Param("failedList") List failedList, + @Param("successList") List successList, + @Param("successMarkI") AtomicInteger successMarkI, @Param("failMarkI") AtomicInteger failMarkI, + @Param("shopVo") ShopVo shopVo, @Param("totalNum") Integer totalNum, @Param("time") long time, + @Param("status") AtomicBoolean status, + @Param("taskType") String taskType + ) { + try { + ZhishuShopGoods zhishuShopGoods = new ZhishuShopGoods(); + BeanUtils.copyProperties(data, zhishuShopGoods); + zhishuShopGoods.setCreateBy(Long.valueOf(data.getUserId())); + zhishuShopGoods.setUserId(userId); + // 处理品相码 + double conditionCode; + if (ObjectUtil.isNotEmpty(data.getConditionCode())) { + conditionCode = Math.round(data.getConditionCode().doubleValue()) / 10.0; + String conditionCodeString = CnumberUtils.getConditionCode(conditionCode); + zhishuShopGoods.setConditionCode(conditionCodeString); + } else { + conditionCode = 8.5; + } + // 处理价格 + if (ObjectUtil.isNotEmpty(data.getPrice())) { + zhishuShopGoods.setPrice(data.getPrice() * 100); + } + if (ObjectUtil.isNotEmpty(data.getFixPrice())) { + zhishuShopGoods.setFixPrice(data.getFixPrice() * 100); + } + // 处理库存 + if (ObjectUtil.isNotEmpty(data.getInventory())) { + zhishuShopGoods.setInventory(Long.valueOf(data.getInventory())); + } + // 判断ISBN码是否为空 + if (ObjectUtil.isEmpty(data.getIsbn())) { + String isbn = CnumberUtils.generateRandomIsbn(); + zhishuShopGoods.setIsbn(isbn); + } + + // 自动为书籍分配一二三级存储区域 + FreightGoodsCountVo freightGoodsCountVo = CnumberUtils.autoAllocatingAreas(freightGoodsCountList); + // 将freightGoodsCountList对应货区书籍数量+1 + for (FreightGoodsCountVo goodsCountVo : freightGoodsCountList) { + if (goodsCountVo.getFreightId().equals(freightGoodsCountVo.getFreightId())) { + goodsCountVo.setGoodsCount(goodsCountVo.getGoodsCount() + 1); + } + } + + // 获取货号 + String artNo = zhishuShopGoodsService.artNoProcessing(saveGoodsVo.getSaveArtNoRule(), userId, zhishuShopGoods.getIsbn(), data.getArtNo(), conditionCode, freightGoodsCountVo); + zhishuShopGoods.setArtNo(artNo); + + // 写入仓库id + zhishuShopGoods.setDepotId(freightGoodsCountVo.getDepotId()); + TaskTypeEnum taskTypeEnum = TaskTypeEnum.valueOfCode(taskType); + switch (taskTypeEnum) { + case SYNC_GOODS_KFZ: + // 写入原始货号 + zhishuShopGoods.setOriginalArtNo(data.getArtNo()); + // 将新生成的货号同步到kfz + if (saveGoodsVo.getSaveArtNoRule() != 0) { + UpdateArtNoRequest request = new UpdateArtNoRequest(); + request.setShopId(saveGoodsVo.getShopId()); + request.setProductId(Long.valueOf(zhishuShopGoods.getProductId())); + request.setArtNo(zhishuShopGoods.getArtNo()); + try { + Thread.sleep(1000L); // 在调用前休眠 + // kfzClient.updateArtNo(UrlUtil.getKfzServiceUrl(), request); + // 是否已货号转换 + zhishuShopGoods.setIsArtNoConversion(1); + } catch (Exception e) { + throw new ServiceException("同步货号失败:" + e.getMessage()); + } + } + break; + case SYNC_GOODS_WLN: + // 写入原始货号 + zhishuShopGoods.setOriginalArtNo(data.getProductId()); + break; + } + // 将这条数据插入到数据库 + baseMapper.insert(zhishuShopGoods); + // 初始化该商品redis库存 + zhishuShopGoodsService.batchRedisInitInventory(List.of(zhishuShopGoods)); + successList.add(data); + } catch (Exception e) { + log.error(e.getMessage()); + failedList.add(data); + status.set(false); + } + } + + @Override + @LogRecord(logResult = true) + public void updateChangedDataList( + @Param("data") ZhishuShopGoodsRequest data, @Param("userId") Long userId, + @Param("freightGoodsCountList") List freightGoodsCountList, + @Param("saveGoodsVo") SaveGoodsVo saveGoodsVo, + @Param("failedList") List failedList, + @Param("successList") List successList, + @Param("successMarkI") AtomicInteger successMarkI, @Param("failMarkI") AtomicInteger failMarkI, + @Param("shopVo") ShopVo shopVo, @Param("totalNum") Integer totalNum, @Param("newTime") long time, + @Param("status") AtomicBoolean status + ) { + List originalList = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ZhishuShopGoods::getId, data.getId()) + .list(); + if (ObjectUtil.isNotEmpty(originalList)) { + ZhishuShopGoods zhishuShopGoods = new ZhishuShopGoods(); + zhishuShopGoods.setId(data.getId()); + zhishuShopGoods.setUserId(userId); + // 判断ISBN码是否为空 + if (ObjectUtil.isEmpty(data.getIsbn())) { + String isbn = CnumberUtils.generateRandomIsbn(); + zhishuShopGoods.setIsbn(isbn); + } + // 处理品相码 + double conditionCode = Math.round(data.getConditionCode().doubleValue()) / 10.0; + String conditionCodeString = CnumberUtils.getConditionCode(conditionCode); + zhishuShopGoods.setConditionCode(conditionCodeString); + // 处理库存 + zhishuShopGoods.setInventory(Long.valueOf(data.getInventory())); + // 更新数据 + baseMapper.updateById(zhishuShopGoods); + successList.add(data); + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsDetailServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsDetailServiceImpl.java new file mode 100644 index 0000000..91c89a2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsDetailServiceImpl.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.springframework.stereotype.Service; +import org.dromara.zhishu.domain.bo.ZhishuShopGoodsDetailBo; +import org.dromara.zhishu.domain.vo.ZhishuShopGoodsDetailVo; +import org.dromara.zhishu.domain.ZhishuShopGoodsDetail; +import org.dromara.zhishu.mapper.ZhishuShopGoodsDetailMapper; +import org.dromara.zhishu.service.IZhishuShopGoodsDetailService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 商品信息补全表Service业务层处理 + * + * @author yxy + * @date 2025-06-13 + */ +@RequiredArgsConstructor +@Service +public class ZhishuShopGoodsDetailServiceImpl implements IZhishuShopGoodsDetailService { + + private final ZhishuShopGoodsDetailMapper baseMapper; + + /** + * 查询商品信息补全表 + * + * @param id 主键 + * @return 商品信息补全表 + */ + @Override + public ZhishuShopGoodsDetailVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + @Override + public ZhishuShopGoodsDetailVo selectByPid(Long pid){ + return baseMapper.selectByPid(pid); + } + + /** + * 分页查询商品信息补全表列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品信息补全表分页列表 + */ + @Override + public TableDataInfo queryPageList(ZhishuShopGoodsDetailBo 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(ZhishuShopGoodsDetailBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(ZhishuShopGoodsDetailBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByAsc(ZhishuShopGoodsDetail::getId); + lqw.eq(bo.getPid() != null, ZhishuShopGoodsDetail::getPid, bo.getPid()); + lqw.eq(StringUtils.isNotBlank(bo.getAuthor()), ZhishuShopGoodsDetail::getAuthor, bo.getAuthor()); + lqw.eq(StringUtils.isNotBlank(bo.getPublisher()), ZhishuShopGoodsDetail::getPublisher, bo.getPublisher()); + lqw.eq(StringUtils.isNotBlank(bo.getPublishertime()), ZhishuShopGoodsDetail::getPublishertime, bo.getPublishertime()); + lqw.eq(StringUtils.isNotBlank(bo.getFormat()), ZhishuShopGoodsDetail::getFormat, bo.getFormat()); + lqw.eq(StringUtils.isNotBlank(bo.getWordage()), ZhishuShopGoodsDetail::getWordage, bo.getWordage()); + lqw.eq(StringUtils.isNotBlank(bo.getUnifiedisbn()), ZhishuShopGoodsDetail::getUnifiedisbn, bo.getUnifiedisbn()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), ZhishuShopGoodsDetail::getStatus, bo.getStatus()); + return lqw; + } + + /** + * 新增商品信息补全表 + * + * @param bo 商品信息补全表 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ZhishuShopGoodsDetailBo bo) { + ZhishuShopGoodsDetail add = MapstructUtils.convert(bo, ZhishuShopGoodsDetail.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改商品信息补全表 + * + * @param bo 商品信息补全表 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ZhishuShopGoodsDetailBo bo) { + ZhishuShopGoodsDetail update = MapstructUtils.convert(bo, ZhishuShopGoodsDetail.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ZhishuShopGoodsDetail 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/ZhishuShopGoodsServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsServiceImpl.java new file mode 100644 index 0000000..bf0c995 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopGoodsServiceImpl.java @@ -0,0 +1,5205 @@ +package org.dromara.zhishu.service.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.JsonNode; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +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 jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.dromara.common.core.enums.FormatsType; +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.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +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.dto.BatchProcessingContext; +import org.dromara.zhishu.domain.dto.RunningTaskShopGoodsDto; +import org.dromara.zhishu.domain.dto.request.BatchGoodsRequest; +import org.dromara.zhishu.domain.dto.request.GoodsComparisonRequest; +import org.dromara.zhishu.domain.dto.request.UpdateArtNoRequest; +import org.dromara.zhishu.domain.dto.request.ZhishuShopGoodsRequest; +import org.dromara.zhishu.domain.vo.*; +import org.dromara.zhishu.domain.vo.ProductSubmitResultVo; +import org.dromara.zhishu.enums.*; +import org.dromara.zhishu.mapper.*; +import org.dromara.zhishu.service.*; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.service.client.PddClient; +import org.dromara.zhishu.service.factory.InventorySynchronizedStrategyFactory; +import org.dromara.zhishu.service.strategy.InventorySynchronizedStrategy; +import org.dromara.zhishu.threads.KfzAutoAddRunnable; +import org.dromara.zhishu.threads.ShopGoodsTaskRunnable; +import org.dromara.zhishu.util.*; +import org.hibernate.validator.internal.util.stereotypes.Lazy; +import org.redisson.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.repository.query.Param; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.ProxySelector; +import java.net.URI; +import java.net.URL; +import java.net.URLEncoder; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.dromara.zhishu.util.UrlUtil.getImgResultUrl; +import static org.dromara.zhishu.util.UrlUtil.getUploadImgUrl; + +/** + * 商品信息Service业务层处理 + * + * @author Lion Li + * @date 2025-03-07 + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class ZhishuShopGoodsServiceImpl implements IZhishuShopGoodsService { + + private static final String UPLOAD_DIR = "D:\\images"; + + private final WaveDetailMapper waveDetailMapper; + + + /** + * 锁对象 + */ + private final Map lockMap = new HashMap<>(); + private final Map runMap = new HashMap<>(); + + private final ApplicationContext applicationContext; + private final IZhishuShopGoodsDetailService zhishuShopGoodsDetailService; + + private final ZhishuShopGoodsMapper baseMapper; + + private final IRunningTaskService runningTaskService; + + + private final TBookAuditMapper tBookAuditMapper; + + private final IShopGoodsPublishedService shopGoodsPublishedService; + + private final IZhishuShopImagesService zhishuShopImagesService; + + private final IRunningTaskByShopService runningTaskByShopService; + + private final ScheduledExecutorService scheduledExecutorService; + + private final ITaskService taskService; + + private final ISysConfigService configService; + + private final IShopDetailService shopDetailService; + + private final ITDepotService depotService; + + + private final ITLogisticsService logisticsService; + // 每隔多少秒续期一次 Redis 锁(比如 30 秒) + private static final int INITIAL_DELAY_AND_PERIOD = 30; + + @Resource + private TDepotMapper tDepotMapper; + + @Resource + private TShelvesMapper tShelvesMapper; + + @Autowired + private IShopService shopService; + + @Autowired + private TaskServiceImpl taskServiceImpl; + + @Autowired + private CnumberUtils cnumberUtils; + + @Autowired + private TDepotMapper TDepotMapper; + + @Autowired + private TShelvesMapper TShelvesMapper; + + @Autowired + private TFreightMapper TFreightMapper; + + @Autowired + private TLogisticsMapper tLogisticsMapper; + + @Autowired + private ZhishuShopImagesMapper zhishuShopImagesMapper; + + @Lazy + @Autowired + private SysUserMapper sysUserMapper; + + @Autowired + private ShopMapper shopMapper; + + @Lazy + @Autowired + private KongfzServiceImpl kongfzService; + + @Autowired + private ShopGoodIsbnMapper shopGoodIsbnMapper; + + @Autowired + private ArtNoMoveMapper artNoMoveMapper; + + // 品相对应的数值 + private static final double[] CONDITION_CODES = {1, 2, 3, 4, 5, 6, 6.5, 7, 7.5, 8, 8.5, 9, 9.5, 10}; + // 品相对应的字母标识 + private static final String[] CONDITION_CODE = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N"}; + + // 品相对应的中文标识 + private static final String[] CHINESE_CODE = {"一品", "二品", "三品", "四品", "五品", "六品", "六五品", "七品", "七五品", "八品", "八五品", "九品", "九五品", "全新"}; + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private KfzClient kfzClient; + + @Autowired + private UploadUtil uploadUtil; + + @Autowired + private ZhishuShopGoodsAopService zhishuShopGoodsAopService; + + @Autowired + private StockChangeLogMapper stockChangeLogMapper; + @Autowired + private PddClient pddClient; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private PlatformTransactionManager transactionManager; + + + + /** + * 批量查询商品根据id + * @param ids + * @return + */ + @Override + public List selectByIds(List ids){ + return baseMapper.selectByIds(ids); + } + + /** + * 查询商品信息 + * + * @param id 主键 + * @return 商品信息 + */ + @Override + public ZhishuShopGoodsVo queryById(String id) { + // 查询商品信息 + Long userId = LoginHelper.getUserId(); + ZhishuShopGoodsVo result = baseMapper.selectByIdVo(id); + // 判断result不为空并且result.getPrice不为空 + if (result != null) { + // 查询仓库编码 + String depotCode = result.getArtNo().substring(0, 2); + TDepotVo vo = baseMapper.selectDepotName(userId, depotCode); + if (vo != null) { + result.setDepotName(vo.getName() + vo.getUnit()); + result.setDepotId(vo.getId()); + } + result.setConditionCode(CHINESE_TO_CODE_MAP2.get(result.getConditionCode())); + } + return result; + } + + + /** + * 查询商品信息 + * + * @param isbn 主键 + * @return 商品信息 + */ + @Override + public List getProductByBarcode(String isbn) { + List results = baseMapper.selectShopGoodsByIsbn(isbn); + if (results.isEmpty()) { + + } + return results; + } + + /** + * 查询商品信息 + * + * @param isbn 主键 + * @return 商品信息 + */ + private static final int MAX_RETRIES = 1; + private static final long RETRY_DELAY_MS = 1000; + + @Override + public List getProductByKongfz(String keyword, String searchType, String sortType, String conditionValue, String cookies, String publisher, String author) { + // 记录程序开始时间 + long startTime = System.currentTimeMillis(); + // 创建线程池 + ExecutorService executorService = Executors.newFixedThreadPool(20); + // 获取Cookie的API地址 +// String cookieUrl = "https://test.kongfz.buzhiyushu.cn/api/auth/getCookies/1915230113968467969/18904056801/Long6166@"; + // 调用孔夫子API获取图书信息 + String searchUrl = "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/list"; + Map params = new HashMap<>(); + params.put("searchType", searchType); + params.put("dataType", "0"); + params.put("page", "1"); + params.put("keyword", keyword); + params.put("sortType", sortType); + params.put("quality", conditionValue); + params.put("actionPath", "sortType,quality"); + params.put("quaSelect", "2"); + params.put("userArea", "13003000000"); + if (publisher != null && !publisher.trim().isEmpty()) { + params.put("press", publisher); + } + if (author != null && !author.trim().isEmpty()) { + params.put("author", author); + } + + List productList = new ArrayList<>(); + Exception lastException = null; + + for (int attempt = 0; attempt < MAX_RETRIES; attempt++) { + try { + if (StringUtils.isEmpty(cookies)) { + throw new ServiceException("Cookie数据为空,响应内容:" + cookies); + } + // 将参数编码并拼接到URL + StringBuilder urlWithParams = new StringBuilder(searchUrl); + if (!params.isEmpty()) { + urlWithParams.append("?"); + for (Map.Entry entry : params.entrySet()) { + String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8); + String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8); + urlWithParams.append(encodedKey).append("=").append(encodedValue).append("&"); + } + // 删除末尾多余的"&" + urlWithParams.deleteCharAt(urlWithParams.length() - 1); + } + + + // 设置请求头 + Map headers = new HashMap<>(); + // headers.put("Cookie", "PHPSESSID=" + cookie); + + // 构建HTTP请求 + HttpRequest request = HttpRequest.newBuilder().uri(URI.create(urlWithParams.toString())).header("Cookie", "PHPSESSID=" + cookies).GET() // 显式指定GET方法 + .build(); + // 记录请求开始时间 + long requestStartTime = System.currentTimeMillis(); + // 发送HTTP请求并获取响应 + HttpClient client = HttpClient.newBuilder() + .executor(executorService) // 使用声明的线程池 + .connectTimeout(Duration.ofSeconds(5)) + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.NORMAL) + .proxy(ProxySelector.getDefault()) + .build(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + System.out.println("响应状态码: " + response.statusCode() + "数据" + response); + // 记录请求结束时间 + long requestEndTime = System.currentTimeMillis(); + // 计算请求耗时 + long requestTime = requestEndTime - requestStartTime; + // 打印到控制台 + System.out.println("请求耗时:" + requestTime + "ms"); + + // 打印响应内容,特别是在出错时 + String responseBody = response.body(); +// System.out.println("孔夫子API响应: " + responseBody); + + // 检查状态码,非200状态码可能表示请求失败 + if (response.statusCode() != 200) { + System.err.println("孔夫子API返回非200状态码: " + response.statusCode()); + throw new ServiceException("孔夫子API请求失败,状态码: " + response.statusCode() + ", 响应内容: " + responseBody); + } + + // 检查响应内容中是否包含错误信息 + Map responseMap = JSON.parseObject(responseBody); + if (responseMap != null && responseMap.containsKey("status") && !Integer.valueOf(1).equals(responseMap.get("status"))) { + System.err.println(" 孔夫子API返回错误:" + responseBody); + String errorMessage = responseMap.containsKey("message") ? responseMap.get("message").toString() : "未知错误"; + throw new ServiceException(errorMessage); + } + + // 解析响应JSON + if (responseMap != null && responseMap.get("data") != null) { + Map data = (Map) responseMap.get("data"); + if (data.get("itemResponse") != null) { + Map itemResponse = (Map) data.get("itemResponse"); + List> list = (List>) itemResponse.get("list"); + + // 只取前12条记录 + int limit = Math.min(12, list.size()); + for (int i = 0; i < limit; i++) { + Map item = list.get(i); + KongfzVo productVo = new KongfzVo(); + // 设置ProductVo的属性 + productVo.setName((String) item.get("title")); + productVo.setAuthor((String) item.get("author")); + productVo.setPress((String) item.get("press")); + productVo.setShopName((String) item.get("shopName")); + Object priceObj = item.get("price"); + if (priceObj instanceof Number) { + productVo.setPrice(((Number) priceObj).longValue()); + } + productVo.setImgUrl((String) item.get("imgUrl")); + productVo.setImgBigUrl((String) item.get("imgBigUrl")); + productVo.setPriceText((String) item.get("priceText")); + productVo.setQualityText((String) item.get("qualityText")); + // 关键修复:解析运费信息 + Map postage = (Map) item.get("postage"); + if (postage != null) { + List> shippingList = (List>) postage.get("shippingList"); + if (shippingList != null && !shippingList.isEmpty()) { + // 取第一个运费选项 + Map shipping = shippingList.get(0); + // 处理 shippingFee + Object shippingFeeObj = shipping.get("shippingFee"); + if (shippingFeeObj != null) { + BigDecimal shippingFee = new BigDecimal(shippingFeeObj.toString()); + productVo.setShippingFee(shippingFee); + } + // 处理 shippingFeeText + productVo.setShippingFeeText((String) shipping.get("shippingFeeText")); + } + } + productList.add(productVo); + } + // 记录程序结束时间 + long endTime = System.currentTimeMillis(); + System.out.println("程序运行时间:" + (endTime - startTime) + "毫秒"); + // 关闭线程池 + shutdownAndAwaitTermination(executorService); + return productList; + } + } + + } catch (Exception e) { + lastException = e; + System.err.println("孔夫子API请求失败: " + e.getMessage()); + + if (attempt < MAX_RETRIES - 1) { + try { + Thread.sleep(RETRY_DELAY_MS * (attempt + 1)); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + // 确保在异常情况下也关闭线程池 + shutdownAndAwaitTermination(executorService); + throw new ServiceException("重试过程被中断"); + } + } + } + } + + // 确保在所有重试失败时也关闭线程池 + shutdownAndAwaitTermination(executorService); + // 如果所有重试都失败,抛出最后一次的异常 + throw new ServiceException((lastException != null ? lastException.getMessage() : "未知错误")); + } + + // 添加线程池关闭的辅助方法 + private void shutdownAndAwaitTermination(ExecutorService pool) { + if (pool != null && !pool.isShutdown()) { + pool.shutdown(); // 禁止新任务提交 + try { + // 等待现有任务完成 + if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { + pool.shutdownNow(); // 取消当前执行的任务 + // 等待任务响应关闭操作 + if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { + System.err.println("线程池未能完全终止"); + } + } + } catch (InterruptedException ie) { + // (重新)取消如果当前线程也被中断 + pool.shutdownNow(); + // 保持中断状态 + Thread.currentThread().interrupt(); + } + } + } + + + @Override + public ZhishuShopGoodsVo selectShopGoodsByItemNumber(String itemNumber) { + return baseMapper.selectShopGoodsByItemNumbers(itemNumber); + } + + /** + * 根据货号查询商品 + * + * @param artNo + * @return + */ + @Override + public ZhishuShopGoodsVo selectShopGoodsByArtNo(String artNo) { + return baseMapper.selectShopGoodsByArtNo(artNo); + } + + /** + * 提交商品信息 + * + * @return 商品信息 + */ + @Override + public ProductSubmitResultVo submitProduct(ProductForm form) { + // 书名去除首位空格 + form.setName(form.getName().trim()); + String depotName = form.getDepotName(); + if (StringUtils.isBlank(depotName)) { + throw new IllegalArgumentException("仓库名称不能为空"); + } + + Long userId = sysUserMapper.selectUserIdByNameAndPassWord(form.getPhoneNumber()); + Long depotId = TDepotMapper.getDepotIdByName(depotName, userId); + Long shelvesId = TShelvesMapper.getShelvesIdByName(form.getShelvesName(), depotId); + //获取三级货区信息 + TFreightVo freightVo = TFreightMapper.selectByFreightName(form.getFreightName(), shelvesId); + Long freightId = freightVo.getId(); + // 获取品相数值 + // 中文 + String conCodeTxt = form.getConditionCode(); + // 对应的数值 + String conCode = CnumberUtils.getQualityNum(conCodeTxt); + // 对应的字母 + String letterCode = CnumberUtils.getQualityNum(conCode); + + if (conCode == null) { + throw new IllegalArgumentException("无效的中文品相名称: " + conCode); + } + // 获取货号 + String artNo = cnumberUtils.getArtNo(Double.valueOf(new BigDecimal(conCode).divide(new BigDecimal(10)).toString()), userId, form.getBarcode(), depotId, shelvesId, freightId, form.getSeries()); + // 根据isbn 货号 userid 品相 价格 查询是否存在一样的数据 + long count = baseMapper.selectCountByIsbnAndArtNoAndUserIdAndBarcode(form.getBarcode(), artNo, userId.toString(), letterCode, form.getPrice().toString()); + + ZhishuShopGoods shopGoods = new ZhishuShopGoods(); + + + if (count == 0) { + // 添加库存表 + shopGoods.setIsbn(form.getBarcode()); + shopGoods.setGoodsName(form.getName()); + shopGoods.setUserId(userId); + shopGoods.setPrice(form.getPrice()); + shopGoods.setProductId(""); + shopGoods.setConditionCode(letterCode); + shopGoods.setDepotId(depotId); + shopGoods.setTenantId("000000"); +// shopGoods.setCategoryId(form.getCategoryId()); + if (form.getBarcode().equals("0000000000000")) { + shopGoods.setTemplateType("2"); + } + shopGoods.setFixPrice(form.getFixPrice()); + shopGoods.setInventory(Long.valueOf(0)); + // 根据仓库获取Id + shopGoods.setArtNo(artNo); + shopGoods.setIsJoinDistribution(Integer.parseInt(StringUtils.isNotEmpty(freightVo.getAllowDistribution()) ? freightVo.getAllowDistribution() : "0")); + + baseMapper.insert(shopGoods); + List list = form.getFiles(); + if (list != null && !list.isEmpty()) { + for (FilesVo filesVo : list) { + String url = filesVo.getUrl(); + // 过滤掉临时路径 + if (url == null || url.isEmpty()) { + continue; + } + // 跳过临时文件路径,只保留线上图片 + if (url.startsWith("wxfile://") || + url.startsWith("file://") || + url.startsWith("blob:") || + url.contains("tmp")) { + continue; + } + + // 只插入 https 图片路径 + if (url.startsWith("https://")) { + ZhishuShopImagesBo zhishuShopImagesBo = new ZhishuShopImagesBo(); + zhishuShopImagesBo.setGoodsId(shopGoods.getId()); + zhishuShopImagesBo.setPath(url); + zhishuShopImagesService.insertByBo(zhishuShopImagesBo); + } + } + } + +// List list = form.getFiles(); +// for (FilesVo filesVo : list) { +// ZhishuShopImagesBo zhishuShopImagesBo = new ZhishuShopImagesBo(); +// zhishuShopImagesBo.setGoodsId(shopGoods.getId()); +// zhishuShopImagesBo.setPath(filesVo.getUrl()); +// zhishuShopImagesService.insertByBo(zhishuShopImagesBo); +// } + operatingInventory(1, shopGoods.getId(), Math.toIntExact(form.getInventory()), 4, null, userId); + shopGoods.setInventory(form.getInventory()); + if (form.getBarcode() == null) { + // 增加商品审核 + TBookAudit tBookAudit = new TBookAudit(); + tBookAudit.setGoodsName(form.getName()); + tBookAudit.setIsbn(form.getBarcode()); + tBookAudit.setUserId(userId); + tBookAudit.setProductId(""); + tBookAudit.setArtNo(artNo); + tBookAudit.setPrice(form.getPrice()); + tBookAudit.setFixPrice(form.getFixPrice()); + tBookAudit.setConditionCode(letterCode); + tBookAudit.setInventory(Long.valueOf(form.getInventory())); + tBookAudit.setTenantId("000000"); + tBookAudit.setStatus("2"); + tBookAuditMapper.insert(tBookAudit); + } + } else if (count > 0) { + ZhishuShopGoods existingGoods = baseMapper.selectartNoByIsbnAndConditionCodeAndArtNo(form.getBarcode(), letterCode, artNo, form.getPrice(), userId); + // 价格相同 修改 + long newInventory = existingGoods.getInventory() + form.getInventory(); + shopGoods.setId(existingGoods.getId()); + List list = form.getFiles(); + for (FilesVo filesVo : list) { + ZhishuShopImagesBo zhishuShopImagesBo = new ZhishuShopImagesBo(); + zhishuShopImagesBo.setGoodsId(shopGoods.getId()); + zhishuShopImagesBo.setPath(filesVo.getUrl()); + zhishuShopImagesService.insertByBo(zhishuShopImagesBo); + } + operatingInventory(1, shopGoods.getId(), Math.toIntExact(form.getInventory()), 4, null, userId); + shopGoods.setInventory(newInventory); + tBookAuditMapper.updateInventory(newInventory, userId, letterCode, artNo, form.getPrice(), form.getBarcode()); + } + + + + /** + * 执行孔夫子店铺自动发布商品线程 + */ + //赋值分类 + shopGoods.setCategoryId(form.getCategoryId()); + shopGoods.setDepotId(depotId); + shopGoods.setPrice(form.getPrice()); + TDepotVo depotVo = depotService.queryById(depotId); + TLogisticsVo logisticsVo = logisticsService.queryById(depotVo.getTemplateId()); + if (logisticsVo == null) { + shopGoods.setTemplateMinPrice("0"); + } else { + shopGoods.setTemplateMinPrice(logisticsVo.getFirPrice() == null ? "0" : logisticsVo.getFirPrice().toString()); + } + + System.out.println("shopGoods:" + shopGoods); + TShopDepotAotuMapper tShopDepotAotuMapper = applicationContext.getBean(TShopDepotAotuMapper.class); + KfzAutoAddRunnable kfzAutoAddRunnable = new KfzAutoAddRunnable(userId, + shopService, + shopDetailService, + shopGoodsPublishedService, + kongfzService, + this, + applicationContext, + zhishuShopGoodsDetailService, + shopGoods, + tShopDepotAotuMapper); + Thread thread = new Thread(kfzAutoAddRunnable, "yxy-submitFromCopyrightPage"); + thread.setDaemon(true); // 设置为守护线程 + thread.start(); + // 创建返回对象 + ProductSubmitResultVo result = new ProductSubmitResultVo(); + result.setGoodsId(shopGoods.getId()); + result.setUserId(userId); + result.setDepotId(depotId); + result.setShelvesId(shelvesId); + result.setFreightId(freightId); + result.setArtNo(artNo); + + return result; + } + + + /** + * 上传商品照片 + * + * @param photos 照片文件列表 + * @return 商品信息 + */ + @Override + public void uploadPhotos(MultipartFile[] photos) { + // 确保上传目录存在 + Path uploadPath = Paths.get(UPLOAD_DIR); + if (!Files.exists(uploadPath)) { + try { + Files.createDirectories(uploadPath); + } catch (IOException e) { + throw new RuntimeException("无法创建上传目录", e); + } + } + + // 遍历照片文件并保存 + for (MultipartFile photo : photos) { + if (photo.isEmpty()) { + continue; // 跳过空文件 + } + + try { + // 生成唯一文件名 + String fileName = System.currentTimeMillis() + "_" + photo.getOriginalFilename(); + Path filePath = uploadPath.resolve(fileName); + + // 保存文件 + Files.copy(photo.getInputStream(), filePath); + System.out.println("照片已保存:" + filePath); + } catch (IOException e) { + throw new RuntimeException("照片保存失败", e); + } + } + } + + /** + * 分页查询商品信息列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品信息分页列表 + */ + @Override + public TableDataInfo queryPageList(ZhishuShopGoodsBo bo, PageQuery pageQuery) { + Long userId; + if(bo.getIsQueryAllGoods() != null && bo.getIsQueryAllGoods() == 2){ + bo.setIsJoinDistribution(1); + } + if(bo.getIsQueryAllGoods() == 2 && StringUtils.isNotEmpty(bo.getWarehouseUserId())){ + //修改为单独查一个仓库 + userId = Long.parseLong(bo.getWarehouseUserId()); + bo.setIsQueryAllGoods(1); + }else{ + userId = LoginHelper.getUserId(); + } + + // 小程序传递的userId + if (userId == null) { + // 这里假设bo中有getUserId方法,如果没有需要根据实际情况调整 + if (bo.getUserId() != null) { + userId = bo.getUserId(); + } + } + + bo.setUserId(userId); + // 动态拼接查询条件 + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + + // 获取当前用户id + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + result.getRecords().forEach(item -> { + if (item.getBookPic() == null) { + String path = baseMapper.selectByBookPic(item.getId()); + if (StringUtils.isNotEmpty(path) && !path.contains("wxfile")) { + item.setBookPic(path); + } else { + item.setBookPic(""); + } + } + }); + // 若查询条件不为空构建响应参数 + if (ObjectUtil.isNotEmpty(result.getRecords())) { + // 根据UserId查询用户电话号码 + List userIdList = result.getRecords().stream().map(ZhishuShopGoodsVo::getUserId).distinct().toList(); + Map> userPhoneNumberMap = new LambdaQueryChainWrapper<>(sysUserMapper) + .in(SysUser::getUserId, userIdList) + .list().stream().collect(Collectors.toMap(SysUser::getUserId, user -> { + Map info = new HashMap<>(); + info.put("phonenumber", user.getPhonenumber()); + info.put("warehouseName", user.getWarehouseName() == null ? "" : user.getWarehouseName()); + return info; + })); + // 根据depotId查询仓库名称 + List depotIdList = result.getRecords().stream().map(ZhishuShopGoodsVo::getDepotId).distinct().toList(); + List depotList = new LambdaQueryChainWrapper<>(TDepotMapper).in(TDepot::getId, depotIdList).list(); + Map depotMap = new HashMap<>(); + if (ObjectUtil.isNotEmpty(depotList)) { + for (TDepot tDepot : depotList) { + tDepot.setName(tDepot.getName() + tDepot.getUnit()); + depotMap.put(tDepot.getId(), tDepot); + } + } + List templateIdList = depotList.stream().map(TDepot::getTemplateId).distinct().toList(); + // 根据仓库id查询物流信息 + Map logisticsMap = new HashMap<>(); + if (ObjectUtil.isNotEmpty(templateIdList)) { + List logisticsList = new LambdaQueryChainWrapper<>(tLogisticsMapper).in(TLogistics::getId, templateIdList).list(); + if (ObjectUtil.isNotEmpty(logisticsList)) { + for (TLogistics tLogistics : logisticsList) { + logisticsMap.put(tLogistics.getId(), tLogistics); + } + + } + } + + // 循环赋值 + for (ZhishuShopGoodsVo record : result.getRecords()) { + // 电话打码 + if (ObjectUtil.isNotEmpty(userPhoneNumberMap)) { + Map userMap = userPhoneNumberMap.get(record.getUserId()); + String phoneNumber = userMap.get("phonenumber"); + String warehouseName = userMap.get("warehouseName"); + if (ObjectUtil.isNotEmpty(phoneNumber)) { + String phoneNumberMark = EncryptionUtil.maskPhoneNumber(Long.valueOf(phoneNumber)); + record.setPhoneNumberMark(phoneNumberMark); + } + if (StringUtils.isNotEmpty(warehouseName)){ + record.setWarehouseName(warehouseName); + } + } + // // 商品Id打码 + // if (!userId.equals(record.getUserId())) { + // record.setId(EncryptionUtil.maskString(record.getId())); + // } + record.setUserId(null); + // 品相转换 + record.setConditionCode(CHINESE_TO_CODE_MAP2.get(record.getConditionCode())); + // 价格转换 + // 除于100后保留两位小数 + record.setPrice(record.getPrice()); + if (ObjectUtil.isNotEmpty(depotMap)) { + TDepot tDepot = depotMap.get(record.getDepotId()); + if (ObjectUtil.isNotEmpty(tDepot) && ObjectUtil.isNotNull(tDepot)) { + // 赋值仓库名称 + record.setDepotName(tDepot.getName()); + + // 赋值模板名称,详细地址,最低价格 + if (ObjectUtil.isNotEmpty(logisticsMap)) { + + TLogistics tLogistics = logisticsMap.get(tDepot.getTemplateId()); + if (ObjectUtil.isNotEmpty(tLogistics)) { + // 赋值模板名称 + record.setTemplateName(tLogistics.getTemplateName()); + // 赋值模板Id + record.setTemplateId(tLogistics.getId()); + if (ObjectUtil.isNotEmpty(tLogistics.getShippingRange())) { + // 赋值详细地址 + String split = tLogistics.getDeliveryAddress().split("/")[0]; + record.setDeliveryAddress(split); + // 赋值最低价格 + ObjectMapper objectMapper = new ObjectMapper(); + + // 将 JSON 转换为 Map> + Map> regionMap = null; + try { + regionMap = objectMapper.readValue(tLogistics.getShippingRange(), Map.class); + } catch (JsonProcessingException e) { + throw new ServiceException("解析模板运送范围失败", 555); + } + if (ObjectUtil.isNotEmpty(regionMap)) { + List priceList = new ArrayList<>(); + // 遍历 Map 并修改每个列表中的第二个元素 + for (Map.Entry> entry : regionMap.entrySet()) { + List list = entry.getValue(); + String strValue = String.valueOf(list.get(1)); + priceList.add(new BigDecimal(strValue)); + } + BigDecimal minPrice = Collections.min(priceList); + record.setPricingMethod(tLogistics.getPricingMethod()); + record.setTemplateMinPrice(minPrice); + } + } + + } + } + } + + } + + } + } + return TableDataInfo.build(result); + } + + + public Page queryPageList2(ZhishuShopGoodsBo bo, PageQuery pageQuery) { + // 动态拼接查询条件 + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + // 获取当前用户id + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + + // 若查询条件不为空构建响应参数 + if (ObjectUtil.isNotEmpty(result.getRecords())) { + // 根据UserId查询用户电话号码 + List userIdList = result.getRecords().stream().map(ZhishuShopGoodsVo::getUserId).distinct().toList(); + Map userPhoneNumberMap = new LambdaQueryChainWrapper<>(sysUserMapper) + .in(SysUser::getUserId, userIdList) + .list().stream().collect(Collectors.toMap(SysUser::getUserId, SysUser::getPhonenumber)); + // 根据depotId查询仓库名称 + List depotIdList = result.getRecords().stream().map(ZhishuShopGoodsVo::getDepotId).distinct().toList(); + List depotList = new LambdaQueryChainWrapper<>(TDepotMapper).in(TDepot::getId, depotIdList).list(); + Map depotMap = new HashMap<>(); + if (ObjectUtil.isNotEmpty(depotList)) { + for (TDepot tDepot : depotList) { + tDepot.setName(tDepot.getName() + tDepot.getUnit()); + depotMap.put(tDepot.getId(), tDepot); + } + } + List templateIdList = depotList.stream().map(TDepot::getTemplateId).distinct().toList(); + // 根据仓库id查询物流信息 + Map logisticsMap = new HashMap<>(); + if (ObjectUtil.isNotEmpty(templateIdList)) { + List logisticsList = new LambdaQueryChainWrapper<>(tLogisticsMapper).in(TLogistics::getId, templateIdList).list(); + if (ObjectUtil.isNotEmpty(logisticsList)) { + for (TLogistics tLogistics : logisticsList) { + logisticsMap.put(tLogistics.getId(), tLogistics); + } + + } + } + + // 循环赋值 + for (ZhishuShopGoodsVo record : result.getRecords()) { + // 电话打码 + if (ObjectUtil.isNotEmpty(userPhoneNumberMap)) { + String phoneNumber = userPhoneNumberMap.get(record.getUserId()); + if (ObjectUtil.isNotEmpty(phoneNumber)) { + String phoneNumberMark = EncryptionUtil.maskPhoneNumber(Long.valueOf(phoneNumber)); + record.setPhoneNumberMark(phoneNumberMark); + } + } + record.setUserId(null); + // 品相转换 + record.setConditionCode(CHINESE_TO_CODE_MAP2.get(record.getConditionCode())); + // 价格转换 + // 除于100后保留两位小数 + record.setPrice(record.getPrice()); + if (ObjectUtil.isNotEmpty(depotMap)) { + TDepot tDepot = depotMap.get(record.getDepotId()); + if (ObjectUtil.isNotEmpty(tDepot) && ObjectUtil.isNotNull(tDepot)) { + // 赋值仓库名称 + record.setDepotName(tDepot.getName()); + + // 赋值模板名称,详细地址,最低价格 + if (ObjectUtil.isNotEmpty(logisticsMap)) { + + TLogistics tLogistics = logisticsMap.get(tDepot.getTemplateId()); + if (ObjectUtil.isNotEmpty(tLogistics)) { + // 赋值模板名称 + record.setTemplateName(tLogistics.getTemplateName()); + // 赋值模板Id + record.setTemplateId(tLogistics.getId()); + if (ObjectUtil.isNotEmpty(tLogistics.getShippingRange())) { + // 赋值详细地址 + String split = tLogistics.getDeliveryAddress().split("/")[0]; + record.setDeliveryAddress(split); + // 赋值最低价格 + ObjectMapper objectMapper = new ObjectMapper(); + + // 将 JSON 转换为 Map> + Map> regionMap = null; + try { + regionMap = objectMapper.readValue(tLogistics.getShippingRange(), Map.class); + } catch (JsonProcessingException e) { + throw new ServiceException("解析模板运送范围失败", 555); + } + if (ObjectUtil.isNotEmpty(regionMap)) { + List priceList = new ArrayList<>(); + // 遍历 Map 并修改每个列表中的第二个元素 + for (Map.Entry> entry : regionMap.entrySet()) { + List list = entry.getValue(); + String strValue = String.valueOf(list.get(1)); + priceList.add(new BigDecimal(strValue)); + } + BigDecimal minPrice = Collections.min(priceList); + record.setPricingMethod(tLogistics.getPricingMethod()); + record.setTemplateMinPrice(minPrice); + } + } + + } + } + } + + } + + } + } + return result; + } + + /** + * 查询符合条件的商品信息列表 + * + * @param bo 查询条件 + * @return 商品信息列表 + */ + @Override + public List queryList(ZhishuShopGoodsBo bo) { + if (bo.getUserId() == null){ + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + } + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + List list = baseMapper.selectVoList(lqw); + // 若查询条件不为空构建响应参数 + if (ObjectUtil.isNotEmpty(list)) { + // 根据depotId查询仓库名称 + List depotIdList = list.stream().map(ZhishuShopGoodsVo::getDepotId).distinct().toList(); + List depotList = new LambdaQueryChainWrapper<>(TDepotMapper).in(TDepot::getId, depotIdList).list(); + Map depotNameMap = depotList.stream().collect(Collectors.toMap(TDepot::getId, TDepot::getName)); + List templateIdList = depotList.stream().map(TDepot::getTemplateId).distinct().toList(); + // 根据仓库id查询物流信息 + Map logisticsMap = new HashMap<>(); + if (ObjectUtil.isNotEmpty(templateIdList)) { + List logisticsList = new LambdaQueryChainWrapper<>(tLogisticsMapper).in(TLogistics::getId, templateIdList).list(); + if (ObjectUtil.isNotEmpty(logisticsList)) { + for (TLogistics tLogistics : logisticsList) { + logisticsMap.put(tLogistics.getWarehouseId(), tLogistics); + } + } + } + + // 循环赋值 + for (ZhishuShopGoodsVo record : list) { + // 品相转换 + record.setConditionCode(CHINESE_TO_CODE_MAP2.get(record.getConditionCode())); + // 价格转换 + record.setPrice(record.getPrice().divide(new BigDecimal(100))); + + // 赋值仓库名称 + if (ObjectUtil.isNotEmpty(depotNameMap)) { + record.setDepotName(depotNameMap.get(record.getDepotId())); + } + // 赋值模板名称,详细地址,最低价格 + if (ObjectUtil.isNotEmpty(logisticsMap)) { + TLogistics tLogistics = logisticsMap.get(record.getDepotId()); + if (ObjectUtil.isNotEmpty(tLogistics)) { + // 赋值模板名称 + record.setTemplateName(tLogistics.getTemplateName()); + // 赋值模板Id + record.setTemplateId(tLogistics.getId()); + if (ObjectUtil.isNotEmpty(tLogistics.getShippingRange())) { + // 赋值详细地址 + record.setDeliveryAddress(tLogistics.getDeliveryAddress()); + // 赋值最低价格 + ObjectMapper objectMapper = new ObjectMapper(); + + // 将 JSON 转换为 Map> + Map> regionMap = null; + try { + regionMap = objectMapper.readValue(tLogistics.getShippingRange(), Map.class); + } catch (JsonProcessingException e) { + throw new ServiceException("解析模板运送范围失败", 555); + } + if (ObjectUtil.isNotEmpty(regionMap)) { + List priceList = new ArrayList<>(); + // 遍历 Map 并修改每个列表中的第二个元素 + for (Map.Entry> entry : regionMap.entrySet()) { + List regionMaplist = entry.getValue(); + priceList.add(new BigDecimal(regionMaplist.get(2))); + } + BigDecimal minPrice = Collections.min(priceList); + record.setPricingMethod(tLogistics.getPricingMethod()); + record.setTemplateMinPrice(minPrice); + } + } + + } + } + } + } + return list; + } + + private LambdaQueryWrapper buildQueryWrapper(ZhishuShopGoodsBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByDesc(ZhishuShopGoods::getCreateTime); +// lqw.orderByAsc(ZhishuShopGoods::getId); + // 若不是查询所有商品,则拼接用id过滤 + if (IsQueryAllGoodsEnum.NO.getCode().equals(bo.getIsQueryAllGoods())) { + // 用户Id + lqw.eq(ObjectUtil.isNotEmpty(bo.getUserId()), ZhishuShopGoods::getUserId, bo.getUserId()); + } else { + // 查询所有商品 + lqw.and(wrapper -> wrapper + .eq(ObjectUtil.isNotEmpty(bo.getUserId()), ZhishuShopGoods::getUserId, bo.getUserId()) + .or() + .eq(ZhishuShopGoods::getIsJoinDistribution, IsJoinDistributionEnum.YES.getCode())); + } + // 是否分销 + lqw.eq(ObjectUtil.isNotEmpty(bo.getIsJoinDistribution()), ZhishuShopGoods::getIsJoinDistribution, bo.getIsJoinDistribution()); + // 管理员可以查看所有数据 + // if (bo.getUserId() != null && !Long.valueOf(1).equals(bo.getUserId())) { + // lqw.eq(ZhishuShopGoods::getUserId, bo.getUserId()); + // } + // 商品名称 + lqw.like(StringUtils.isNotBlank(bo.getGoodsName()), ZhishuShopGoods::getGoodsName, bo.getGoodsName()); + // 货号 + lqw.like(StringUtils.isNotBlank(bo.getArtNo()), ZhishuShopGoods::getArtNo, bo.getArtNo()); + + + // 图片是否为空 + if (ObjectUtil.isNotNull(bo.getIsBookPicNull())) { + List zhishuShopImages = baseMapper.selectImages(); +// 2. 根据查询条件处理 + if (bo.getIsBookPicNull() == 0) { + // 情况1:要求无图(记录不存在或path为空) + if (!zhishuShopImages.isEmpty()) { + // 排除fistImage中有图片路径的 + List goodsIds = zhishuShopImages.stream() + .filter(image -> StringUtils.isNotEmpty(image.getPath())) + .map(ZhishuShopImages::getGoodsId) + .toList(); + lqw.notIn(ZhishuShopGoods::getId, goodsIds); + } else { + lqw.eq(ZhishuShopGoods::getId, -1); + } + } else { + // 情况2:要求有图(path不为空) + if (!zhishuShopImages.isEmpty()) { + List goodsIds = zhishuShopImages.stream() + .filter(image -> StringUtils.isNotEmpty(image.getPath())) + .map(ZhishuShopImages::getGoodsId) + .toList(); + lqw.in(ZhishuShopGoods::getId, goodsIds); + } else { + lqw.eq(ZhishuShopGoods::getId, -1); + } + } + } + + + // 原始货号 + lqw.like(StringUtils.isNotBlank(bo.getOriginalArtNo()), ZhishuShopGoods::getOriginalArtNo, bo.getOriginalArtNo()); + + if (StringUtils.isNotEmpty(bo.getMinprice()) && bo.getMaxprice() != null) { + String operator = bo.getMinprice(); + Long price = new BigDecimal(bo.getMaxprice()).multiply(new BigDecimal(100)).longValue(); + switch (operator) { + case "=": + lqw.eq(ZhishuShopGoods::getPrice, price); + break; + case ">": + lqw.gt(ZhishuShopGoods::getPrice, price); // 使用 gt 而不是 ge + break; + case ">=": + lqw.ge(ZhishuShopGoods::getPrice, price); + break; + case "<": + lqw.lt(ZhishuShopGoods::getPrice, price); // 使用 lt 而不是 le + break; + case "<=": + lqw.le(ZhishuShopGoods::getPrice, price); + break; + default: + break; + } + } + +// // 最低价格 +// Optional.ofNullable(bo.getMinprice()).map(price -> price * 100).ifPresent(value -> lqw.ge(ZhishuShopGoods::getPrice, value)); +// // 最高价格 +// Optional.ofNullable(bo.getMaxprice()).map(price -> price * 100).ifPresent(value -> lqw.le(ZhishuShopGoods::getPrice, value)); +// // 最低库存 +// lqw.ge(ObjectUtil.isNotNull(bo.getMininventory()), ZhishuShopGoods::getInventory, bo.getMininventory()); +// // 最高库存 +// lqw.le(ObjectUtil.isNotNull(bo.getMaxinventory()), ZhishuShopGoods::getInventory, bo.getMaxinventory()); + + if (StringUtils.isNotEmpty(bo.getMininventory()) && bo.getMaxinventory() != null) { + String operator = bo.getMininventory(); + Long inventory = bo.getMaxinventory(); + switch (operator) { + case "=": + lqw.eq(ZhishuShopGoods::getInventory, inventory); + break; + case ">": + lqw.gt(ZhishuShopGoods::getInventory, inventory); // 使用 gt 而不是 ge + break; + case ">=": + lqw.ge(ZhishuShopGoods::getInventory, inventory); + break; + case "<": + lqw.lt(ZhishuShopGoods::getInventory, inventory); // 使用 lt 而不是 le + break; + case "<=": + lqw.le(ZhishuShopGoods::getInventory, inventory); + break; + default: + break; + } + } + + + // 商品编号 + lqw.eq(StringUtils.isNotBlank(bo.getItemNumber()), ZhishuShopGoods::getProductId, bo.getItemNumber()); + + // ISBN + if (StringUtils.isNotBlank(bo.getIsbn()) || bo.getIsExistIsbn() != null) { + if (bo.getIsExistIsbn() != null) { + if (bo.getIsExistIsbn() == 0) { + // 情况1:isExistIsbn=0 + if (StringUtils.isNotBlank(bo.getIsbn())) { + if (bo.getIsbn().startsWith("678")) { + lqw.likeRight(ZhishuShopGoods::getIsbn, bo.getIsbn()); + } else { + // 不符合678开头的条件,返回空结果 + lqw.eq(ZhishuShopGoods::getId, -1); + } + } else { + // 默认查询678开头的记录 + lqw.likeRight(ZhishuShopGoods::getIsbn, "678"); + } + } else { + // 情况2:isExistIsbn=1,查询不以678开头的记录 + lqw.notLikeRight(ZhishuShopGoods::getIsbn, "0") + .notLikeRight(ZhishuShopGoods::getIsbn, "1") + .notLikeRight(ZhishuShopGoods::getIsbn, "4") + .notLikeRight(ZhishuShopGoods::getIsbn, "5") + .notLikeRight(ZhishuShopGoods::getIsbn, "6") + .notLikeRight(ZhishuShopGoods::getIsbn, "8") + .eq(StringUtils.isNotBlank(bo.getIsbn()), ZhishuShopGoods::getIsbn, bo.getIsbn()); + } + } else { + // 情况3:isExistIsbn=null,精确查询 + lqw.eq(ZhishuShopGoods::getIsbn, bo.getIsbn()); + } + } + + // 品相 + if (StringUtils.isNotBlank(bo.getConditionCode())) { +// String conditionCode = CHINESE_TO_CODE_MAP1.get(bo.getConditionCode()); +// Assert.isTrue(ObjectUtil.isNotEmpty(conditionCode), "没有对应品级"); + lqw.eq(ZhishuShopGoods::getConditionCode, bo.getConditionCode()); + } + // 仓库名称 仓库Id + if (ObjectUtil.isNotNull(bo.getDepotId()) || ObjectUtil.isNotEmpty(bo.getDepotName())) { + + + + List depotList = new LambdaQueryChainWrapper<>(TDepotMapper).eq(ObjectUtil.isNotNull(bo.getDepotId()), TDepot::getId, bo.getDepotId()).like(ObjectUtil.isNotEmpty(bo.getDepotName()), TDepot::getName, bo.getDepotName()).list(); + if (ObjectUtil.isNotEmpty(depotList)) { + List depotIds = depotList.stream().map(TDepot::getId).toList(); + lqw.in(ZhishuShopGoods::getDepotId, depotIds); + } + } + // 模板名称 模板Id 详细地址 + if (ObjectUtil.isNotNull(bo.getTemplateId()) || ObjectUtil.isNotEmpty(bo.getTemplateName())) { + List logisticsList = new LambdaQueryChainWrapper<>(tLogisticsMapper).eq(ObjectUtil.isNotNull(bo.getTemplateId()), TLogistics::getId, bo.getTemplateId()).like(ObjectUtil.isNotEmpty(bo.getTemplateName()), TLogistics::getTemplateName, bo.getTemplateName()).like(ObjectUtil.isNotEmpty(bo.getAddress()), TLogistics::getDeliveryAddress, bo.getAddress()).list(); + if (ObjectUtil.isNotEmpty(logisticsList)) { + List warehouseId = logisticsList.stream().map(TLogistics::getWarehouseId).toList(); + lqw.in(ZhishuShopGoods::getDepotId, warehouseId); + } + } + + + // 货区ids列表 + if (ObjectUtil.isNotEmpty(bo.getCargoAreaIds())) { + Integer cargoAreaId = bo.getCargoAreaIds().size(); + ArrayList ids = new ArrayList<>(); + List zhishuShopGoodsList = new LambdaQueryChainWrapper<>(baseMapper).eq(ObjectUtil.isNotNull(bo.getCargoAreaIds()), ZhishuShopGoods::getDepotId, bo.getCargoAreaIds().get(0)).list(); + if (ObjectUtil.isNotEmpty(zhishuShopGoodsList)) { + List depotList = new LambdaQueryChainWrapper<>(TDepotMapper).eq(ObjectUtil.isNotNull(bo.getCargoAreaIds()), TDepot::getId, bo.getCargoAreaIds().get(0)).list(); + if (ObjectUtil.isNotEmpty(depotList)) { + if (cargoAreaId == 1) { + List depotIds = depotList.stream().map(TDepot::getId).toList(); + lqw.in(ZhishuShopGoods::getDepotId, depotIds); + } else if (cargoAreaId == 2) { + List shelvesList = new LambdaQueryChainWrapper<>(TShelvesMapper).eq(ObjectUtil.isNotNull(bo.getCargoAreaIds()), TShelves::getId, bo.getCargoAreaIds().get(1)).list(); + if (ObjectUtil.isNotEmpty(shelvesList)) { + // 获取depotList中的code + List depotCodes = depotList.stream().map(TDepot::getCode).toList(); + // 获取shelvesList中的code + List sheCodes = shelvesList.stream().map(TShelves::getCode).toList(); + String depotCode = depotCodes.get(0) + sheCodes.get(0); + // 判断zhishuShopGoodsList中的artNo的前缀是否包含depotCode + for (ZhishuShopGoods item : zhishuShopGoodsList) { + if (item.getArtNo().startsWith(depotCode)) { + ids.add(item.getId()); + } + } + if (ids.isEmpty()) { + lqw.eq(ZhishuShopGoods::getDepotId, -1); + } else { + lqw.in(ZhishuShopGoods::getId, ids); + } + } else { + lqw.eq(ZhishuShopGoods::getDepotId, -1); + } + } else if (cargoAreaId == 3) { + List shelvesList = new LambdaQueryChainWrapper<>(TShelvesMapper).eq(ObjectUtil.isNotNull(bo.getCargoAreaIds()), TShelves::getId, bo.getCargoAreaIds().get(1)).list(); + List freightList = new LambdaQueryChainWrapper<>(TFreightMapper).eq(ObjectUtil.isNotNull(bo.getCargoAreaIds()), TFreight::getId, bo.getCargoAreaIds().get(2)).list(); + if (ObjectUtil.isNotEmpty(shelvesList) && ObjectUtil.isNotEmpty(freightList)) { + // 获取depotList中的code + List depotCodes = depotList.stream().map(TDepot::getCode).toList(); + // 获取shelvesList中的code + List sheCodes = shelvesList.stream().map(TShelves::getCode).toList(); + // 获取freightList中的code + List freCodes = freightList.stream().map(TFreight::getCode).toList(); + String depotCode = depotCodes.get(0) + sheCodes.get(0) + freCodes.get(0); + // 判断zhishuShopGoodsList中的artNo的前缀是否包含depotCode + for (ZhishuShopGoods item : zhishuShopGoodsList) { + if (item.getArtNo().startsWith(depotCode)) { + ids.add(item.getId()); + } + } + if (ids.isEmpty()) { + lqw.eq(ZhishuShopGoods::getDepotId, -1); + } else { + lqw.in(ZhishuShopGoods::getId, ids); + } + } else { + lqw.eq(ZhishuShopGoods::getDepotId, -1); + } + } + } else { + lqw.eq(ZhishuShopGoods::getDepotId, -1); + } + } else { + lqw.eq(ZhishuShopGoods::getDepotId, -1); + } + } + + // 发货地址 + if (ObjectUtil.isNotNull(bo.getAddress())) { + List logisticsList = new LambdaQueryChainWrapper<>(tLogisticsMapper).eq(ObjectUtil.isNotNull(bo.getAddress()), TLogistics::getDeliveryProvince, bo.getAddress()).list(); + if (ObjectUtil.isNotEmpty(logisticsList)) { + List depotIds = new ArrayList<>(); + for (TLogistics item : logisticsList) { + List depotList = new LambdaQueryChainWrapper<>(TDepotMapper) + .eq(TDepot::getTemplateId, item.getId()) + .list(); + depotIds.addAll(depotList.stream().map(TDepot::getId).toList()); + } + + if (ObjectUtil.isNotEmpty(depotIds)) { + lqw.in(ZhishuShopGoods::getDepotId, depotIds); + } else { + // 如果没有匹配的仓库,直接返回空结果 + lqw.eq(ZhishuShopGoods::getId, -1); + } + } else { + // 如果没有匹配的物流信息,直接返回空结果 + lqw.eq(ZhishuShopGoods::getId, -1); + } + } + + // 添加入库时间比较 + if (ObjectUtil.isNotNull(bo.getStartTime()) && ObjectUtil.isNotNull(bo.getEndTime())) { + lqw.between(ZhishuShopGoods::getCreateTime, bo.getStartTime(), bo.getEndTime()); + } else if (ObjectUtil.isNotNull(bo.getStartTime())) { + // 只有开始时间,查询该时间之后的数据 + lqw.ge(ZhishuShopGoods::getCreateTime, bo.getStartTime()); + } else if (ObjectUtil.isNotNull(bo.getEndTime())) { + // 只有结束时间,查询该时间之前的数据 + lqw.le(ZhishuShopGoods::getCreateTime, bo.getEndTime()); + } + + + return lqw; + } + + + public static final Map CHINESE_TO_CODE_MAP2 = IntStream.range(0, CHINESE_CODE.length).boxed().collect(Collectors.toMap(i -> CONDITION_CODE[i], // 值:字母标识(如"A") + i -> CHINESE_CODE[i], // 键:中文标识(如"一品") + (oldVal, newVal) -> oldVal, LinkedHashMap::new // 保持插入顺序 + )); + + /** + * 新增商品信息 + * + * @param bo 商品信息 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ZhishuShopGoodsBo bo) { + validEntityBeforeSave(bo); + ZhishuShopGoods add = MapstructUtils.convert(bo, ZhishuShopGoods.class); + Long userId = LoginHelper.getUserId(); + add.setUserId(userId); + add.setProductId(""); +// if (add.getFixPrice() != null) { +// add.setFixPrice(add.getFixPrice() * 100); +// } +// if (add.getPrice() != null) { +// add.setPrice(add.getPrice() * 100); +// } + add.setConditionCode(CHINESE_TO_CODE_MAP1.get(add.getConditionCode())); + Double s = convertChineseToCode(bo.getConditionCode()); + List sheCount = baseMapper.selectSheCount(bo.getDepotId()); + if (sheCount.size() == 0) { + throw new RuntimeException("二级货区不存在,请先创建二级货区"); + } + List freCount = baseMapper.selectFreCount1(sheCount); + if (freCount.size() == 0) { + throw new RuntimeException("三级货区不存在,请创建三级货区"); + } + Map map = new HashMap<>(); + sheCount.forEach(she -> { + // 跳过无效code长度(非1位或2位) + if (she.getCode().length() != 1 && she.getCode().length() != 2) { + return; // 在forEach中相当于continue + } + List tFreight = baseMapper.selectBySId(she.getId()); + if (tFreight == null) { + return; // 跳过空数据 + } + for (int i = 0; i < tFreight.size(); i++) { + if (tFreight.get(i).getCode() == null) { + return; // 跳过空数据 + } + // 核心匹配逻辑 + if ((she.getCode().length() == 2 && tFreight.get(i).getCode().length() == 1) || (she.getCode().length() == 1 && tFreight.get(i).getCode().length() == 2)) { + map.put(tFreight.get(i).getId(), she.getId()); + } + } + }); + if (map.isEmpty()) { + return false; + } + Long sheId = null; + Long freId = null; + // 1. 转换为可随机访问的Entry集合 + List> entries = new ArrayList<>(map.entrySet()); + // 2. 线程安全随机选择(Java 8+) + if (!entries.isEmpty()) { + Map.Entry randomEntry = entries.get(ThreadLocalRandom.current().nextInt(entries.size())); + freId = randomEntry.getKey(); + sheId = randomEntry.getValue(); + } + + + String artNo = cnumberUtils.getArtNo(s, userId, bo.getIsbn(), bo.getDepotId(), sheId, freId, null); + add.setArtNo(artNo); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + + // @Override + public void insertByBo1(ZhishuShopGoodsBo bo,String type) { + validEntityBeforeSave(bo); + ZhishuShopGoods add = MapstructUtils.convert(bo, ZhishuShopGoods.class); + add.setConditionCode(CHINESE_TO_CODE_MAP1.get(add.getConditionCode())); + add.setPrice(add.getPrice() * 100); + if (add.getIsbn() == null) { + boolean flag = baseMapper.insert(add) > 0; + } else { + add.setProductId(""); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + } + + //修改成功后,记录自营书品库存修改表 + StockChangeLog stockChangeLog = new StockChangeLog(); + stockChangeLog.setShopGoodsId(Long.parseLong(add.getId())); + //类型 2-订单减扣 3-退单添加 + stockChangeLog.setType(Integer.parseInt(type)); + stockChangeLog.setAboutId("0"); + stockChangeLog.setBeforeInv(0L); + stockChangeLog.setAfterInv(bo.getInventory()); + stockChangeLog.setCreateBy(bo.getUserId()); + stockChangeLog.setUpdateBy(bo.getUserId()); + stockChangeLog.setCreateTime(DateUtils.getNowDate()); + stockChangeLog.setUpdateTime(DateUtils.getNowDate()); + stockChangeLog.setDelFlag("0"); + stockChangeLogMapper.insert(stockChangeLog); + } + + public void insertByBo2(ZhishuShopGoodsBo bo, List zhishuShopGoodsList, + List stockChangeLogList, List zhishuShopImagesList, + String accessToken,Long taskId,Long shopId) { +// validEntityBeforeSave(bo); + //查询当前货号是否在自营书品已经存在 + ZhishuShopGoodsVo zhishuShopGoodsVo = selectShopGoodsByArtNo(bo.getArtNo()); + if(zhishuShopGoodsVo == null){ + ZhishuShopGoods add = MapstructUtils.convert(bo, ZhishuShopGoods.class); + add.setTaskId(taskId); + add.setConditionCode(CHINESE_TO_CODE_MAP1.get(add.getConditionCode())); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + // 获取pdd图片 + bo.setId(add.getId()); + // 增加图片 + if (ObjectUtil.isNotEmpty(add.getBookPic())) { + ZhishuShopImages zhishuShopImages = new ZhishuShopImages(); + zhishuShopImages.setGoodsId(add.getId()); + zhishuShopImages.setPath(add.getBookPic()); + zhishuShopImages.setCreateBy(add.getUserId()); + zhishuShopImages.setUpdateBy(add.getUserId()); + zhishuShopImages.setCreateTime(DateUtils.getNowDate()); + zhishuShopImages.setUpdateTime(DateUtils.getNowDate()); + zhishuShopImages.setDelFlag("0"); + zhishuShopImagesList.add(zhishuShopImages); + } + // 增加库存操作日志 + StockChangeLog stockChangeLog = new StockChangeLog(); + stockChangeLog.setShopGoodsId(Long.valueOf(add.getId())); + stockChangeLog.setType(5); + // 孔网拉取的数据初始库存为0 + stockChangeLog.setBeforeInv(0L); + stockChangeLog.setAfterInv((long) add.getInventory()); + stockChangeLog.setCreateBy(add.getUserId()); + stockChangeLog.setUpdateBy(add.getUserId()); + stockChangeLog.setCreateTime(DateUtils.getNowDate()); + stockChangeLog.setUpdateTime(DateUtils.getNowDate()); + stockChangeLog.setDelFlag("0"); + // 增加库存操作日志 + stockChangeLog.setAfterInv((long) add.getInventory()); + stockChangeLogList.add(stockChangeLog); + // todo 新增已发布商品记录 + ShopGoodsPublishedBo shopGoodsPublishedBo = new ShopGoodsPublishedBo(); + shopGoodsPublishedBo.setShopId(shopId+""); + shopGoodsPublishedBo.setShopGoodsId(add.getId()); + shopGoodsPublishedBo.setPlatformId(bo.getProductId()); + shopGoodsPublishedBo.setCreateBy(add.getUserId()); + shopGoodsPublishedBo.setCreateTime(DateUtils.getNowDate()); + shopGoodsPublishedService.insertByBo(shopGoodsPublishedBo); + zhishuShopGoodsList.add(add); + } + }else{ + //已存在自营书品,校验已发布商品是否存在记录 + ShopGoodsPublishedVo shopGoodsPublishedVo = shopGoodsPublishedService.queryByShopIdAndShopGoodsId(shopId+"",zhishuShopGoodsVo.getId()); + if(shopGoodsPublishedVo == null){ + //如果为空代表没有已发布商品记录,新增记录 + ShopGoodsPublishedBo shopGoodsPublishedBo = new ShopGoodsPublishedBo(); + shopGoodsPublishedBo.setShopId(shopId+""); + shopGoodsPublishedBo.setShopGoodsId(zhishuShopGoodsVo.getId()); + shopGoodsPublishedBo.setPlatformId(bo.getProductId()); + shopGoodsPublishedBo.setCreateBy(zhishuShopGoodsVo.getUserId()); + shopGoodsPublishedBo.setCreateTime(DateUtils.getNowDate()); + shopGoodsPublishedService.insertByBo(shopGoodsPublishedBo); + } + } + } + + private String fullBookPic(ZhishuShopGoods add) { + // 获取md5加密的32位首位小写字母 + String md5 = DigestUtils.md5Hex(add.getGoodsName()); + String substring = md5.substring(0, 1); + return String.format("https://book.center.image.buzhiyushu.cn/%s/%s%s", substring, add.getIsbn(), "_s_01.jpg"); + } + + + @Transactional(rollbackFor = Exception.class) + public Boolean insertListGoods(ZhishuShopGoods add) { + Long message = baseMapper.findBookMsgByISBN(add); + if (message == 0) { + // Integer Inventory = baseMapper.selectGoods(add); + // if(Inventory!=0){ + // add.setInventory(add.getInventory() + Inventory); + // baseMapper.updateBook(add); + // }else { + Integer msg = baseMapper.setExamineBook(add); + System.out.println(msg); + } + return true; + // }else{ + // return false; + } + + // } + + + private String callApi(String apiUrl) throws Exception { + URL url = new URL(apiUrl); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Accept", "application/json"); + conn.setInstanceFollowRedirects(true); // 自动跟随重定向 + + if (conn.getResponseCode() != 200) { + throw new RuntimeException("HTTP error code : " + conn.getResponseCode()); + } + + BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream()))); + StringBuilder response = new StringBuilder(); + String output; + while ((output = br.readLine()) != null) { + response.append(output); + } + conn.disconnect(); + + return response.toString(); + } + + private String parseBookName(String jsonResponse) throws Exception { + ObjectMapper mapper = new ObjectMapper(); + JsonNode root = mapper.readTree(jsonResponse); + + // 解析出 book_name + JsonNode dataNode = root.path("data"); + if (dataNode.isMissingNode()) { + throw new RuntimeException("Data field not found in response"); + } + + JsonNode bookNameNode = dataNode.path("book_name"); + if (bookNameNode.isMissingNode()) { + throw new RuntimeException("book_name field not found in data"); + } + + return bookNameNode.asText(); + } + + public Boolean insertByBo(List bo, Long userId,String type) { + for (ZhishuShopGoodsBo goodsBo : bo) { + // 检查书名是否为null,如果是则根据ISBN搜索 + if (goodsBo.getGoodsName() == null && goodsBo.getIsbn() != null && !goodsBo.getIsbn().isEmpty()) { + String apiUrl = "https://book.center.yushutx.com/api/es/searchByISBN?isbn=" + goodsBo.getIsbn(); + try { + String response = callApi(apiUrl); + String bookName = parseBookName(response); + goodsBo.setGoodsName(bookName); + } catch (Exception e) { + // 异常处理,可以根据实际情况调整 + log.error("Error searching book by ISBN: {}", e.getMessage()); + } + } + + // 将ZhishuShopGoodsBo数据 转换为到ZhishuShopGoods数据 + Integer isJoinDistribution = goodsBo.getIsJoinDistribution() == null ? this.parseShipmentId(userId.toString(), goodsBo.getArtNo().substring(0, 5)) : goodsBo.getIsJoinDistribution(); + + + ZhishuShopGoods zhishuShopGoods = MapstructUtils.convert(goodsBo, ZhishuShopGoods.class); + zhishuShopGoods.setUserId(userId); + zhishuShopGoods.setConditionCode(CHINESE_TO_CODE_MAP1.get(zhishuShopGoods.getConditionCode())); + zhishuShopGoods.setPrice(zhishuShopGoods.getPrice() * 100); + zhishuShopGoods.setIsJoinDistribution(isJoinDistribution); + if (zhishuShopGoods.getPrice() != null) { + zhishuShopGoods.setFixPrice(zhishuShopGoods.getPrice() * 100); + } + ZhishuShopGoodsVo zhishuShopGoodsVo = baseMapper.selectShopGoodsByItemNumber1(zhishuShopGoods); + zhishuShopGoods.setUserId(userId); + if (zhishuShopGoodsVo != null ) { + Long Inventory = Long.parseLong(zhishuShopGoodsVo.getInventory()); + Long oldInventory = Inventory; + Long newInventory = Inventory + zhishuShopGoods.getInventory(); + // 商品存在 + zhishuShopGoods.setInventory(newInventory); + Integer a = baseMapper.updateByProduct(zhishuShopGoods); + // 添加日志 + //修改成功后,记录自营书品库存修改表 + StockChangeLog stockChangeLog = new StockChangeLog(); + stockChangeLog.setShopGoodsId(Long.parseLong(zhishuShopGoodsVo.getId())); + //类型 2-订单减扣 3-退单添加 + stockChangeLog.setType(Integer.parseInt(type)); + stockChangeLog.setAboutId("0"); + stockChangeLog.setBeforeInv(oldInventory); + stockChangeLog.setAfterInv(newInventory); + stockChangeLog.setCreateBy(zhishuShopGoods.getUserId()); + stockChangeLog.setUpdateBy(zhishuShopGoods.getUserId()); + stockChangeLog.setCreateTime(DateUtils.getNowDate()); + stockChangeLog.setUpdateTime(DateUtils.getNowDate()); + stockChangeLog.setDelFlag("0"); + stockChangeLogMapper.insert(stockChangeLog); + } else { + goodsBo.setUserId(userId); + goodsBo.setIsJoinDistribution(isJoinDistribution); + this.insertByBo1(goodsBo,type); + } + + /** + * yxy增加代码:如果 goodsBo 的 params 不为空,则进行新增已发布商品 + */ + if (goodsBo.getParams() != null) { + ShopGoodsPublishedBo shopGoodsPublishedBo = new ShopGoodsPublishedBo(); + // 商品id + shopGoodsPublishedBo.setShopGoodsId(goodsBo.getId()); + // 店铺id + shopGoodsPublishedBo.setShopId(goodsBo.getParams().get("shopId") == null ? null : goodsBo.getParams().get("shopId").toString()); + // 三方平台商品id + shopGoodsPublishedBo.setPlatformId(goodsBo.getParams().get("trilateralId") == null ? null : goodsBo.getParams().get("trilateralId").toString()); + // 创建人 + shopGoodsPublishedBo.setCreateBy(userId); + shopGoodsPublishedService.insertByBo(shopGoodsPublishedBo); + } + } + return true; + } + + public Boolean insertByBo1(List bo, Long userId, List zhishuShopGoodsList, + List stockChangeLogList, List zhishuShopImagesList, + String accessToken,Long taskId,Long shopId) { + for (ZhishuShopGoodsBo goodsBo : bo) { + this.insertByBo2(goodsBo, zhishuShopGoodsList, stockChangeLogList, zhishuShopImagesList,accessToken,taskId,shopId); + + // 新增商品详情 + if(ObjectUtil.isEmpty(goodsBo.getIsbn()) || Objects.equals(goodsBo.getIsbn().substring(0,1),"6")){ + System.out.println("商品描述详情:"+JSONObject.toJSONString(goodsBo)); + ZhishuShopGoodsDetailBo zhishuShopGoodsDetail = new ZhishuShopGoodsDetailBo(); + zhishuShopGoodsDetail.setPid(Long.valueOf(goodsBo.getId())); + zhishuShopGoodsDetail.setAuthor(goodsBo.getAuthor()); + zhishuShopGoodsDetail.setPublisher(goodsBo.getPublisher()); + zhishuShopGoodsDetail.setPublishertime(goodsBo.getPublisherTime()); + zhishuShopGoodsDetail.setFormat(goodsBo.getFormat()); + zhishuShopGoodsDetail.setWordage(goodsBo.getWordage()); + zhishuShopGoodsDetail.setUnifiedisbn(goodsBo.getUnifiedIsbn()); + zhishuShopGoodsDetailService.insertByBo(zhishuShopGoodsDetail); + } + } + return true; + } + + + @Transactional(rollbackFor = Exception.class) + @Override + public Boolean insertList(List list, Long depotId, String Filename) { + // 开始时间 + long time1 = System.currentTimeMillis(); + // 获取列表总数量 + int count = list.size(); + + // 每批次插入的数据量 + int pageSize = 1000; + // 根据总数量和每批次的数量计算需要的线程数 + int threadNum = count % pageSize == 0 ? (count / pageSize) : (count / pageSize + 1); + // 获取当前用户id + Long userId = LoginHelper.getUserId(); + + // 通过变量存储数据库中数据 + List countList = baseMapper.selectAll(userId); + // 生成任务key + String cat = buildTaskKey(depotId.toString(), Filename, LocalDateTime.now()); + + // 判断当前仓库是否有货架 + List sheCount = baseMapper.selectSheCount(depotId); + if (sheCount.size() == 0) { + throw new RuntimeException("当前一级货区未存在二级货区"); + } + // 判断当前货区是否有货位 + List freCount = baseMapper.selectFreCount1(sheCount); + if (freCount.size() == 0) { + throw new RuntimeException("当前一级货区未存在三级货区"); + } + + Map map = new HashMap<>(); + sheCount.forEach(she -> { + // 跳过无效code长度(非1位或2位) + if (she.getCode().length() != 1 && she.getCode().length() != 2) { + return; // 在forEach中相当于continue + } + + List tFreight = baseMapper.selectBySId(she.getId()); + if (tFreight == null) { + return; // 跳过空数据 + } + for (int i = 0; i < tFreight.size(); i++) { + if (tFreight.get(i).getCode() == null) { + return; // 跳过空数据 + } + // 核心匹配逻辑 + if ((she.getCode().length() == 2 && tFreight.get(i).getCode().length() == 1) || (she.getCode().length() == 1 && tFreight.get(i).getCode().length() == 2)) { + map.put(tFreight.get(i).getId(), she.getId()); + } + } + }); + if (map.isEmpty()) { + return false; + } + + + baseMapper.insertTask(depotId, Filename, count, userId); + + // 初始化线程池 + ExecutorService executor = Executors.newFixedThreadPool(100); + // 创建计数器 + CountDownLatch end = new CountDownLatch(threadNum); + // 将列表按照线程数量进行分批处理 + Lists.partition(list, threadNum).forEach(batch -> executor.execute(() -> { + try { + // 5.并行化ArtNo生成(线程安全处理) + // 随机获取sheCount列表中的任意一个数并判断是否为空 + Long sheId = null; + Long freId = null; + // 1. 转换为可随机访问的Entry集合 + List> entries = new ArrayList<>(map.entrySet()); + // 2. 线程安全随机选择(Java 8+) + if (!entries.isEmpty()) { + Map.Entry randomEntry = entries.get(ThreadLocalRandom.current().nextInt(entries.size())); + freId = randomEntry.getKey(); + sheId = randomEntry.getValue(); + } + + processArtNoConcurrently(list, userId, depotId, sheId, freId); + Boolean b = this.insertByBo(batch, userId,null); + + } finally { + // 6. 计数器减一,表示一个线程完成任务 + end.countDown(); + } + })); + + try { + // 等待所有线程完成任务 + end.await(); + // 关闭线程池 + executor.shutdown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ServiceException("任务被中断"); + } + // finally { + // // 7.双重保障清理机制(即使线程崩溃也会执行) + // redisTemplate.delete(depotId); + // log.info(" 任务[{}]已执行完成并清理锁", userId); + // } + long time2 = System.currentTimeMillis(); + System.out.println("总耗时:" + (time2 - time1)); + return true; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public Boolean insertListGoodsInfo(List list, Long depotId, Long shelvesDepotId, Long freightDepotId, String Filename, String code,Long userId,String type) { + // 获取当前用户id + if (userId == null){ + userId = LoginHelper.getUserId(); + } + + // 开始时间 + long time1 = System.currentTimeMillis(); + // 获取列表总数量 + int count = list.size(); + + // 每批次插入的数据量 + int pageSize = 1000; + // 根据总数量和每批次的数量计算需要的线程数 + int threadNum = count % pageSize == 0 ? (count / pageSize) : (count / pageSize + 1); + + + // 通过变量存储数据库中数据 + List countList = baseMapper.selectAll(userId); + // 生成任务key + String cat = buildTaskKey(depotId.toString(), Filename, LocalDateTime.now()); + + baseMapper.insertTask(depotId, Filename, count, userId); + + // 初始化线程池 + ExecutorService executor = Executors.newFixedThreadPool(100); + // 创建计数器 + CountDownLatch end = new CountDownLatch(threadNum); + // 将列表按照线程数量进行分批处理 + Long finalUserId = userId; + Lists.partition(list, threadNum).forEach(batch -> executor.execute(() -> { + try { + // 直接使用传入的ID + Long sheId = shelvesDepotId; + Long freId = freightDepotId; + + processArtNoConcurrently(list, finalUserId, depotId, sheId, freId); + Boolean b = this.insertByBo(batch, finalUserId,type); + } finally { + // 计数器减一,表示一个线程完成任务 + end.countDown(); + } + })); + + try { + // 等待所有线程完成任务 + end.await(); + // 关闭线程池 + executor.shutdown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ServiceException("任务被中断"); + } + + long time2 = System.currentTimeMillis(); + System.out.println("总耗时:" + (time2 - time1)); + return true; + } + /** + * 处理ArtNo生成的并发问题 + */ + private void processArtNoConcurrently(List list, Long userId, Long depotId, Long sheId, Long freId) { + + List tDepotList = tDepotMapper.selectV(userId); + List tShelvesList = tShelvesMapper.selectM(userId); + List tFreightList = tShelvesMapper.selectFList(userId); + // 并行处理每个商品对象 + list.stream().forEach(zhishuShopGoodsBo -> { +// if (zhishuShopGoodsBo.getIsArtNoConversion() == 0) { +// return; +// } + + int count= baseMapper.selectArtNobyartNo(zhishuShopGoodsBo.getArtNo(), userId); + if(count>0){ + return; + } + // 设置商品对象的用户ID + zhishuShopGoodsBo.setUserId(userId); + // 初始化新的ArtNo为空字符串 + String newArtNo = ""; + // 接收新的artNo + String artNo1 = zhishuShopGoodsBo.getArtNo(); + // 获取商品的品相 + String conCode = zhishuShopGoodsBo.getConditionCode(); + // 获取商品的ISBN + String isbn = zhishuShopGoodsBo.getIsbn(); + // 调用方法获取新的ArtNo + Double s = convertChineseToCode(conCode); + + String letterCode = CnumberUtils.CHINESE_TO_CODE_MAP.get(conCode); + // 判断artNo是否为 +// if (StringUtils.isEmpty(artNo1)) { + // 调用生成货号的工具类 + newArtNo = cnumberUtils.getArtNo(s, userId, isbn, depotId, sheId, freId, letterCode, tDepotList, tShelvesList, tFreightList); +// } else if (artNo1.length() < 13) { + // 货号小于13位,则补全货号 + +// String depotCode = TDepotMapper.selectByCode(userId, depotId); +// String sheCode = TShelvesMapper.selectFreCode(depotCode, userId); +// String freCode = String.valueOf(generateRandomNumber(1, 5)); +// String conditionCode = getConditionCode(convertChineseToCode(zhishuShopGoodsBo.getConditionCode())); +// newArtNo = depotCode + sheCode + freCode + conditionCode + "-" + artNo1; +// } else { +// newArtNo = artNo1; +// } + zhishuShopGoodsBo.setArtNo(newArtNo); + }); + } + + + /** + * 修改商品信息 + * + * @param bo 商品信息 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ZhishuShopGoodsBo bo) { + ZhishuShopGoods update = MapstructUtils.convert(bo, ZhishuShopGoods.class); + if (update != null) { + update.setConditionCode(CHINESE_TO_CODE_MAP1.get(bo.getConditionCode())); + } + try { + boolean inven = false; + ZhishuShopGoods zhishuShopGoods = baseMapper.selectById(update.getId()); + if (bo.getInventory() != null && !bo.getInventory().equals(zhishuShopGoods.getInventory())) { + int caozuoType = 0; + int inverend = 0; + if (zhishuShopGoods.getInventory() == null) { + caozuoType = 1; + inverend = bo.getInventory().intValue(); + } else { + int newInventory = bo.getInventory().intValue(); + int oldInventory = zhishuShopGoods.getInventory().intValue(); + // 通过三元运算符实现当newInventory大于oldInventory时,caozuoType为1(增加库存),否则为2(减少库存) + caozuoType = newInventory > oldInventory ? 1 : 2; + inverend = newInventory > oldInventory ? newInventory - oldInventory : oldInventory - newInventory; + } + boolean authorizeStatus = getshopAuthorize(zhishuShopGoods); + if (authorizeStatus) { + //执行库存同步操作 + Boolean invent = CaoZuoInvent(caozuoType, zhishuShopGoods, inverend); + // 获取当前库存数量 + Boolean count = baseMapper.updateChunkInventory(update); + if (invent && count) { + inven = true; + } + if (!inven) { + throw new RuntimeException("线上库存修改失败"); + } + } + } + return inven; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 获取店铺授权状态 + * + * @param zhishuShopGoods + * @return + */ + public Boolean getshopAuthorize(ZhishuShopGoods zhishuShopGoods) { + List shopGoodsPublishedVoList = shopGoodsPublishedService.queryByShopGoodsId(zhishuShopGoods.getId()); + // 循环根据店铺Id查询出店铺信息 + List shopNames = new ArrayList<>(); + for (ShopGoodsPublishedVo goodsPublishedVo : shopGoodsPublishedVoList) { + // 根据店铺Id查询出店铺信息 + ShopVo shop = shopService.queryById(Long.valueOf(goodsPublishedVo.getShopId())); + if (shop == null){ + shopGoodsPublishedService.deleteWithValidByIds(List.of(goodsPublishedVo.getId()), true); + continue; + } + // 根据店铺类型分别推送平台同步库存 + try { + if (shop.getShopAuthorize().equals("2")) { + shopNames.add(shop.getShopName()); + } + } catch (Exception e) { + throw new RuntimeException(shop.getShopName() + "同步失败:" + e); + } finally { + continue; + } + } + if (!shopNames.isEmpty()) { + String formattedShops = String.join(",", shopNames); // 中文逗号分隔 + throw new RuntimeException("店铺:" + formattedShops + ",授权已过期,请重新授权"); + } + return true; + } + + + /** + * 根据库存操作类型操作库存并同步平台库存 + * + * @param operationType + * @param zhishuShopGoods + * @param count + * @return + */ + public Boolean CaoZuoInvent(Integer operationType, ZhishuShopGoods zhishuShopGoods, Integer count) { + Boolean result = operatingInventory(operationType, zhishuShopGoods.getId(), count, 1, "0", zhishuShopGoods.getUserId()); + Assert.isTrue(result, "操作redis/数据库库存失败"); + // 根据商品Id查询出拥有同商品的店铺Id和平台商品Id + List shopGoodsPublishedVoList = shopGoodsPublishedService.queryByShopGoodsId(zhishuShopGoods.getId()); + // 循环根据店铺Id查询出店铺信息 + for (ShopGoodsPublishedVo goodsPublishedVo : shopGoodsPublishedVoList) { + // 根据店铺Id查询出店铺信息 + ShopVo shop = shopService.queryById(Long.valueOf(goodsPublishedVo.getShopId())); + if (shop == null){ + shopGoodsPublishedService.deleteWithValidByIds(List.of(goodsPublishedVo.getId()), true); + continue; + } + // 根据店铺类型分别推送平台同步库存 + try { + InventorySynchronizedStrategy strategy = InventorySynchronizedStrategyFactory.getStrategy(shop.getShopType()); + /** + * operationType 1 添加库存任务 2 减少库存任务 + * type 3 添加库存 2 减少库存 + */ + Integer type = operationType == 1 ? 3 : 2; + strategy.inventorySynchronized(shop, goodsPublishedVo,type); + } catch (Exception e) { + throw new RuntimeException(shop.getShopName() + "同步失败:" + e); + } finally { + continue; + } + } + return true; + } + + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ZhishuShopGoodsBo entity) { + + // 获取当前用户id + // Long userId = LoginHelper.getUserId(); + // if (entity.getArtNo() == null || entity.getArtNo().length() < 13) { + // Double s = convertChineseToCode(entity.getConditionCode()); + // entity.setUserId(userId); + // String artNo = cnumberUtils.getArtNo(s, userId, entity.getIsbn(), null, null, null, null); + // entity.setArtNo(artNo); + // + // } + + // TODO 做一些数据校验,如唯一约束 + } + + /** + * 校验并批量删除商品信息信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + boolean message = false; + ArrayList idsList = new ArrayList<>(); + if (isValid) { +// 删除商品信息 +// 循环ids设置ZhishuShopGoods中的id和设置库存为0 + ids.forEach(id -> { + ZhishuShopGoods zhishuShopGoods = baseMapper.selectById(id); + if (zhishuShopGoods.getInventory() != null) { + Integer inventory = zhishuShopGoods.getInventory().intValue(); + Boolean result = CaoZuoInvent(2, zhishuShopGoods, inventory); + if (result) { + idsList.add(id); + } + } + }); + if (!idsList.isEmpty()) { + for (String id : idsList) { + // 查询是否存在已发布商品信息 + Integer count = baseMapper.selectPubCount(id); + if (count > 0) { + // 删除已发布商品信息 + baseMapper.delPubGood(id); + } + } + message = baseMapper.deleteIds(idsList) > 0; + } + } else { + for (String id : ids) { + // 查询是否存在已发布商品信息 + Integer count = baseMapper.selectPubCount(id); + if (count > 0) { + // 删除已发布商品信息 + baseMapper.delPubGood(id); + } + } + message = baseMapper.deleteIds(ids) > 0; + } + + // baseMapper.selectPubCount(ids); + + return message; + } + + + /** + * 构建任务的唯一键 + *

+ * 该方法通过结合仓库ID、目录路径的MD5值和时间来生成一个全局唯一的任务键 + * 使用MD5值是为了确保即使目录路径非常长,生成的键也不会超过一定的长度,并且是唯一的 + * 时间格式化为yyyyMMddHHmm是为了确保时间的部分在键中是固定长度和格式的 + * + * @param depotId 仓库ID,标识任务所属的仓库 + * @param catalogPath 目录路径,标识任务所在的目录结构 + * @param time 时间,标识任务创建的时间 + * @return 返回构建的任务键字符串 + */ + public static String buildTaskKey(String depotId, String catalogPath, LocalDateTime time) { + return String.format("TASK:%s:%s:%s", depotId, DigestUtils.md5Hex(catalogPath), time.format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"))); + } + + public static final Map CHINESE_TO_CODE_MAP1 = IntStream.range(0, CHINESE_CODE.length).boxed().collect(Collectors.toMap(i -> CHINESE_CODE[i], // 键:中文标识(如"一品") + i -> CONDITION_CODE[i], // 值:字母标识(如"A") + (oldVal, newVal) -> oldVal, LinkedHashMap::new // 保持插入顺序 + )); + + public static final Map CHINESE_TO_CODE_MAP = IntStream.range(0, CHINESE_CODE.length).boxed().collect(Collectors.toMap(i -> CHINESE_CODE[i], // 键:中文标识(如"一品") + i -> CONDITION_CODES[i], // 值:字母标识(如"1") + (oldVal, newVal) -> oldVal, LinkedHashMap::new // 保持插入顺序 + )); + + // 品相映射表 + public static final Map CODE_MAP = IntStream.range(0, CONDITION_CODES.length).boxed().collect(Collectors.toMap(i -> CONDITION_CODES[i], + i -> CONDITION_CODE[i], + (oldVal, newVal) -> oldVal, () -> new TreeMap<>(Comparator.comparingDouble(Double::doubleValue)))); + + public Double convertChineseToCode(String chineseName) { + Double code = CHINESE_TO_CODE_MAP.get(chineseName); + if (code == null) { + throw new IllegalArgumentException("无效的中文品名: " + chineseName); + } + return code; + } + + private int generateRandomNumber(int min, int max) { + Random random = new Random(); + return random.nextInt(max - min + 1) + min; + } + + + public static String getConditionCode(double input) { + return CODE_MAP.getOrDefault(input, "UNDEFINED"); + } + + /** + * 调用Python脚本查询图书信息 + * + * @param isbn ISBN编号 + * @return 查询结果 + */ + public ProductVo queryBookByPython(String isbn) { + try { + // 1. 确认线上Python脚本路径 + String scriptPath = "/www/wwwroot/python/chaxun.py"; // 线上绝对路径 + File scriptFile = new File(scriptPath); + + // 2. 检查脚本是否存在 + if (!scriptFile.exists()) { + throw new RuntimeException("Python脚本不存在: " + scriptPath); + } + + // 3. 检查执行权限(Linux/Unix环境) + if (!scriptFile.canExecute()) { + throw new RuntimeException("Python脚本无执行权限: " + scriptPath); + } + + // 4. 构建进程命令(明确使用python3) + ProcessBuilder processBuilder = new ProcessBuilder("python3", scriptPath, // 脚本路径 + isbn // ISBN参数 + ); + processBuilder.redirectErrorStream(true); // 合并错误流到标准输出 + + // 5. 启动进程并等待完成 + System.out.println("执行命令: " + String.join(" ", processBuilder.command())); + Process process = processBuilder.start(); + + // 6. 读取输出 + StringBuilder output = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + output.append(line).append("\n"); + } + } + + // 7. 检查执行结果 + int exitCode = process.waitFor(); + if (exitCode != 0) { + throw new RuntimeException("Python脚本执行失败,退出码: " + exitCode + "\n输出: " + output); + } + + // 8. 解析JSON结果 + return JSON.parseObject(output.toString().trim(), ProductVo.class); + } catch (Exception e) { + throw new RuntimeException("调用Python脚本失败: " + e.getMessage(), e); + } + } + + /** + * 查询上书记录 + */ +// @Override +// public List selectShopGoodsByPhoneNumber(String phoneNumber) { +// Long userId = sysUserMapper.selectUserIdByNameAndPassWord(phoneNumber); +// // 获取用户对应的店铺ID列表 +// Map> shopIdsMap = getShopIdsByUserId(userId); +// // 获取拼多多店铺ID列表 +// List pddShopIds = shopIdsMap.get("1"); +// // 获取孔夫子店铺ID列表 +// List kfzShopIds = shopIdsMap.get("2"); +// // 根据UserId获取商品列表ID +// List goodsList = baseMapper.selectShopGoodsByUser(userId); +// // 提取当前用户上传的商品ID列表 +// List goodsIds = goodsList.stream().map(ZhishuShopGoodsVo::getId).collect(Collectors.toList()); +// +// // 合并所有店铺ID +// List allShopIds = new ArrayList<>(); +// if (pddShopIds != null) allShopIds.addAll(pddShopIds); +// if (kfzShopIds != null) allShopIds.addAll(kfzShopIds); +// +// // 查询所有商品的发布状态 +// if (!goodsIds.isEmpty() && !allShopIds.isEmpty()) { +// List> publishedStatusList = shopGoodsPublishedService.selectPublishedStatus(goodsIds, allShopIds); +// +// // 将发布状态设置到商品对象中 +// Map> statusMap = publishedStatusList.stream() +// .collect(Collectors.toMap( +// map -> String.valueOf(map.get("goodsId")), +// map -> map, +// (v1, v2) -> v1 +// )); +// +// goodsList.forEach(goods -> { +// Map status = statusMap.get(goods.getId()); +// if (status != null) { +// goods.setPddPublishedStatus((Long) status.get("pddStatus")); +// goods.setKfzPublishedStatus((Long) status.get("kfzStatus")); +// } else { +// goods.setPddPublishedStatus(0L); +// goods.setKfzPublishedStatus(0L); +// } +// }); +// } +// +// // 获取商品图片 +// if (!goodsIds.isEmpty()) { +// // 批量查询图片路径 +// List> imagePathList = zhishuShopImagesMapper.batchQueryFirstPathByGoodsIds(goodsIds); +// +// // 将图片路径列表转换为Map +// Map imagePathMap = imagePathList.stream() +// .collect(Collectors.toMap( +// map -> String.valueOf(map.get("goodsId")), +// map -> String.valueOf(map.get("path")), +// (v1, v2) -> v1 +// )); +// +// // 设置图片路径并调用getFiles方法获取图片 +// goodsList.forEach(goods -> { +// String path = imagePathMap.get(goods.getId()); +// if (path != null && !path.isEmpty()) { +// try { +// // 调用getFiles方法获取图片 +// String bookPic = uploadUtil.getFiles(null, goods.getGoodsName(), path); +// goods.setBookPic(bookPic); +// } catch (Exception e) { +// // 记录错误但继续处理其他商品 +// log.error("获取商品图片失败: goodsId={}, path={}", goods.getId(), path, e); +// } +// } +// }); +// } +// +// return goodsList; +// } + public Map> getShopIdsByUserId(Long userId) { + // 构建查询条件 + LambdaQueryWrapper wrapper = Wrappers.lambdaQuery(); + wrapper.eq(Shop::getCreateBy, userId) + .eq(Shop::getStatus, "0") // 正常状态 + .eq(Shop::getDelFlag, "0") // 未删除 + .select(Shop::getId, Shop::getShopType); // 只查询需要的字段 + + // 执行查询 + List shopList = shopMapper.selectList(wrapper); + + // 按店铺类型分组 + Map> resultMap = new HashMap<>(); + + // 初始化结果Map + resultMap.put("1", new ArrayList<>()); // 拼多多店铺 + resultMap.put("2", new ArrayList<>()); // 孔夫子店铺 + resultMap.put("5", new ArrayList<>()); // 闲鱼店铺 + + // 遍历店铺列表,按类型分组 + for (Shop shop : shopList) { + String shopType = shop.getShopType(); + if (shopType != null) { + List idList = resultMap.getOrDefault(shopType, new ArrayList<>()); + idList.add(shop.getId()); + resultMap.put(shopType, idList); + } + } + + return resultMap; + } + + + /** + * 初始化Redis库存 + */ + @Override + public void batchInitInventoryToRedis() { + List goodsList = new LambdaQueryChainWrapper<>(baseMapper).list(); + batchRedisInitInventory(goodsList); + } + + public void batchRedisInitInventory(List goodsList) { + if (ObjectUtil.isNotEmpty(goodsList)) { + RBatch batch = RedisUtils.getClient().createBatch(); + + goodsList.forEach(goods -> { + String inventoryKey = "zhishu_shop_goods_inventory:" + goods.getId(); + RListAsync list = batch.getList(inventoryKey); + for (int i = 0; i < goods.getInventory(); i++) { + list.addAsync(goods.getId()); + } + }); + + // 执行批量操作 + batch.execute(); + } + } + + /** + * 操作Redis/db库存 + * + * @param shopGoodsId + * @param count + * @return + */ + @Override + public Boolean operatingInventory(Integer operationType, String shopGoodsId, Integer count, Integer type, String aboutId, Long operationBy) { + // 确定操作类型 + OperationInventoryTypeEnum operationEnum = OperationInventoryTypeEnum.valueOfCode(operationType); + // 指定redis库000000 + String inventoryKey = "zhishu_shop_goods_inventory:" + shopGoodsId; + String lockKey = "lock:" + shopGoodsId; // 分布式锁的键 + RLock lock = null; + boolean isLockAcquired = false; + try { + // 尝试获取分布式锁 + lock = RedisUtils.getClient().getLock(lockKey); + isLockAcquired = lock.tryLock(10, 10, TimeUnit.SECONDS); // 尝试获取锁,等待时间10秒,锁持有时间为10秒 + + if (!isLockAcquired) { + throw new ServiceException("未能获取到锁,请稍后重试"); + } + + // 查询原始库存 + ZhishuShopGoods zhishuShopGoods = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ZhishuShopGoods::getId, shopGoodsId) + .oneOpt().orElseThrow(() -> new ServiceException("查询商品数据异常-shopGoodsId:" + shopGoodsId)); + + Long currentInventorySize = zhishuShopGoods.getInventory(); + + boolean dbUpdateResult = false; + + // 增加库存操作日志 + StockChangeLog stockChangeLog = new StockChangeLog(); + stockChangeLog.setShopGoodsId(Long.valueOf(shopGoodsId)); + stockChangeLog.setType(type); + stockChangeLog.setAboutId(aboutId); + stockChangeLog.setBeforeInv((long) zhishuShopGoods.getInventory()); + stockChangeLog.setCreateBy(operationBy); + stockChangeLog.setUpdateBy(operationBy); + stockChangeLog.setCreateTime(DateUtils.getNowDate()); + stockChangeLog.setUpdateTime(DateUtils.getNowDate()); + stockChangeLog.setDelFlag("0"); + + switch (operationEnum) { + case REDUCE_INVENTORY: + //减少库存 + if (currentInventorySize < count) { + stockChangeLog.setAfterInv((long) currentInventorySize); // 库存保持不变 + break; // 跳出switch,继续后续流程 + } + // 扣除库存 + + // 更新数据库中的库存 + dbUpdateResult = new LambdaUpdateChainWrapper<>(baseMapper).eq(ZhishuShopGoods::getId, shopGoodsId).setSql("inventory = inventory - " + count).update(); + stockChangeLog.setAfterInv((long) (currentInventorySize - count)); + break; + case INCREASE_INVENTORY: + // 增加库存 + + // 更新数据库中的库存 + dbUpdateResult = new LambdaUpdateChainWrapper<>(baseMapper).eq(ZhishuShopGoods::getId, shopGoodsId).setSql("inventory = inventory + " + count).update(); + stockChangeLog.setAfterInv((long) (currentInventorySize + count)); + break; + default: + throw new ServiceException("未知的操作类型"); + } + + if (!dbUpdateResult) { + throw new ServiceException("扣减库存,操作数据库失败"); + } + + int insert = stockChangeLogMapper.insert(stockChangeLog); + if (insert <= 0) { + throw new ServiceException("库存操作日志插入失败"); + } + return true; + } catch (ServiceException be) { + System.out.println("库存操作异常: " + be.getMessage() + be); + throw be; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); // 恢复线程中断状态 + throw new ServiceException(e.getMessage()); + } finally { + // 确保释放锁 + safeUnlock(lock, isLockAcquired); + } + } + + private void safeUnlock(RLock lock, boolean isLockAcquired) { + if (isLockAcquired && lock != null) { + try { + // 检查当前线程是否还持有锁 + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } else { + System.err.println("当前线程已不再持有锁,跳过释放操作"); + } + } catch (Exception e) { + System.err.println("释放锁异常: " + e.getMessage()); + // 这里可以记录日志,但不要抛出异常 + } + } + } + + + + + /** + * 比对店铺商品信息并生成Excel文件 + * + * @param request + */ + @Async + @Override + public void goodsComparison(GoodsComparisonRequest request) { + Long shopId = request.getShopId(); + Long userId = request.getUserId(); + List zhishuShopGoodsRequestList = request.getZhishuShopGoodsRequestList(); + // 尝试获取锁 + String lockKey = "WriteExcelKey_" + shopId; + String lockValue = "WriteExcelLock"; + Duration lockExpireDuration = Duration.ofMinutes(2); // 设置锁的过期时间为2分钟 + String writeExcelLock = RedisUtils.getCacheObject(lockKey); + // 若获取存在说明存在读取该文件的线程,则直接返回,不进行后续操作 + if (ObjectUtil.isNotEmpty(writeExcelLock)) throw new ServiceException("已在处理该文件,请勿重复操作"); + System.out.println("获取到redis锁,执行读取文件操作"); + // 若不存在,则设置锁,并执行后续操作 + RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration); + ScheduledExecutorService scheduler = null; + ScheduledFuture future = null; + try { + scheduler = Executors.newScheduledThreadPool(1); + // 设置一个定时任务来不断延长锁的过期时间 + Runnable renewLockTask = () -> { + RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration); + System.out.println("Redis锁过期时间已更新"); + }; + // 启动定时任务 + future = scheduler.scheduleAtFixedRate(renewLockTask, 0, INITIAL_DELAY_AND_PERIOD, TimeUnit.SECONDS); + + // 使用并发流处理 + List changedData = Collections.synchronizedList(new ArrayList<>()); + List newData = Collections.synchronizedList(new ArrayList<>()); + + List artNoList = zhishuShopGoodsRequestList.stream() + .map(ZhishuShopGoodsRequest::getArtNo) + .filter(Objects::nonNull) // 过滤掉 null + .filter(s -> !s.isEmpty()) // 过滤掉 空字符串 "" + .distinct() // 去重 + .toList(); + List alreadyExistList = new ArrayList<>(); + if (!ObjectUtil.isEmpty(artNoList)) { + // 查出数据库是否存在数据 + alreadyExistList = new LambdaQueryChainWrapper<>(baseMapper) + .in(ZhishuShopGoods::getArtNo, artNoList) + .list(); + } + Map goodsHashMap = new HashMap<>(); + if (ObjectUtil.isNotEmpty(alreadyExistList)) { + for (ZhishuShopGoods zhishuShopGoods : alreadyExistList) { + goodsHashMap.put(zhishuShopGoods.getProductId(), zhishuShopGoods); + } + } + + for (ZhishuShopGoodsRequest zhishuShopGoodsRequest : zhishuShopGoodsRequestList) { + // 是否发生变化辨识 + Boolean isChanged = false; + // 若经过ISBN码、价格、货号都匹配,则却该数据已在库中存在,则进行具体的其他参数值对比,看是否有其他参数做了修改 + if (ObjectUtil.isNotEmpty(alreadyExistList)) { + // 默认取第一条,多条情况为数据存在异常,不考虑 + if (ObjectUtil.isNotEmpty(goodsHashMap)) { + ZhishuShopGoods zhishuShopGoods = goodsHashMap.get(zhishuShopGoodsRequest.getItemNumber()); + if (ObjectUtil.isNotEmpty(zhishuShopGoods)) { + // 判断ISBN码是否发生变化 + if (!Objects.equals(zhishuShopGoodsRequest.getIsbn(), zhishuShopGoods.getIsbn())) + isChanged = true; + // 判断品相是否发生变化 + double conditionCode = Math.round(zhishuShopGoodsRequest.getConditionCode().doubleValue()) / 10.0; + String conditionCodeString = CnumberUtils.getConditionCode(conditionCode); + if (!conditionCodeString.equals(zhishuShopGoods.getConditionCode())) isChanged = true; + // 判断库存是否发生变化 + if (!zhishuShopGoodsRequest.getInventory().equals(zhishuShopGoods.getInventory().intValue())) + isChanged = true; + // 将原数据库中该条数据的id赋值给当前新拉取下来的数据,用于后续更新数据库 + zhishuShopGoodsRequest.setId(zhishuShopGoods.getId()); + if (isChanged) { + changedData.add(zhishuShopGoodsRequest); + } + } else { + // 若数据库中未查询到符合判定规则的数据,说明该数据为新增数据,将其加入到newData中 + newData.add(zhishuShopGoodsRequest); + } + } + } else { + // 若数据库中未查询到符合判定规则的数据,说明该数据为新增数据,将其加入到newData中 + newData.add(zhishuShopGoodsRequest); + } + } + + List fileNameList = new ArrayList<>(); + // 分别指定新增和修改的数据生成的Excel文件存储路径,文件名称前缀,并写到该路径下 + if (!changedData.isEmpty()) { + fileNameList.add("Changed_" + shopId + "_0.xlsx"); + ExcelFileHandlerUtil.handleExport(changedData, UrlUtil.getUrl(), "Changed", shopId.toString(), ZhishuShopGoodsRequest.class); + } + if (!newData.isEmpty()) { + fileNameList.add("New_" + shopId + "_0.xlsx"); + ExcelFileHandlerUtil.handleExport(newData, UrlUtil.getUrl(), "New", shopId.toString(), ZhishuShopGoodsRequest.class); + } + + + RedisUtils.setCacheObject("lastGoodsSynTime_" + shopId, request.getCurrentDateTime()); + + if (!newData.isEmpty() || !changedData.isEmpty()) { + // 查询店铺名称 + ShopVo shop = shopService.queryById(shopId); + // 将任务信息插入到数据库中,创建一条任务 + TaskBo taskBo = new TaskBo(); + taskBo.setTaskType(TaskTypeEnum.SYNC_GOODS_KFZ.getCode()); + taskBo.setShopIds(shopId.toString()); + taskBo.setShopNames(shop.getShopName()); + taskBo.setFileName(String.join("/", fileNameList)); + taskBo.setDataNum((long) zhishuShopGoodsRequestList.size()); + taskBo.setTaskStatus("0"); + taskBo.setStatus("0"); + taskBo.setCreateBy(userId); + taskServiceImpl.insertByBo(taskBo); + } + + // 发送消息给前端告知拉取下来的数据已比对完毕 + scheduledExecutorService.schedule(() -> + + { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage("已拉取到商品数据总计:" + zhishuShopGoodsRequestList.size() + "条,新增:" + newData.size() + "条新数据,更新:" + changedData.size() + "条数据"); + dto.setUserIds(List.of(userId)); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); + } catch (Exception e) { + // 捕获其他未知异常 + log.error("商品导入写入Excel过程中发生异常: {}", e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } finally { + // 取消定时任务 + if (future != null) { + future.cancel(false); + } + // 关闭线程池 + if (scheduler != null) { + scheduler.shutdownNow(); + } + // 确保释放锁 + RedisUtils.deleteObject(lockKey); + System.out.println("已释放redis锁"); + } + + } + + // 新增成员变量,用于存储分批处理的状态 + private final ConcurrentHashMap batchContextMap = new ConcurrentHashMap<>(); + + /** + * 分批比对商品 + */ + @Override + public void batchGoodsComparison(BatchGoodsRequest request) { + Long shopId = request.getShopId(); + Long userId = request.getUserId(); + + // 获取或创建处理上下文 + BatchProcessingContext context = batchContextMap.computeIfAbsent(shopId, k -> { + BatchProcessingContext newContext = new BatchProcessingContext(); + newContext.setShopId(shopId); + newContext.setUserId(userId); + newContext.setCurrentDateTime(request.getCurrentDateTime()); + newContext.setTotalBatches(request.getTotalBatches()); + + // 初始化锁 + String lockKey = "WriteExcelKey_" + shopId; + String lockValue = "WriteExcelLock"; + Duration lockExpireDuration = Duration.ofMinutes(30); // 延长锁时间 + RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration); + newContext.setLockKey(lockKey); + + return newContext; + }); + + try { + // 处理当前批次数据 + processBatchData(request.getBatchData(), context); + + // 更新已接收批次计数 + int received = context.getReceivedBatches().incrementAndGet(); + + // 如果是最后一批,完成处理 + if (request.getIsLastBatch() && received == context.getTotalBatches()) { + completeBatchProcessing(context); + } + } catch (Exception e) { + // 发生异常时清理资源 + cleanupBatchProcessing(context); + throw new ServiceException("分批处理商品数据异常: " + e.getMessage() + "异常详情:" + e); + } + } + + /** + * 处理单批数据 + */ + private void processBatchData(List batchData, BatchProcessingContext context) { + List artNoList = batchData.stream() + .map(ZhishuShopGoodsRequest::getArtNo) + .filter(Objects::nonNull) + .filter(s -> !s.isEmpty()) + .distinct() + .toList(); + + // 查询数据库已有数据 + List alreadyExistList = Collections.emptyList(); + if (!artNoList.isEmpty()) { + alreadyExistList = new LambdaQueryChainWrapper<>(baseMapper) + .in(ZhishuShopGoods::getArtNo, artNoList) + .list(); + } + + Map goodsHashMap = alreadyExistList.stream() + .collect(Collectors.toMap(ZhishuShopGoods::getProductId, Function.identity())); + + // 分类处理当前批次数据 + for (ZhishuShopGoodsRequest request : batchData) { + Boolean isChanged = false; + + if (!goodsHashMap.isEmpty()) { + ZhishuShopGoods existingGoods = goodsHashMap.get(request.getItemNumber()); + if (existingGoods != null) { + // 检查数据是否有变化 + if (!Objects.equals(request.getIsbn(), existingGoods.getIsbn())) { + isChanged = true; + } + + double conditionCode = Math.round(request.getConditionCode().doubleValue()) / 10.0; + String conditionCodeString = CnumberUtils.getConditionCode(conditionCode); + if (!conditionCodeString.equals(existingGoods.getConditionCode())) { + isChanged = true; + } + + if (!request.getInventory().equals(existingGoods.getInventory().intValue())) { + isChanged = true; + } + + request.setId(existingGoods.getId()); + + if (isChanged) { + context.getAllChangedData().add(request); + } + } else { + context.getAllNewData().add(request); + } + } else { + context.getAllNewData().add(request); + } + } + } + + /** + * 完成批次处理 + */ + private void completeBatchProcessing(BatchProcessingContext context) { + ScheduledExecutorService scheduler = null; + ScheduledFuture future = null; + + try { + // 设置锁续期 + scheduler = Executors.newScheduledThreadPool(1); + Runnable renewLockTask = () -> { + RedisUtils.setCacheObject(context.getLockKey(), "WriteExcelLock", Duration.ofMinutes(30)); + }; + future = scheduler.scheduleAtFixedRate(renewLockTask, 0, 1, TimeUnit.MINUTES); + + // 处理所有数据 + List fileNameList = new ArrayList<>(); + + if (!context.getAllChangedData().isEmpty()) { + fileNameList.add("Changed_" + context.getShopId() + "_0.xlsx"); + ExcelFileHandlerUtil.handleExport( + context.getAllChangedData(), + UrlUtil.getUrl(), + "Changed", + context.getShopId().toString(), + ZhishuShopGoodsRequest.class + ); + } + + if (!context.getAllNewData().isEmpty()) { + fileNameList.add("New_" + context.getShopId() + "_0.xlsx"); + ExcelFileHandlerUtil.handleExport( + context.getAllNewData(), + UrlUtil.getUrl(), + "New", + context.getShopId().toString(), + ZhishuShopGoodsRequest.class + ); + } + + // 更新同步时间 + RedisUtils.setCacheObject("lastGoodsSynTime_" + context.getShopId(), context.getCurrentDateTime()); + + if (!context.getAllNewData().isEmpty() || !context.getAllChangedData().isEmpty()) { + // 查询店铺名称 + ShopVo shop = shopService.queryById(context.getShopId()); + + // 创建任务 + TaskBo taskBo = new TaskBo(); + taskBo.setTaskType(TaskTypeEnum.SYNC_GOODS_KFZ.getCode()); + taskBo.setShopIds(context.getShopId().toString()); + taskBo.setShopNames(shop.getShopName()); + taskBo.setFileName(String.join("/", fileNameList)); + taskBo.setDataNum((long) (context.getAllNewData().size() + context.getAllChangedData().size())); + taskBo.setTaskStatus("0"); + taskBo.setStatus("0"); + taskBo.setCreateBy(context.getUserId()); + taskServiceImpl.insertByBo(taskBo); + } + + // 发送通知 + scheduledExecutorService.schedule(() -> { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage("已拉取到商品数据总计:" + + (context.getAllNewData().size() + context.getAllChangedData().size()) + + "条,新增:" + context.getAllNewData().size() + + "条新数据,更新:" + context.getAllChangedData().size() + "条数据"); + dto.setUserIds(List.of(context.getUserId())); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); + } finally { + // 清理资源 + if (future != null) { + future.cancel(false); + } + if (scheduler != null) { + scheduler.shutdownNow(); + } + cleanupBatchProcessing(context); + } + } + + /** + * 清理批次处理资源 + */ + private void cleanupBatchProcessing(BatchProcessingContext context) { + if (context != null) { + // 释放锁 + RedisUtils.deleteObject(context.getLockKey()); + // 移除上下文 + batchContextMap.remove(context.getShopId()); + } + } + + /** + * 根据用户选择货号规则将商品存入数据库 + * + * @param saveGoodsVo + */ + @Async + @Override + public void saveShopGoodsInDb(SaveGoodsVo saveGoodsVo) { + System.out.println("开始根据用户选择货号规则将商品存入数据库"); + System.out.println("saveShopGoodsInDb:request-" + JSONObject.toJSONString(saveGoodsVo)); + // 指定读取需要新增的商品Excel文件路径 + String newGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "New_" + saveGoodsVo.getShopId() + "_0.xlsx").toString(); + // 指定读取需要修改的商品Excel文件路径 + String updateGoodsExcelPath = Paths.get(UrlUtil.getUrl(), "Changed_" + saveGoodsVo.getShopId() + "_0.xlsx").toString(); + // 初期化任务对象 + TaskBo taskBo = new TaskBo(); + taskBo.setId(saveGoodsVo.getTaskId()); + + // 尝试获取锁 + String lockKey = "ReadExcelKey_" + saveGoodsVo.getShopId(); + String lockValue = "ReadExcelLock"; + Duration lockExpireDuration = Duration.ofMinutes(2); // 设置锁的过期时间为2分钟 + String readExcelLock = RedisUtils.getCacheObject(lockKey); + // 若获取存在说明存在读取该文件的线程,则直接返回,不进行后续操作 + if (ObjectUtil.isNotEmpty(readExcelLock)) throw new ServiceException("已在处理该文件,请勿重复操作"); + System.out.println("获取到redis锁,执行读取文件操作"); + // 若不存在,则设置锁,并执行后续操作 + RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration); + ScheduledExecutorService scheduler = null; + ScheduledFuture future = null; + try { + scheduler = Executors.newScheduledThreadPool(1); + // 设置一个定时任务来不断延长锁的过期时间 + Runnable renewLockTask = () -> { + RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration); + System.out.println("Redis锁过期时间已更新"); + }; + // 启动定时任务 + future = scheduler.scheduleAtFixedRate(renewLockTask, 0, INITIAL_DELAY_AND_PERIOD, TimeUnit.SECONDS); + + // 修改任务执行状态为执行中 + taskBo.setTaskStatus(TaskStatusTypeEnum.EXECUTING.getCode()); + taskServiceImpl.updateByBo(taskBo); + + // 分别定义两个列表,用于存储读取的数据 + List newDataList = new ArrayList<>(); + List updateDataList = new ArrayList<>(); + try { + System.out.println("尝试读取新增的数据:path-" + newGoodsExcelPath); + // 尝试读取新增的数据 + newDataList = EasyExcel.read(newGoodsExcelPath) + .head(ZhishuShopGoodsRequest.class) + .sheet("New_" + saveGoodsVo.getShopId() + "_0") + .doReadSync(); + } catch (Exception e) { + // 读取不到说明没有对应需要处理的数据,不做处理,仅记录日志以防其他未知原因导致,不抛出异常 + System.out.println("未能读取新增数据文件: " + newGoodsExcelPath + "原因:{}" + e.getMessage()); + } + try { + System.out.println("尝试读取更新的数据:path-" + newGoodsExcelPath); + // 尝试读取更新的数据 + updateDataList = EasyExcel.read(updateGoodsExcelPath) + .head(ZhishuShopGoodsRequest.class) + .sheet("Changed_" + saveGoodsVo.getShopId() + "_0") + .doReadSync(); + } catch (Exception e) { + // 读取不到说明没有对应需要处理的数据,不做处理,仅记录日志以防其他未知原因导致,不抛出异常 + System.out.println("未能读取新增数据文件: " + updateGoodsExcelPath + "原因:{}" + e.getMessage()); + } + + // 查询当前任务状态,若任务状态为暂停/停止,说明存在未执行完数据,读取txt文件 + TaskVo taskVo = taskService.queryById(saveGoodsVo.getTaskId()); + AtomicInteger successMarkI; + AtomicInteger failMarkI; + if (TaskStatusTypeEnum.EXECUTE_PAUSE_STOP.getCode().equals(taskVo.getTaskStatus())) { + // 初始化markI计数器用来统计处理成功的数据条数,AtomicInteger线程安全 + successMarkI = new AtomicInteger(taskVo.getDataNum().intValue() - (newDataList.size() + updateDataList.size())); + // 初始化markI计数器用来统计处理失败的数据条数,AtomicInteger线程安全 + failMarkI = new AtomicInteger(newDataList.size() + updateDataList.size()); + } else if (TaskStatusTypeEnum.EXECUTED.getCode().equals(taskVo.getTaskStatus())) { + return; + } else { + // 初始化markI计数器用来统计处理成功的数据条数,AtomicInteger线程安全 + successMarkI = new AtomicInteger(0); + // 初始化markI计数器用来统计处理失败的数据条数,AtomicInteger线程安全 + failMarkI = new AtomicInteger(0); + } + + // 将新增的和更新的数据合并到一起并写入文件 + writeAllDateToExcel(newDataList, updateDataList, saveGoodsVo.getShopId(), saveGoodsVo.getTaskId(), ZhishuShopGoodsRequest.class); + + // 总计读取数据条数 + Integer totalNum = newDataList.size() + updateDataList.size(); + // 根据商店id查询出对应的userId + ShopVo shopVo = shopService.queryById(saveGoodsVo.getShopId()); + System.out.println("根据商店id查询出对应的userId:" + JSONObject.toJSONString(shopVo)); + Long userId = shopVo.getCreateBy(); + + // 查询出该用户下所有货架 + List freightGoodsCountList = baseMapper.selectFreightGoodsNumber(userId, saveGoodsVo.getFreightIdList()); + if (ObjectUtil.isEmpty(freightGoodsCountList)) + throw new ServiceException("该用户下或没有三级货区,请检查后重试"); + + // 对新增的数据进行处理 + List failedInsertedList = new CopyOnWriteArrayList<>(); + List successInsertedList = new CopyOnWriteArrayList<>(); + if (ObjectUtil.isNotEmpty(newDataList)) { + // 将 newDataList 分成 8 个批次 + int totalSize = newDataList.size(); + int batchSize = (int) Math.ceil((double) totalSize / 8); + List> partitionedData = new ArrayList<>(); + for (int i = 0; i < totalSize; i += batchSize) { + int end = Math.min(i + batchSize, totalSize); + partitionedData.add(newDataList.subList(i, end)); + } + // 使用 CopyOnWriteArrayList 确保线程安全 + CountDownLatch latch = new CountDownLatch(partitionedData.size()); + long newTime = System.currentTimeMillis(); + + for (List subList : partitionedData) { + ThreadPoolUtils.execute(() -> { + try { + for (ZhishuShopGoodsRequest newData : subList) { + // TODO 新增数据处理逻辑 + try { + AtomicBoolean insertNewDataStatus = new AtomicBoolean(true); + zhishuShopGoodsAopService.insertNewDataList(newData, userId, freightGoodsCountList, saveGoodsVo, failedInsertedList, successInsertedList, successMarkI, failMarkI, shopVo, totalNum, newTime, insertNewDataStatus, taskVo.getTaskType()); + } catch (Exception e) { + log.error(e.getMessage()); + failedInsertedList.add(newData); + } + // 将这条数据写入到异常记录中,后去完成后会删除 + ExcelFileHandlerUtil.syncWriteRecord(UrlUtil.getUrl(), "Error_New_" + saveGoodsVo.getShopId() + "_" + Thread.currentThread().getId(), List.of(newData), "0"); + } + } finally { + latch.countDown(); + } + }); + } + try { + latch.await(); // 等待所有线程完成 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("线程等待中断", e); + } + // 数据处理完毕删除异常文件 + ExcelFileHandlerUtil.deleteFilesByPrefix(UrlUtil.getUrl(), "Error_New_" + saveGoodsVo.getShopId()); + // 将这条数据写入到历史版本中 + if (!successInsertedList.isEmpty()) { + ExcelFileHandlerUtil.handleExport(successInsertedList, UrlUtil.getUrl(), "New", saveGoodsVo.getShopId().toString() + "_" + newTime, ZhishuShopGoodsRequest.class); + } + // 处理失败数据和文件删除 + if (!failedInsertedList.isEmpty()) { + ExcelFileHandlerUtil.handleExport(failedInsertedList, UrlUtil.getUrl(), "New", saveGoodsVo.getShopId().toString(), ZhishuShopGoodsRequest.class); + } else { + FileUtil.fileDelete(newGoodsExcelPath); + } + } + // 对更新的数据进行处理 + List failedUpdateList = new CopyOnWriteArrayList<>(); + List successUpdateList = new CopyOnWriteArrayList<>(); + if (ObjectUtil.isNotEmpty(updateDataList)) { + // 将 updateDataList 分成 8 个批次 + int totalSize = updateDataList.size(); + int batchSize = (int) Math.ceil((double) totalSize / 8); + List> partitionedData = new ArrayList<>(); + for (int i = 0; i < totalSize; i += batchSize) { + int end = Math.min(i + batchSize, totalSize); + partitionedData.add(updateDataList.subList(i, end)); + } + CountDownLatch latch = new CountDownLatch(partitionedData.size()); + long updateTime = System.currentTimeMillis(); + for (List subList : partitionedData) { + ThreadPoolUtils.execute(() -> { + try { + for (ZhishuShopGoodsRequest changedData : subList) { + // TODO 更新数据处理逻辑 + try { + AtomicBoolean updateChangedDataStatus = new AtomicBoolean(true); + zhishuShopGoodsAopService.updateChangedDataList(changedData, userId, freightGoodsCountList, saveGoodsVo, failedUpdateList, successUpdateList, successMarkI, failMarkI, shopVo, totalNum, updateTime, updateChangedDataStatus); + } catch (Exception e) { + log.error(e.getMessage()); + failedUpdateList.add(changedData); + } + // 将这条数据写入到异常记录中,后去完成后会删除 + ExcelFileHandlerUtil.syncWriteRecord(UrlUtil.getUrl(), "Error_Changed_" + saveGoodsVo.getShopId() + "_" + Thread.currentThread().getId(), List.of(changedData), "0"); + } + } finally { + latch.countDown(); // 当前线程完成 + } + }); + } + try { + latch.await(); // 等待所有线程完成 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + log.error("线程等待中断", e); + } + // 数据处理完毕删除异常文件 + ExcelFileHandlerUtil.deleteFilesByPrefix(UrlUtil.getUrl(), "Error_Changed_" + saveGoodsVo.getShopId()); + // 将这条数据写入到历史版本中 + if (!successUpdateList.isEmpty()) { + ExcelFileHandlerUtil.handleExport(successUpdateList, UrlUtil.getUrl(), "Changed", + saveGoodsVo.getShopId().toString() + "_" + updateTime, ZhishuShopGoodsRequest.class); + } + // 处理失败数据和文件删除 + if (!failedUpdateList.isEmpty()) { + ExcelFileHandlerUtil.handleExport(failedUpdateList, UrlUtil.getUrl(), "Changed", saveGoodsVo.getShopId().toString(), ZhishuShopGoodsRequest.class); + } else { + FileUtil.fileDelete(updateGoodsExcelPath); + } + } + + // 数据全部正常执行完毕,修改任务状态为已完成 + if (ObjectUtil.isNotEmpty(failedInsertedList) || ObjectUtil.isNotEmpty(failedUpdateList)) { + // 若存在失败数据则修改任务状态为暂停/停止 + taskBo.setTaskStatus(TaskStatusTypeEnum.EXECUTE_PAUSE_STOP.getCode()); + } else { + // 若不存在失败数据则修改任务状态为已完成 + taskBo.setTaskStatus(TaskStatusTypeEnum.EXECUTED.getCode()); + } + taskServiceImpl.updateByBo(taskBo); + + // 发送消息给前端告知拉取下来的数据已下载完毕 + scheduledExecutorService.schedule(() -> { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage("成功新增:" + successInsertedList.size() + "条,新增失败:" + failedInsertedList.size() + "条,更新成功:" + successUpdateList.size() + "条,更新失败:" + failedUpdateList.size() + "条"); + dto.setUserIds(List.of(userId)); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); + + } catch (Exception e) { + // 若执行中出现异常,修改任务执行结束 + taskBo.setTaskStatus(TaskStatusTypeEnum.EXECUTE_PAUSE_STOP.getCode()); + taskServiceImpl.updateByBo(taskBo); + // 捕获其他未知异常 + log.error("读取商品导入Excel过程中发生异常: {}", e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } finally { + // 取消定时任务 + if (future != null) { + future.cancel(false); + } + // 关闭线程池 + if (scheduler != null) { + scheduler.shutdownNow(); + } + // 确保释放锁 + RedisUtils.deleteObject(lockKey); + System.out.println("已释放redis锁"); + } + } + + + /** + * 将全部数据写入到Excel中 + * + * @param newDataList + * @param updateDataList + * @param shopId + * @param taskId + * @param clazz + * @param + */ + private void writeAllDateToExcel(List newDataList, List updateDataList, Long shopId, Long taskId, Class clazz) { + List allDataList = new ArrayList<>(); + allDataList.addAll(newDataList); + allDataList.addAll(updateDataList); + EasyExcelUtil.exportToExcel(UrlUtil.getUrl(), taskId + "" + shopId + ".xlsx", allDataList, "0", clazz); + } + + @Override + public ProductForm repeatBook(ProductForm form) { + Long userId = sysUserMapper.selectUserIdByNameAndPassWord(form.getPhoneNumber()); + Long depotId = TDepotMapper.getDepotIdByName(form.getDepotName(), userId); + Long shelvesId = TShelvesMapper.getShelvesIdByName(form.getShelvesName(), depotId); + Long freightId = TFreightMapper.getFreightIdByName(form.getFreightName(), shelvesId); + // 获取品相数值 + String conCode = null; + String chineseName = form.getConditionCode(); + String letterCode = null; + if (CnumberUtils.CHINESE_TO_CODE_MAP.containsKey(chineseName)) { + // String letterCode = CnumberUtils.CHINESE_TO_CODE_MAP.get(chineseName); + letterCode = CnumberUtils.CHINESE_TO_CODE_MAP.get(chineseName); + for (Map.Entry entry : CnumberUtils.CODE_MAP.entrySet()) { + if (entry.getValue().equals(letterCode)) { + conCode = String.valueOf(entry.getKey()); + break; + } + } + } + if (conCode == null) { + throw new IllegalArgumentException("无效的中文品相名称: " + chineseName); + } + String artNo = cnumberUtils.getArtNo(Double.valueOf(conCode), userId, form.getBarcode(), depotId, shelvesId, freightId, null); + System.out.println("重复商品货号为:" + artNo); + // 查询对应的图片 + + Long count = baseMapper.selectArtNoCount1(artNo, form.getPrice(), letterCode); + System.out.println("重复商品数量为:" + count); + String shopId = baseMapper.selectArtNoCount(artNo, form.getPrice()); + System.out.println("重复商品ID为:" + shopId); + String image = baseMapper.queryByShopId(shopId); + System.out.println("重复商品图片为:" + image); + ProductForm productForm = new ProductForm(); + productForm.setImage(image); + productForm.setArtNo(artNo); + productForm.setCount(count); + productForm.setName(form.getName()); + System.out.println("==============" + productForm); + return productForm; + } + + /** + * 根据库存操作类型操作库存并同步平台库存 + * + * @param operationType + * @param shopGoodsPublishedVo + * @param count + * @return + */ + @Override + public Boolean operatingGoodsInventory(Long shopId, Integer shopType, Integer operationType, ShopGoodsPublishedVo shopGoodsPublishedVo, Integer count, String orderSn) { + Integer type; + if (operationType == 1) { + // 退单添加 + type = 3; + } else { + // 订单减扣 + type = 2; + } + Boolean result = operatingInventory(operationType, shopGoodsPublishedVo.getShopGoodsId(), count, type, orderSn, null); + Assert.isTrue(result, "操作redis/数据库库存失败"); + // 根据商品Id查询出拥有同商品的店铺Id和平台商品Id + List shopGoodsPublishedVoList = shopGoodsPublishedService.queryByShopGoodsId(shopGoodsPublishedVo.getShopGoodsId()); + + // 若是订单扣减或是孔夫子平台操作则去除掉自己 + if (type == 2 || shopType == 2) { + // 过滤掉自己的 + shopGoodsPublishedVoList = shopGoodsPublishedVoList.stream().filter(o -> !o.getShopId().equals(shopId.toString())).toList(); + } + System.out.println("shopGoodsPublishedVoList:" + shopGoodsPublishedVoList+"zhuxiaodong1028"); + + // 循环根据店铺Id查询出店铺信息 + for (ShopGoodsPublishedVo goodsPublishedVo : shopGoodsPublishedVoList) { + // 根据店铺Id查询出店铺信息 + ShopVo shop = shopService.queryById(Long.valueOf(goodsPublishedVo.getShopId())); + if (shop == null){ + shopGoodsPublishedService.deleteWithValidByIds(List.of(goodsPublishedVo.getId()), true); + continue; + } + // 根据店铺类型分别推送平台同步库存 + InventorySynchronizedStrategy strategy = InventorySynchronizedStrategyFactory.getStrategy(shop.getShopType()); + Objects.requireNonNull(strategy).inventorySynchronized(shop, goodsPublishedVo,type); + } + return true; + } + + @Override + public Boolean goofishoperatingGoodsInventory(Long shopId, Integer shopType, Integer operationType, ZhishuShopGoodsVo zhishuShopGoodsVo, Integer count, String orderSn) { + Integer type; + if (operationType == 1) { + // 退单添加 + type = 3; + } else { + // 订单减扣 + type = 2; + } + Boolean result = operatingInventory(operationType, zhishuShopGoodsVo.getId(), count, type, orderSn, null); + Assert.isTrue(result, "操作redis/数据库库存失败"); + // 根据商品Id查询出拥有同商品的店铺Id和平台商品Id + List shopGoodsPublishedVoList = shopGoodsPublishedService.queryByShopGoodsId(zhishuShopGoodsVo.getId()); + + // 若是订单扣减或是孔夫子平台操作则去除掉自己 + if (type == 2 || shopType == 2) { + // 过滤掉自己的 + shopGoodsPublishedVoList = shopGoodsPublishedVoList.stream().filter(o -> !o.getShopId().equals(shopId.toString())).toList(); + } + System.out.println("shopGoodsPublishedVoList:" + shopGoodsPublishedVoList+"zhuxiaodong1028"); + + // 循环根据店铺Id查询出店铺信息 + for (ShopGoodsPublishedVo goodsPublishedVo : shopGoodsPublishedVoList) { + // 根据店铺Id查询出店铺信息 + ShopVo shop = shopService.queryById(Long.valueOf(goodsPublishedVo.getShopId())); + if (shop == null){ + shopGoodsPublishedService.deleteWithValidByIds(List.of(goodsPublishedVo.getId()), true); + continue; + } + // 根据店铺类型分别推送平台同步库存 + InventorySynchronizedStrategy strategy = InventorySynchronizedStrategyFactory.getStrategy(shop.getShopType()); + Objects.requireNonNull(strategy).inventorySynchronized(shop, goodsPublishedVo,type); + } + return true; + } + + /** + * Excel文件处理 + * + * @param filePath + */ + private void fileProcessing(String filePath) { + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + Path source = Paths.get(filePath); + Path target = Paths.get(UrlUtil.getUrl(), source.getFileName().toString().replace(".xlsx", "_" + timestamp + ".xlsx")); + try { + // 文件移动 + Files.move(source, target, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + log.error("文件移动失败: {}", e.getMessage()); + } + } + + /** + * 货号处理 + * + * @param saveArtNoRule 保存商品规则:0-不修改直接保存货号 1-按照系统默认规则保存货号 + * @param conditionCode 品相码(如9.5/8.0) + * @param userId 用户Id + * @param isbn ISBN + * @param oldArtNo 原始货号 + * @param freightGoodsCountVo 货区信息 + * @return + */ + @Override + public String artNoProcessing(Integer saveArtNoRule, Long userId, String isbn, String oldArtNo, double conditionCode, FreightGoodsCountVo freightGoodsCountVo) { + // 若保存商品规则:1-按照系统默认规则保存货号 + if (saveArtNoRule == 1) { + // 若传入货号为null或空字符串"" + return cnumberUtils.getArtNo(conditionCode, userId, isbn, freightGoodsCountVo.getDepotId(), freightGoodsCountVo.getShelvesId(), freightGoodsCountVo.getFreightId(), "A"); + } + // 若保存商品规则:0-不修改直接保存货号 ,则不做处理直接返回原本的货号 + // 或其他暂时未知情况货号规则,暂时先返回原本货号 + return oldArtNo; + } + + + /** + * 随机修改孔夫子货号(仅测试使用) + */ + @Override + public void randomUpdateArtNo(Long userId, Long shopId) { + List list = new LambdaQueryChainWrapper<>(baseMapper) + .eq(ZhishuShopGoods::getUserId, userId) + .list(); + for (ZhishuShopGoods zhishuShopGoods : list) { + UpdateArtNoRequest request = new UpdateArtNoRequest(); + request.setShopId(shopId); + request.setProductId(Long.valueOf(zhishuShopGoods.getProductId())); + request.setArtNo(generateRandomString()); + try { + kfzClient.updateArtNo(UrlUtil.getKfzServiceUrl(), request); + } catch (Exception e) { + log.error("同步货号失败:{}", e.getMessage()); + } + } + + } + + @Override + public void goodsAdd(Map map) { + // 获取用户系统库数据 + Long userId; + if (map.get("userId") != null && StringUtils.isNotEmpty(map.get("userId").toString())) { + userId = Long.parseLong(map.get("userId").toString()); + } else { + userId = LoginHelper.getUserId(); + } + // 店铺ids + List shopIdList = (List) map.get("shopIds"); + // 商品信息download + List bookList = map.get("bookList") == null ? new ArrayList<>() : (List) map.get("bookList"); + + for (String shopId : shopIdList) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + if (shopService.checkUsageCount(shopVo) == 0){ + // 无可用额度 + continue; + } + Map createMap = new HashMap(); + createMap.put("shop_id",shopVo.getId().toString()); + createMap.put("shop_type",shopVo.getShopType()); + createMap.put("task_count",bookList.size()+""); + createMap.put("task_type","8"); + + // 图片类型 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 "3":createMap.put("img_type","2");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); + + + + // 执行线程 + ShopGoodsTaskRunnable shopGoodsTaskRunnable = new ShopGoodsTaskRunnable(this, map, userId,shopVo); + Thread thread = new Thread(shopGoodsTaskRunnable, "yxy-goodsAdd"); + thread.start(); + + } + + } + + @Override + public void goodsAutoAdd(Map map) { + // 获取用户系统库数据 + Long userId; + if (map.get("userId") != null && StringUtils.isNotEmpty(map.get("userId").toString())) { + userId = Long.parseLong(map.get("userId").toString()); + } else { + userId = LoginHelper.getUserId(); + } + // 店铺ids + List shopIdList = (List) map.get("shopIds"); + // 商品信息 + List bookList = (List) map.get("bookList"); + + String shopIds = ""; + String shopNames = ""; + String isbn = bookList.get(0).get(1).toString(); + String bookName = bookList.get(0).get(2).toString(); + String artNo = bookList.get(0).get(6) == null ? "" : bookList.get(0).get(6).toString(); + + for (String shopId : shopIdList) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + if (shopNames.equals("")) { + shopIds = shopId; + shopNames = shopVo.getShopName(); + } else { + shopIds = shopIds + "," + shopId; + shopNames = shopNames + "," + shopVo.getShopName(); + } + } + TaskBo taskBo = new TaskBo(); + // 存储任务信息 + taskBo.setTaskType("1"); + taskBo.setFileName("小程序-"+bookName+"-"+isbn+"-"+artNo); + taskBo.setShopIds(shopIds); + taskBo.setShopNames(shopNames); + taskBo.setDataNum(Long.parseLong(bookList.size() + "")); + taskBo.setTaskStatus("0"); + taskBo.setCreateBy(userId); + taskService.insertByBo(taskBo); + goodsAdd2(map, taskBo, userId); + } + + public void goodsAdd2(Map map, TaskBo taskBo, Long userId) { + + String pati = map.get("X-PDD-Pati") == null ? "" : map.get("X-PDD-Pati").toString(); + + // 线程锁对象初始化 + lockMap.put(String.valueOf(Thread.currentThread().getId()), new Object()); + runMap.put(String.valueOf(Thread.currentThread().getId()), false); + + String mark = map.get("mark") != null ? map.get("mark").toString() : ""; + //分类 + String categoryId = map.get("categoryId") != null ? map.get("categoryId").toString() : ""; + + // 店铺ids + List shopIdList = (List) map.get("shopIds"); + // 商品信息 + List bookList = (List) map.get("bookList"); + + for (String shopId : shopIdList) { + ShopVo shopVo = shopService.queryById(Long.parseLong(shopId)); + //如果是孔夫子店铺则等待十秒钟 + if(shopVo.getShopType().equals("2")){ + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + System.out.println("睡眠失败"); + } + } + for (List list : bookList) { + taskWait(String.valueOf(Thread.currentThread().getId())); + + String goodsId = list.get(0).toString(); + String isbn = list.get(1).toString(); + String bookName = list.get(2).toString(); + String price = new BigDecimal(list.get(3).toString()).divide(new BigDecimal(100)).toString(); + + String stock = list.get(4).toString(); + // 品相 + String conditionCode = list.get(5) == null ? "" : list.get(5).toString(); + String artNo = list.get(6) == null ? "" : list.get(6).toString(); + // 运费 + String templateMinPrice = list.get(7) == null ? "" : list.get(7).toString(); + + //先获取redis是否存在该商品的自拍图 + Object zhishuShopImagesVoObj = RedisUtils.getSecondCacheObject(goodsId+"-img"); + if(zhishuShopImagesVoObj == null){ + List zhishuShopImagesVoList = zhishuShopImagesService.selectShopImagesByShopId(goodsId); + if(!zhishuShopImagesVoList.isEmpty()){ + RedisUtils.setSecondCacheObject(goodsId+"-img",JsonUtil.transferToJson(zhishuShopImagesVoList)); + } + } + + Map goMap = new HashMap(); + goMap.put("priority", "1"); + goMap.put("retry_count", "3"); + goMap.put("isbn", isbn); + goMap.put("totalPrice", price); + goMap.put("stock", stock); + goMap.put("bookName", bookName); + goMap.put("code", ""); + goMap.put("imgBigUrl", ""); + goMap.put("artNo", artNo); + goMap.put("taskId", taskBo.getId().toString()); + goMap.put("shopId", shopId); + goMap.put("imageSelect", "12"); + goMap.put("goodsId", goodsId); + goMap.put("conditionCode", conditionCode); + goMap.put("mark", map.get("mark")); + goMap.put("templateMinPrice", templateMinPrice); + goMap.put("categoryId", categoryId); + + System.out.println("task_verifyPricePublishGoods接口"+goMap); + + try { + InterfaceUtils.postForm("http://146.56.192.164:10098", "/api/task_verifyPricePublishGoods", goMap); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + lockMap.remove(String.valueOf(Thread.currentThread().getId())); + runMap.remove(String.valueOf(Thread.currentThread().getId())); + } + + + @Override + public void goodsAdd(Map map, Long userId,ShopVo shopVo) { + // 获取余额 + Long usageCount = shopService.checkUsageCount(shopVo); + + // 商品信息download + List bookList = map.get("bookList") == null ? new ArrayList<>() : (List) map.get("bookList"); + ZhishuShopGoodsBo bo = map.get("params") != null ? MapUtils.convertToObject((Map) map.get("params"),ZhishuShopGoodsBo.class) : null; + if(bo == null){ + bo = new ZhishuShopGoodsBo(); + bo.setIsQueryAllGoods(1); + } + bo.setUserId(userId); + int pageNum = 1,pageSize = 1000; + //查询全部自营商品数据一键发布 + PageQuery pageQuery = new PageQuery(pageSize,pageNum); + String createResStr = map.get("createResStr").toString(); + Map createResMap = JsonUtil.transferToObj(createResStr,Map.class); + String taskId = createResMap.get("data").toString(); + List> bodyList = new ArrayList<>(); + if (usageCount > 0){ + if(bookList.isEmpty()){ + //一键发布 + while (true){ + pageQuery.setPageNum(pageNum); + pageQuery.setPageSize(pageSize); + Page pageList = queryPageList2(bo, pageQuery); + + List zhishuShopGoodsVoList = pageList.getRecords(); + // 提取列表中的全部商品id + List shopGoodsIds = zhishuShopGoodsVoList.stream() + .map(vo -> Long.valueOf(vo.getId())) // String转Long + .collect(Collectors.toList()); + // 查询是否存在商品记录 + List result = shopGoodsPublishedService.selectByShopGoodsIds(shopGoodsIds,shopVo.getId()); + // 提取查询到的已存在发布记录的商品id + Set publishedGoodsIds = result.stream() + .map(vo -> Long.valueOf(vo.getShopGoodsId())) + .collect(Collectors.toSet()); + + + // 过滤掉已发布的商品(即不在publishedGoodsIds中的保留) + List filteredList = zhishuShopGoodsVoList.stream() + .filter(vo -> !publishedGoodsIds.contains(Long.valueOf(vo.getId()))) + .collect(Collectors.toList()); + + // 替换原列表(如果需要) + zhishuShopGoodsVoList = filteredList; + + for (ZhishuShopGoodsVo zhishuShopGoodsVo : zhishuShopGoodsVoList){ + String goodsId = zhishuShopGoodsVo.getId(); + String isbn = zhishuShopGoodsVo.getIsbn(); + String bookName = zhishuShopGoodsVo.getGoodsName(); + String price = zhishuShopGoodsVo.getPrice().divide(new BigDecimal(100)).toString(); + String stock = zhishuShopGoodsVo.getInventory().toString(); + // 品相 + String conditionCode = StringUtils.isEmpty(zhishuShopGoodsVo.getConditionCode()) ? "" : zhishuShopGoodsVo.getConditionCode(); + String artNo = StringUtils.isEmpty(zhishuShopGoodsVo.getArtNo()) ? "" : zhishuShopGoodsVo.getArtNo(); + // 运费 + String templateMinPrice = zhishuShopGoodsVo.getTemplateMinPrice() == null ? "" : zhishuShopGoodsVo.getTemplateMinPrice().toString(); + List zhishuShopImagesVoList = zhishuShopImagesService.selectShopImagesByShopId(goodsId); + Map body = new HashMap(); + Map bookInfo = new HashMap(); + bookInfo.put("isbn",isbn); + bookInfo.put("book_name",bookName); + if(!zhishuShopImagesVoList.isEmpty()){ + JSONObject imageObject = new JSONObject(); + List carouselUrlArray = new ArrayList<>(); + for (ZhishuShopImagesVo zhishuShopImagesVo : zhishuShopImagesVoList){ + String path = zhishuShopImagesVo.getPath(); + // 只有拼多多店铺并且是孔夫子图片上传图片 + if(path.contains("www0.kfzimg.com") && shopVo.getShopType().equals("1")){ + path = path.replace("_s","_n"); + Map imgMap = new HashMap(); + imgMap.put("shop_id",shopVo.getId().toString()); + imgMap.put("img_url",path); + String pddImgData = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/uploadImg/ImgUploadToPdd",imgMap); + Map pddImgMap = JsonUtil.transferToObj(pddImgData,Map.class); + if (pddImgMap.get("code").equals("200")){ + path = pddImgMap.get("data").toString(); + } + } + carouselUrlArray.add(path); + } + imageObject.put("carousel_url_array",carouselUrlArray); + bookInfo.put("image_object",imageObject); + } + body.put("book_info",bookInfo); + Map detail = new HashMap(); + BigDecimal totalPrice = new BigDecimal(price).multiply(new BigDecimal(100)); + detail.put("price",totalPrice.longValue()); + detail.put("stock",Long.parseLong(stock)); + // 商品编码 + detail.put("out_goods_id",isbn); + // 规格编码 + detail.put("sku_code",artNo); + // 运费 + detail.put("shipping_cost",new BigDecimal(templateMinPrice).multiply(new BigDecimal(100)).longValue()); + // 品相 + detail.put("condition",Integer.parseInt(CnumberUtils.getQualityNum(conditionCode))); + // 上下架状态 + detail.put("is_onsale",0); + //商品id + JSONObject json = new JSONObject(); + json.put("erp_goods_id",goodsId); + json.put("user_id",userId+""); + detail.put("msg",json.toString()); + body.put("detail",detail); + bodyList.add(body); + if (bodyList.size() % 1000 == 0){ + String response = InterfaceUtils.postTaskBodyWithSign(UrlUtil.getNewTaskUrl(), "/task/setTaskBody", taskId, bodyList); + System.out.println("新发布任务发布"+bodyList.size()+"条"); + // 清空列表,准备下一批 + bodyList.clear(); + } + } + if (!bodyList.isEmpty()) { + String response = InterfaceUtils.postTaskBodyWithSign(UrlUtil.getNewTaskUrl(), "/task/setTaskBody", taskId, bodyList); + System.out.println("新发布任务发布"+bodyList.size()+"条"); + // 清空列表,准备下一批 + bodyList.clear(); + } + pageNum++; + + usageCount--; + //获取总数 + if((pageList.getTotal() / 1000 + 1) < pageNum || pageList.getRecords().isEmpty() || usageCount == 0){ + break; + } + } + }else{ + + // 提取列表中的全部商品id + List shopGoodsIds = bookList.stream() + .map(vo -> Long.valueOf(vo.get(0).toString())) // String转Long + .collect(Collectors.toList()); + // 查询是否存在商品记录 + List result = shopGoodsPublishedService.selectByShopGoodsIds(shopGoodsIds,shopVo.getId()); + // 提取查询到的已存在发布记录的商品id + Set publishedGoodsIds = result.stream() + .map(vo -> Long.valueOf(vo.getShopGoodsId())) + .collect(Collectors.toSet()); + + // 过滤掉已发布的商品(即不在publishedGoodsIds中的保留) + List filteredList = bookList.stream() + .filter(vo -> !publishedGoodsIds.contains(Long.valueOf(vo.get(0).toString()))) + .collect(Collectors.toList()); + + // 替换原列表(如果需要) + bookList = filteredList; + + for (List list : bookList) { + String goodsId = list.get(0).toString(); + String isbn = list.get(1).toString(); + String bookName = list.get(2).toString(); + String price = new BigDecimal(list.get(3).toString()).divide(new BigDecimal(100)).toString(); + String stock = list.get(4).toString(); + // 品相 + String conditionCode = list.get(5) == null ? "" : list.get(5).toString(); + String artNo = list.get(6) == null ? "" : list.get(6).toString(); + // 运费 + String templateMinPrice = list.get(7) == null ? "" : list.get(7).toString(); + List zhishuShopImagesVoList = zhishuShopImagesService.selectShopImagesByShopId(goodsId); + Map body = new HashMap(); + Map bookInfo = new HashMap(); + bookInfo.put("isbn",isbn); + bookInfo.put("book_name",bookName); + if(!zhishuShopImagesVoList.isEmpty()){ + JSONObject imageObject = new JSONObject(); + List carouselUrlArray = new ArrayList<>(); + for (ZhishuShopImagesVo zhishuShopImagesVo : zhishuShopImagesVoList){ + String path = zhishuShopImagesVo.getPath(); + if(path.contains("www0.kfzimg.com")){ + path = path.replace("_s","_n"); + Map imgMap = new HashMap(); + imgMap.put("shop_id",shopVo.getId().toString()); + imgMap.put("img_url",path); + String pddImgData = InterfaceUtils.postFormWithSign(UrlUtil.getNewTaskUrl(),"/uploadImg/ImgUploadToPdd",imgMap); + Map pddImgMap = JsonUtil.transferToObj(pddImgData,Map.class); + if (pddImgMap.get("code").equals("200")){ + path = pddImgMap.get("data").toString(); + } + } + carouselUrlArray.add(path); + } + imageObject.put("carousel_url_array",carouselUrlArray); + bookInfo.put("image_object",imageObject); + } + body.put("book_info",bookInfo); + Map detail = new HashMap(); + BigDecimal totalPrice = new BigDecimal(price).multiply(new BigDecimal(100)); + detail.put("price",totalPrice.longValue()); + detail.put("stock",Long.parseLong(stock)); + // 商品编码 + detail.put("out_goods_id",isbn); + // 规格编码 + detail.put("sku_code",artNo); + // 运费 + detail.put("shipping_cost",new BigDecimal(templateMinPrice).multiply(new BigDecimal(100)).longValue()); + // 品相 + detail.put("condition",Integer.parseInt(CnumberUtils.getQualityNum(conditionCode))); + // 上下架状态 + detail.put("is_onsale",0); + // erp 商品id + JSONObject json = new JSONObject(); + json.put("erp_goods_id",goodsId); + json.put("user_id",userId+""); + detail.put("msg",json.toString()); + body.put("detail",detail); + bodyList.add(body); + if (bodyList.size() % 1000 == 0){ + String response = InterfaceUtils.postTaskBodyWithSign(UrlUtil.getNewTaskUrl(), "/task/setTaskBody", taskId, bodyList); + System.out.println("新发布任务发布"+bodyList.size()+"条"); + // 清空列表,准备下一批 + bodyList.clear(); + } + + usageCount--; + if (usageCount == 0){ + break; + } + } + // 处理剩余数据 + if (!bodyList.isEmpty()) { + String response = InterfaceUtils.postTaskBodyWithSign(UrlUtil.getNewTaskUrl(), "/task/setTaskBody", taskId, bodyList); + System.out.println("新发布任务发布结束:"+bodyList.size()+"条"); + } + } + + + // 更新使用次数 + shopService.updateUsageCount(shopVo,usageCount); + } + } + + // 线程暂停 + public void taskWait(String threadId) { + if (runMap.get(threadId)) { + try { + synchronized (lockMap.get(threadId)) { + lockMap.get(threadId).wait(); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public int zanTing(String threadId) { + if (runMap.get(threadId) == null) { + return 0; + } + runMap.put(threadId, true); + return 1; + } + + @Override + public int huanXing(String threadId) { + if (lockMap.get(threadId) == null) { + return 0; + } + synchronized (lockMap.get(threadId)) { + runMap.put(threadId, false); + lockMap.get(threadId).notify(); + } + return 1; + } + + @Override + public List selectShopStockLog(String id) { + List list = baseMapper.selectStockLog(id); + try{ + if (!list.isEmpty()) { + Map params = new HashMap<>(); + params.put("jsonList",JsonUtil.transferToJson(list)); + String result = InterfaceUtils.getInterfaceGetWithParams(UrlUtil.getOrderServiceUrl(),"/api/erpGoodsOrder/handleShopStockLog",params); + list = JsonUtil.transferToObj(result,List.class); + } + } catch (Exception e){ + System.out.println("关联数据查询失败"); + } + return list; + } + + @Override + public Integer queryInventory(Long shopGoodsId) { + String inventoryKey = "zhishu_shop_goods_inventory:" + shopGoodsId; + // 获取当前库存数量 + RList inventoryList = RedisUtils.getClient().getList(inventoryKey); + int currentInventorySize = inventoryList.size(); + if (currentInventorySize == 0) { + return 0; + } else { + return currentInventorySize; + } + } + + @Override + public List getAuthorAndPublisher(String keyword, String cookies) { + // 定义两个URL + String authorUrl = "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/more/author/facet"; + String pressUrl = "https://search.kongfz.com/pc-gw/search-web/client/pc/product/keyword/more/press/facet"; + + // 构建请求参数 + Map params = new HashMap<>(); + params.put("keyword", keyword); + + // 存储结果的列表 + List resultList = new ArrayList<>(); + + try { + // 构建作者查询URL + StringBuilder authorUrlWithParams = new StringBuilder(authorUrl); + if (!params.isEmpty()) { + authorUrlWithParams.append("?"); + for (Map.Entry entry : params.entrySet()) { + String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8); + String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8); + authorUrlWithParams.append(encodedKey).append("=").append(encodedValue).append("&"); + } + authorUrlWithParams.deleteCharAt(authorUrlWithParams.length() - 1); + } + + // 构建出版社查询URL + StringBuilder pressUrlWithParams = new StringBuilder(pressUrl); + if (!params.isEmpty()) { + pressUrlWithParams.append("?"); + for (Map.Entry entry : params.entrySet()) { + String encodedKey = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8); + String encodedValue = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8); + pressUrlWithParams.append(encodedKey).append("=").append(encodedValue).append("&"); + } + pressUrlWithParams.deleteCharAt(pressUrlWithParams.length() - 1); + } + + // 构建HTTP客户端 + HttpClient client = HttpClient.newBuilder() + .executor(Executors.newFixedThreadPool(20)) + .connectTimeout(Duration.ofSeconds(5)) + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.NORMAL) + .proxy(ProxySelector.getDefault()) + .build(); + + // 发送作者查询请求 + HttpRequest authorRequest = HttpRequest.newBuilder() + .uri(URI.create(authorUrlWithParams.toString())) + .header("Cookie", "PHPSESSID=" + cookies) + .GET() + .build(); + + // 发送出版社查询请求 + HttpRequest pressRequest = HttpRequest.newBuilder() + .uri(URI.create(pressUrlWithParams.toString())) + .header("Cookie", "PHPSESSID=" + cookies) + .GET() + .build(); + + // 执行请求并获取响应 + HttpResponse authorResponse = client.send(authorRequest, HttpResponse.BodyHandlers.ofString()); + HttpResponse pressResponse = client.send(pressRequest, HttpResponse.BodyHandlers.ofString()); + + // 解析作者响应 + if (authorResponse.statusCode() == 200) { + JSONObject authorJson = JSON.parseObject(authorResponse.body()); + if (authorJson != null && authorJson.getJSONObject("data") != null) { + JSONArray authorLabels = authorJson.getJSONObject("data").getJSONArray("labels"); + if (authorLabels != null) { + for (int i = 0; i < authorLabels.size(); i++) { + JSONObject label = authorLabels.getJSONObject(i); + AuthorPressVo vo = new AuthorPressVo(); + vo.setAuthor(label.getString("showName")); + resultList.add(vo); + } + } + } + } + + // 解析出版社响应 + if (pressResponse.statusCode() == 200) { + JSONObject pressJson = JSON.parseObject(pressResponse.body()); + if (pressJson != null && pressJson.getJSONObject("data") != null) { + JSONArray pressLabels = pressJson.getJSONObject("data").getJSONArray("labels"); + if (pressLabels != null) { + for (int i = 0; i < pressLabels.size(); i++) { + JSONObject label = pressLabels.getJSONObject(i); + AuthorPressVo vo = new AuthorPressVo(); + vo.setPress(label.getString("showName")); + resultList.add(vo); + } + } + } + } + + } catch (Exception e) { + log.error("获取作者和出版社信息失败: {}", e.getMessage(), e); + throw new ServiceException("获取作者和出版社信息失败: " + e.getMessage()); + } + + return resultList; + } + + + @Override + public ProductSubmitResultVo submitFromCopyrightPage(ProductForm form) { + // 书名去除首位空格 + form.setName(form.getName().trim()); + String depotName = form.getDepotName(); + if (StringUtils.isBlank(depotName)) { + throw new IllegalArgumentException("仓库名称不能为空"); + } + + Long userId = sysUserMapper.selectUserIdByNameAndPassWord(form.getPhoneNumber()); + Long depotId = TDepotMapper.getDepotIdByName(depotName, userId); + Long shelvesId = TShelvesMapper.getShelvesIdByName(form.getShelvesName(), depotId); + //获取三级货区信息 + TFreightVo freightVo = TFreightMapper.selectByFreightName(form.getFreightName(), shelvesId); + Long freightId = freightVo.getId(); + // 获取品相数值 + // 中文 + String conCodeTxt = form.getConditionCode(); + // 对应的数值 + String conCode = CnumberUtils.getQualityNum(conCodeTxt); + // 对应的字母 + String letterCode = CnumberUtils.getQualityNum(conCode); + + if (conCode == null) { + throw new IllegalArgumentException("无效的中文品相名称: " + conCode); + } + // 获取货号 + String artNo = cnumberUtils.getArtNo(Double.valueOf(new BigDecimal(conCode).divide(new BigDecimal(10)).toString()), userId, form.getBarcode(), depotId, shelvesId, freightId, form.getSeries()); + // 根据isbn 货号 userid 品相 价格 查询是否存在一样的数据 + long count = baseMapper.selectCountByIsbnAndArtNoAndUserIdAndBarcode(form.getBarcode(), artNo, userId.toString(), letterCode, form.getPrice().toString()); + + ZhishuShopGoods shopGoods = new ZhishuShopGoods(); + ShopGoodIsbn shopGoodIsbn = new ShopGoodIsbn(); + + if (count == 0) { + // 添加库存表 + shopGoods.setIsbn(form.getBarcode()); + shopGoods.setGoodsName(form.getName()); + shopGoods.setUserId(userId); + shopGoods.setPrice(form.getPrice()); + shopGoods.setProductId(""); + shopGoods.setConditionCode(letterCode); + shopGoods.setDepotId(depotId); + shopGoods.setTenantId("000000"); + shopGoods.setFixPrice(form.getFixPrice()); + shopGoods.setInventory(Long.valueOf(0)); + // 根据仓库获取Id + shopGoods.setArtNo(artNo); + //新增分销字段 + shopGoods.setIsJoinDistribution(Integer.parseInt(StringUtils.isNotEmpty(freightVo.getAllowDistribution()) ? freightVo.getAllowDistribution() : "0")); + baseMapper.insert(shopGoods); + List list = form.getFiles(); + for (FilesVo filesVo : list) { + ZhishuShopImagesBo zhishuShopImagesBo = new ZhishuShopImagesBo(); + zhishuShopImagesBo.setGoodsId(shopGoods.getId()); + zhishuShopImagesBo.setPath(filesVo.getUrl()); + zhishuShopImagesService.insertByBo(zhishuShopImagesBo); + } + operatingInventory(1, shopGoods.getId(), Math.toIntExact(form.getInventory()), 4, null, userId); + shopGoods.setInventory(form.getInventory()); + if (form.getBarcode() != null && form.getBarcode().length() == 13 && !form.getBarcode().startsWith("9")) { + shopGoods.setTemplateType("2"); + } + shopGoods.setAuthor(form.getAuthor()); + shopGoods.setPublisher(form.getPublisher()); + shopGoods.setFormat(form.getFormat()); + shopGoods.setPrintTime(form.getPrintTime()); + shopGoods.setWordage(form.getWordage()); + shopGoods.setGoodUnifyIsbn(form.getGoodUnifyIsbn()); + shopGoodIsbn.setGoodIsbn(form.getBarcode()); + shopGoodIsbn.setShopGoodsId(shopGoods.getId()); + shopGoodIsbn.setGoodUnifyIsbn(form.getGoodUnifyIsbn()); + shopGoodIsbnMapper.insert(shopGoodIsbn); + if (form.getBarcode() == null) { + // 增加商品审核 + TBookAudit tBookAudit = new TBookAudit(); + tBookAudit.setGoodsName(form.getName()); + tBookAudit.setIsbn(form.getBarcode()); + tBookAudit.setUserId(userId); + tBookAudit.setProductId(""); + tBookAudit.setArtNo(artNo); + tBookAudit.setPrice(form.getPrice()); + tBookAudit.setFixPrice(form.getFixPrice()); + tBookAudit.setConditionCode(letterCode); + tBookAudit.setInventory(Long.valueOf(form.getInventory())); + tBookAudit.setTenantId("000000"); + tBookAudit.setStatus("2"); + tBookAuditMapper.insert(tBookAudit); + } + } else if (count > 0) { + ZhishuShopGoods existingGoods = baseMapper.selectartNoByIsbnAndConditionCodeAndArtNo(form.getBarcode(), letterCode, artNo, form.getPrice(), userId); + // 价格相同 修改 + long newInventory = existingGoods.getInventory() + form.getInventory(); + shopGoods.setId(existingGoods.getId()); + List list = form.getFiles(); + for (FilesVo filesVo : list) { + ZhishuShopImagesBo zhishuShopImagesBo = new ZhishuShopImagesBo(); + zhishuShopImagesBo.setGoodsId(shopGoods.getId()); + zhishuShopImagesBo.setPath(filesVo.getUrl()); + zhishuShopImagesService.insertByBo(zhishuShopImagesBo); + } + operatingInventory(1, shopGoods.getId(), Math.toIntExact(form.getInventory()), 4, null, userId); + shopGoods.setInventory(newInventory); + if (form.getBarcode() != null && form.getBarcode().length() == 13 && !form.getBarcode().startsWith("9")) { + shopGoods.setTemplateType("2"); + } + shopGoods.setAuthor(form.getAuthor()); + shopGoods.setPublisher(form.getPublisher()); + shopGoods.setFormat(form.getFormat()); + shopGoods.setPrintTime(form.getPrintTime()); + shopGoods.setWordage(form.getWordage()); + tBookAuditMapper.updateInventory(newInventory, userId, letterCode, artNo, form.getPrice(), form.getBarcode()); + } + + + /** + * 执行孔夫子店铺自动发布商品线程 + */ + shopGoods.setCategoryId(form.getCategoryId()); + shopGoods.setDepotId(depotId); + shopGoods.setPrice(form.getPrice()); + TDepotVo depotVo = depotService.queryById(depotId); + TLogisticsVo logisticsVo = logisticsService.queryById(depotVo.getTemplateId()); + if (logisticsVo == null) { + shopGoods.setTemplateMinPrice("0"); + } else { + shopGoods.setTemplateMinPrice(logisticsVo.getFirPrice() == null ? "0" : logisticsVo.getFirPrice().toString()); + } + System.out.println("shopGoods:" + shopGoods); + TShopDepotAotuMapper tShopDepotAotuMapper = applicationContext.getBean(TShopDepotAotuMapper.class); + KfzAutoAddRunnable kfzAutoAddRunnable = new KfzAutoAddRunnable(userId, shopService, shopDetailService, shopGoodsPublishedService, kongfzService, this, applicationContext, zhishuShopGoodsDetailService, shopGoods,tShopDepotAotuMapper); + Thread thread = new Thread(kfzAutoAddRunnable, "yxy-submitFromCopyrightPage"); + thread.setDaemon(true); // 设置为守护线程 + thread.start(); + + ProductSubmitResultVo result = new ProductSubmitResultVo(); + result.setGoodsId(shopGoods.getId()); + result.setUserId(userId); + result.setDepotId(depotId); + result.setShelvesId(shelvesId); + result.setFreightId(freightId); + result.setArtNo(artNo); + + return result; + } + + // 定义可用字符集 + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + private static final int LENGTH = 8; + + public static String generateRandomString() { + Random random = new Random(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < LENGTH; i++) { + int index = random.nextInt(CHARACTERS.length()); + sb.append(CHARACTERS.charAt(index)); + } + return sb.toString(); + } + + public TableDataInfo selectShopGoodsByPhoneNumber(String phoneNumber, int pageNum, int pageSize, String date) { + Long userId = sysUserMapper.selectUserIdByNameAndPassWord(phoneNumber); + + // 分页查询 + Page page = new Page<>(pageNum, pageSize); + + // 构建日期查询条件 + if (StringUtils.isNotEmpty(date)) { + // 将日期字符串转换为日期范围 + LocalDate localDate = LocalDate.parse(date); + LocalDateTime startOfDay = localDate.atStartOfDay(); + LocalDateTime endOfDay = localDate.plusDays(1).atStartOfDay().minusSeconds(1); + + // 使用日期范围查询 + Page goodsPage = baseMapper.selectShopGoodsByUserPageWithDate( + page, + userId, + Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()), + Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()) + ); + + List goodsList = goodsPage.getRecords(); + List goodsIds = goodsList.stream().map(ZhishuShopGoodsVo::getId).collect(Collectors.toList()); + + // 合并所有店铺ID + Map> shopIdsMap = getShopIdsByUserId(userId); + List allShopIds = new ArrayList<>(); + List pddShopIds = shopIdsMap.get("1"); + List kfzShopIds = shopIdsMap.get("2"); + List xyShopIds = shopIdsMap.get("5"); + if (pddShopIds != null) allShopIds.addAll(pddShopIds); + if (kfzShopIds != null) allShopIds.addAll(kfzShopIds); + if (xyShopIds != null) allShopIds.addAll(xyShopIds); + + // 查询所有商品的发布状态 + if (!goodsIds.isEmpty() && !allShopIds.isEmpty()) { + List> publishedStatusList = shopGoodsPublishedService.selectPublishedStatus(goodsIds, allShopIds); + Map> statusMap = publishedStatusList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> map, + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + Map status = statusMap.get(goods.getId()); + if (status != null) { + goods.setPddPublishedStatus((Long) status.get("pddStatus")); + goods.setKfzPublishedStatus((Long) status.get("kfzStatus")); + goods.setXyPublishedStatus((Long) status.get("xyStatus")); + } else { + goods.setPddPublishedStatus(0L); + goods.setKfzPublishedStatus(0L); + goods.setXyPublishedStatus(0L); + } + }); + } + + // 获取商品图片 + if (!goodsIds.isEmpty()) { + List> imagePathList = zhishuShopImagesMapper.batchQueryFirstPathByGoodsIds(goodsIds); + Map imagePathMap = imagePathList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> String.valueOf(map.get("path")), + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + String path = imagePathMap.get(goods.getId()); + if (path != null && !path.isEmpty()) { + try { +// String bookPic = uploadUtil.getFiles("", "", "", path); + goods.setBookPic(path); + } catch (Exception e) { + log.error("获取商品图片失败: goodsId={}, path={}", goods.getId(), path, e); + } + } + }); + } + + // 返回分页对象 + return TableDataInfo.build(goodsPage); + } else { + // 如果没有日期参数,使用原来的查询方法 + Page goodsPage = baseMapper.selectShopGoodsByUserPage(page, userId); + List goodsList = goodsPage.getRecords(); + List goodsIds = goodsList.stream().map(ZhishuShopGoodsVo::getId).collect(Collectors.toList()); + + // 合并所有店铺ID + Map> shopIdsMap = getShopIdsByUserId(userId); + List allShopIds = new ArrayList<>(); + List pddShopIds = shopIdsMap.get("1"); + List kfzShopIds = shopIdsMap.get("2"); + List xyShopIds = shopIdsMap.get("5"); + if (pddShopIds != null) allShopIds.addAll(pddShopIds); + if (kfzShopIds != null) allShopIds.addAll(kfzShopIds); + if (xyShopIds != null) allShopIds.addAll(xyShopIds); + + // 查询所有商品的发布状态 + if (!goodsIds.isEmpty() && !allShopIds.isEmpty()) { + List> publishedStatusList = shopGoodsPublishedService.selectPublishedStatus(goodsIds, allShopIds); + Map> statusMap = publishedStatusList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> map, + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + Map status = statusMap.get(goods.getId()); + if (status != null) { + goods.setPddPublishedStatus((Long) status.get("pddStatus")); + goods.setKfzPublishedStatus((Long) status.get("kfzStatus")); + goods.setXyPublishedStatus((Long) status.get("xyStatus")); + } else { + goods.setPddPublishedStatus(0L); + goods.setKfzPublishedStatus(0L); + goods.setXyPublishedStatus(0L); + } + }); + } + + // 获取商品图片 + if (!goodsIds.isEmpty()) { + List> imagePathList = zhishuShopImagesMapper.batchQueryFirstPathByGoodsIds(goodsIds); + Map imagePathMap = imagePathList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> String.valueOf(map.get("path")), + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + String path = imagePathMap.get(goods.getId()); + if (path != null && !path.isEmpty()) { + try { +// String bookPic = uploadUtil.getFiles("", "", "", path); + goods.setBookPic(path); + } catch (Exception e) { + log.error("获取商品图片失败: goodsId={}, path={}", goods.getId(), path, e); + } + } + }); + } + + // 返回分页对象 + return TableDataInfo.build(goodsPage); + } + } + + + @Override + public Map selectDepotIds(String userId, String artNo) { + ArrayList list = new ArrayList(); + + String dcode = artNo.substring(0, 2); + // 当货号第三位是字母时,截取第三和第四位,若为数字,截取第三位 + String scode = ""; + String fcode = ""; + if (artNo.charAt(2) >= 'A' && artNo.charAt(2) <= 'Z') { + scode = artNo.substring(2, 4); + fcode = artNo.substring(4, 5); + } else { + scode = artNo.substring(2, 3); + fcode = artNo.substring(3, 5); + } + + // 查询一级二级三级获取 + Map map = baseMapper.selectArt(userId, dcode, scode, fcode); + + return map; + } + + @Override + public StockChangeLog queryStockChangeLogByOrderSn(String orderSn, Integer type) { + List list = new LambdaQueryChainWrapper<>(stockChangeLogMapper) + .eq(StockChangeLog::getAboutId, orderSn) + .eq(StockChangeLog::getType, type) + .ne(StockChangeLog::getDelFlag, "1") + .list(); + if (!list.isEmpty()) + return list.get(0); + return null; + } + + @Override + public Boolean operatingGoodsSoldOut(Long shopId, Integer platformType, Integer logType, Integer operationType, ShopGoodsPublishedVo shopGoodsPublishedVo, String orderSn) { + // 根据商品Id查询出拥有同商品的店铺Id和平台商品Id + List shopGoodsPublishedVoList = shopGoodsPublishedService.queryByShopGoodsId(shopGoodsPublishedVo.getShopGoodsId()); + + // 过滤掉自己的 + shopGoodsPublishedVoList = shopGoodsPublishedVoList.stream().filter(o -> !o.getShopId().equals(shopId.toString())).toList(); + + // 循环根据店铺Id查询出店铺信息 + for (ShopGoodsPublishedVo goodsPublishedVo : shopGoodsPublishedVoList) { + // 根据店铺Id查询出店铺信息 + ShopVo shop = shopService.queryById(Long.valueOf(goodsPublishedVo.getShopId())); + if (shop == null){ + shopGoodsPublishedService.deleteWithValidByIds(List.of(goodsPublishedVo.getId()), true); + continue; + } + // 根据店铺类型分别推送平台同步库存 + InventorySynchronizedStrategy strategy = InventorySynchronizedStrategyFactory.getStrategy(shop.getShopType()); + strategy.operatingGoodsSoldOut(shop, goodsPublishedVo, platformType, logType, operationType, orderSn); + } + return true; + } + + /** + * 获取货区对应商品数据 + * + * @param code + * @param userId + * @param pageNum + * @param pageSize + * @return + */ + @Override + public TableDataInfo queryGoodListByArtNo(String code, Long userId, int pageNum, int pageSize, String date) { + // 分页查询 + Page page = new Page<>(pageNum, pageSize); + + // 构建日期查询条件 + if (StringUtils.isNotEmpty(date)) { + // 将日期字符串转换为日期范围 + LocalDate localDate = LocalDate.parse(date); + LocalDateTime startOfDay = localDate.atStartOfDay(); + LocalDateTime endOfDay = localDate.plusDays(1).atStartOfDay().minusSeconds(1); + + // 使用日期范围查询 + Page goodsPage = baseMapper.selectShopGoodsByUserPageWithDateArtNo( + page, + userId, + Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()), + Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()), + code + ); + + List goodsList = goodsPage.getRecords(); + List goodsIds = goodsList.stream().map(ZhishuShopGoodsVo::getId).collect(Collectors.toList()); + + // 合并所有店铺ID + Map> shopIdsMap = getShopIdsByUserId(userId); + List allShopIds = new ArrayList<>(); + List pddShopIds = shopIdsMap.get("1"); + List kfzShopIds = shopIdsMap.get("2"); + if (pddShopIds != null) allShopIds.addAll(pddShopIds); + if (kfzShopIds != null) allShopIds.addAll(kfzShopIds); + + // 查询所有商品的发布状态 + if (!goodsIds.isEmpty() && !allShopIds.isEmpty()) { + List> publishedStatusList = shopGoodsPublishedService.selectPublishedStatus(goodsIds, allShopIds); + Map> statusMap = publishedStatusList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> map, + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + Map status = statusMap.get(goods.getId()); + if (status != null) { + goods.setPddPublishedStatus((Long) status.get("pddStatus")); + goods.setKfzPublishedStatus((Long) status.get("kfzStatus")); + } else { + goods.setPddPublishedStatus(0L); + goods.setKfzPublishedStatus(0L); + } + }); + } + + // 获取商品图片 + if (!goodsIds.isEmpty()) { + List> imagePathList = zhishuShopImagesMapper.batchQueryFirstPathByGoodsIds(goodsIds); + Map imagePathMap = imagePathList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> String.valueOf(map.get("path")), + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + String path = imagePathMap.get(goods.getId()); + if (path != null && !path.isEmpty()) { + try { +// String bookPic = uploadUtil.getFiles(null, goods.getGoodsName(), path); + goods.setBookPic(path); + } catch (Exception e) { + log.error("获取商品图片失败: goodsId={}, path={}", goods.getId(), path, e); + } + } + }); + } + + // 返回分页对象 + return TableDataInfo.build(goodsPage); + } else { + // 如果没有日期参数,使用原来的查询方法 + Page goodsPage = baseMapper.selectShopGoodsByUserPageArtNo(page, userId, code); + List goodsList = goodsPage.getRecords(); + List goodsIds = goodsList.stream().map(ZhishuShopGoodsVo::getId).collect(Collectors.toList()); + + // 合并所有店铺ID + Map> shopIdsMap = getShopIdsByUserId(userId); + List allShopIds = new ArrayList<>(); + List pddShopIds = shopIdsMap.get("1"); + List kfzShopIds = shopIdsMap.get("2"); + if (pddShopIds != null) allShopIds.addAll(pddShopIds); + if (kfzShopIds != null) allShopIds.addAll(kfzShopIds); + + // 查询所有商品的发布状态 + if (!goodsIds.isEmpty() && !allShopIds.isEmpty()) { + List> publishedStatusList = shopGoodsPublishedService.selectPublishedStatus(goodsIds, allShopIds); + Map> statusMap = publishedStatusList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> map, + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + Map status = statusMap.get(goods.getId()); + if (status != null) { + goods.setPddPublishedStatus((Long) status.get("pddStatus")); + goods.setKfzPublishedStatus((Long) status.get("kfzStatus")); + } else { + goods.setPddPublishedStatus(0L); + goods.setKfzPublishedStatus(0L); + } + }); + } + + // 获取商品图片 + if (!goodsIds.isEmpty()) { + List> imagePathList = zhishuShopImagesMapper.batchQueryFirstPathByGoodsIds(goodsIds); + Map imagePathMap = imagePathList.stream() + .collect(Collectors.toMap( + map -> String.valueOf(map.get("goodsId")), + map -> String.valueOf(map.get("path")), + (v1, v2) -> v1 + )); + goodsList.forEach(goods -> { + String path = imagePathMap.get(goods.getId()); + if (path != null && !path.isEmpty()) { + try { +// String bookPic = uploadUtil.getFiles(null, goods.getGoodsName(), path); + goods.setBookPic(path); + } catch (Exception e) { + log.error("获取商品图片失败: goodsId={}, path={}", goods.getId(), path, e); + } + } + }); + } + + // 返回分页对象 + return TableDataInfo.build(goodsPage); + } + } + + /** + * 根据用户ID查询商品数量 + * + * @param userId 用户ID + * @return 商品数量 + */ + @Override + public Long queryGoodsCountByUserId(Long userId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(ZhishuShopGoods.class); + lqw.eq(ZhishuShopGoods::getUserId, userId); + return baseMapper.selectCount(lqw); + } + + @Override + public SysUser queryUserByUserId(Long userId) { + return sysUserMapper.selectUserById(userId); + } + + /** + * 批量移动商品位置 + * + * @param itemIds 商品ID列表 + * @param userId 用户ID + * + * @return 操作结果 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public String batchMoveItems(List itemIds, String warehouse, String shelf, String freight, Long userId) { + if (itemIds == null || itemIds.isEmpty()) { + return "请选择要移动的商品"; + } + + +// // 检查仓库、货架、货位是否存在 + TDepotVo depot = baseMapper.selectDepotName(userId, warehouse); + if (depot == null) { + return "仓库编码不存在"; + } + + Long sheId = baseMapper.selectSheId(depot.getId(), shelf); + if (sheId == null) { + return "货架编码不存在"; + } + + Long freId = baseMapper.selectFreId(sheId, freight); + if (freId == null) { + return "货位编码不存在"; + } + // 拼接新的货号 + String newLocationCode = warehouse + shelf + freight; + // 校验是否为五位 + if (newLocationCode.length() != 5) { + return "货位编码长度必须为5位"; + } + + int successCount = 0; + StringBuilder failItems = new StringBuilder(); + + for (String id : itemIds) { + try { + // 查询商品信息 + ZhishuShopGoodsVo goodsVo = baseMapper.selectByIdVo(id); + if (goodsVo == null) { + failItems.append(id).append("(商品不存在),"); + continue; + } + + // 获取原货号,保留后面的部分 + String artNo = goodsVo.getArtNo(); + String newArtNo = ""; + + // 处理新的货号 + if (artNo.length() > 5) { + // 替换前5位,保留后面的部分 + newArtNo = newLocationCode + artNo.substring(5); + } else if(artNo.isEmpty()){ + return "原货号错误"; + } + + // 更新商品货号 + ZhishuShopGoodsBo updateBo = new ZhishuShopGoodsBo(); + updateBo.setId(id); + updateBo.setArtNo(newArtNo); + updateBo.setUserId(userId); + updateBo.setDepotId(depot.getId()); + boolean updateByBo =baseMapper.updateByArtNo(updateBo); + if (updateByBo) { + successCount++; + } else { + failItems.append(id).append("(更新失败),"); + } + // 同时插入货号移动表 + ArtNoMove artNoMove = new ArtNoMove(); + ZhishuShopGoods zhishuShopGoods = baseMapper.selectById(id); + artNoMove.setOldArtNo(artNo); + artNoMove.setNewArtNo(newArtNo); + artNoMove.setUserId(userId); + artNoMove.setOldDepotId(zhishuShopGoods.getDepotId()); + artNoMove.setNewDepotId(depot.getId()); + artNoMove.setCreateBy(userId); + artNoMove.setUpdateBy(userId); + // 插入时间戳 + artNoMove.setCreateTime(System.currentTimeMillis()); + artNoMove.setUpdateTime(System.currentTimeMillis()); + artNoMove.setIsDel(0L); + artNoMoveMapper.insert(artNoMove); + } catch (Exception e) { + log.error("批量移动商品位置异常,商品ID:{}", id, e); + failItems.append(id).append("(").append(e.getMessage()).append("),"); + } + } + + if (successCount == itemIds.size()) { + return "成功移动" + successCount + "件商品"; + } else { + return "成功移动" + successCount + "件商品,失败" + (itemIds.size() - successCount) + "件:" + failItems; + } + } + + @Override + public int updateByArtNoPrefix(String isJoinDistribution,String artNoPrefix,Long userId, Long limitNum){ + return baseMapper.updateByArtNoPrefix(isJoinDistribution,artNoPrefix,userId,limitNum); + } + + @Override + public int batchUpdateCargo(BatchUpdateCargoBo bo) { + //分别获取bo.getAres中的三个货区Id + Long deId = bo.getAreas().get(0); + Long shId = bo.getAreas().get(1); + Long frId = bo.getAreas().get(2); + String beartNo = baseMapper.getSelectArtNo(deId, shId, frId, bo.getUserId()); + Integer flag = baseMapper.batchUpdateartNo(deId, beartNo, bo.getIds()); + return flag; + } + + @Override + public void createShopGoodsList(BatchGoodsRequest request) { + System.out.println("zhuxiaodong=================== createShopGoodsList"); + Long shopId = request.getShopId(); + ShopVo shopVo = shopService.queryById(shopId); + System.out.println("zhuxiaodong=================== createShopGoodsList"+request.getBatchData()); + new Thread(() -> { + + createShopGoodsList(shopVo, request); + }).start(); + System.out.println("zhuxiaodong=================== Thread"+Thread.currentThread().getId()); + + } + + @Override + public void deleteTaskDataByShopId(Long shopId) { + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopId); + if (checkMark == 1) { + runningTaskByShopService.deleteAll("t_running_task_" + shopId); + } + } + + private void createShopGoodsList(ShopVo shopVo, BatchGoodsRequest request) { + log.info("任务开始:" + DateUtils.dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS)+request.getBatchData()); + System.out.println("zhuxiaodong==================="); + System.out.println("任务开始:" + DateUtils.dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS)+request.getBatchData()); + System.out.println("zhuxiaodong==================="); + // 根据shopId查询数据表是否存在 + int checkMark = runningTaskByShopService.checkTableExists("t_running_task_" + shopVo.getId()); + if (checkMark == 0) { + // 不存在则创建表 + runningTaskByShopService.createTable("t_running_task_" + shopVo.getId()); + } + List dataList = request.getBatchData(); + + if (dataList.isEmpty()) { + return; + } + + TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); + + transactionTemplate.execute(status -> { + try { + // 批量检查存在性(在事务内) + Map existsMap = runningTaskByShopService + .batchCheckGoodsIdExists("t_running_task_" + shopVo.getId(), + dataList.stream() + .map(ZhishuShopGoodsRequest::getItemNumber) + .collect(Collectors.toList())); + + // 过滤并构建数据 + List runningTaskList = dataList.stream() + .filter(item -> !existsMap.getOrDefault(item.getItemNumber(), false)) + .map(item -> buildRunningTask(shopVo, request, item)) + .collect(Collectors.toList()); + + log.info("过滤后需要插入的数据量: {},跳过重复数据: {}", + runningTaskList.size(), dataList.size() - runningTaskList.size()); + + // 批量插入 + if (!runningTaskList.isEmpty()) { + runningTaskByShopService.batchInsert("t_running_task_" + shopVo.getId(), runningTaskList); + runningTaskByShopService.updateStatus("t_running_task_" + shopVo.getId()); + } + + return null; + } catch (Exception e) { + status.setRollbackOnly(); + log.error("批量插入商品数据失败: {}", e.getMessage(), e); + throw e; + } + }); + + if (request.getIsLastBatch()) { + RedisUtils.setCacheObject("lastGoodsSynTime_" + shopVo.getId(), + DateUtilsUtils.getNowDate()); + } + + + // 添加数据 + // if (dataList.size() > 0) { + // List runningTaskList = new ArrayList<>(); + // for (ZhishuShopGoodsRequest map : dataList) { + // + // + // + // // 构建 JSON 对象 + // JSONObject json = new JSONObject(); + // // 平台的商品id + // json.put("trilateralId", map.getItemNumber()); + // json.put("author", map.getAuthor()); + // json.put("publisher", map.getPublisher()); + // json.put("publisherTime", map.getPublisherTime()); + // json.put("format", map.getFormat()); + // json.put("wordage", map.getWordage()); + // json.put("unifiedIsbn", map.getUnifiedIsbn()); + // json.put("img", map.getBookPic()); + // // 当前时间 + // json.put("finishTime", DateUtilsUtils.getNowDate()); + // json.put("imageSelect", "2"); + // // 商品价格单位分 + // json.put("totalPrice", map.getPrice()); + // // 书号 + // json.put("isbn", map.getIsbn()); + // // 权重不用管 + // json.put("priority", "3"); + // // 不用填,上传的实拍图 + // json.put("imageBigUrl", ""); + // // 商品标题 + // json.put("title", map.getGoodsName()); + // json.put("quality", map.getConditionCode()); + // json.put("shopType", shopVo.getShopType()); + // json.put("artNo", map.getArtNo()); + // // 库存 + // json.put("stock", map.getInventory()); + // json.put("isOnSale", "1"); + // json.put("skuCode", ""); + // json.put("skuId", ""); + // // json.put("isOnSale", map.get("is_onsale").toString()); + // // json.put("isMoreSku", map.get("is_more_sku").toString()); + // String jsonString = json.toString(); + // + // RunningTask runningTask = new RunningTask(); + // runningTask.setTaskId(request.getTaskId()); + // runningTask.setShopId(shopVo.getId()); + // runningTask.setGoodsId(Long.valueOf(map.getItemNumber())); + // runningTask.setRandomNum(System.currentTimeMillis()); + // runningTask.setTaskName("拉取孔网商品任务"); + // runningTask.setPriority(255L); + // runningTask.setData(""); + // runningTask.setStatus("2"); + // runningTask.setTaskType("GET_KW_SHOP_GOODS"); + // runningTask.setSuccessData(jsonString); + // runningTask.setCallBackData("拉取成功"); + // runningTaskList.add(runningTask); + // } + // if (ObjectUtil.isNotEmpty(runningTaskList)) { + // runningTaskByShopService.batchInsert("t_running_task_" + shopVo.getId(), runningTaskList); + // runningTaskByShopService.updateStatus("t_running_task_" + shopVo.getId()); + // } + // if (request.getIsLastBatch()) { + // RedisUtils.setCacheObject("lastGoodsSynTime_" + shopVo.getId(), DateUtilsUtils.getNowDate()); + // } + // } + } + + + private RunningTask buildRunningTask(ShopVo shopVo, BatchGoodsRequest request, + ZhishuShopGoodsRequest map) { + JSONObject json = buildGoodsJson(shopVo, map); + + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(request.getTaskId()); + runningTask.setShopId(shopVo.getId()); + runningTask.setGoodsId(Long.valueOf(map.getItemNumber())); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setTaskName("拉取孔网商品任务"); + runningTask.setPriority(255L); + runningTask.setData(""); + runningTask.setStatus("2"); + runningTask.setTaskType("GET_KW_SHOP_GOODS"); + runningTask.setSuccessData(json.toString()); + runningTask.setCallBackData("拉取成功"); + + return runningTask; + } + + private JSONObject buildGoodsJson(ShopVo shopVo, ZhishuShopGoodsRequest map) { + JSONObject json = new JSONObject(); + json.put("trilateralId", map.getItemNumber()); + json.put("author", map.getAuthor()); + json.put("publisher", map.getPublisher()); + json.put("publisherTime", map.getPublisherTime()); + json.put("format", map.getFormat()); + json.put("wordage", map.getWordage()); + json.put("unifiedIsbn", map.getUnifiedIsbn()); + json.put("img", map.getBookPic()); + json.put("finishTime", DateUtilsUtils.getNowDate()); + json.put("imageSelect", "11"); + json.put("totalPrice", map.getPrice()); + json.put("isbn", map.getIsbn()); + json.put("priority", "3"); + json.put("imageBigUrl", ""); + json.put("title", map.getGoodsName()); + json.put("quality", map.getConditionCode()); + json.put("shopType", shopVo.getShopType()); + json.put("artNo", map.getArtNo()); + json.put("stock", map.getInventory()); + json.put("isOnSale", "1"); + json.put("skuCode", ""); + json.put("skuId", ""); + return json; + } + + + + @Override + public void syncRunningTaskToShopGoods(Long shopId, Long freightId,Long userId,TaskBo taskBo) { + /** + * 查询货号 + */ + Map freightMap = TFreightMapper.selectByFreightId(freightId); + Long pageSize = 100L; + Long page = 1L; + + RunningTaskShopGoodsDto runningTaskShopGoodsDto = new RunningTaskShopGoodsDto(); + runningTaskShopGoodsDto.setTableName("t_running_task_"+shopId); + runningTaskShopGoodsDto.setTaskId(taskBo.getRelationId()); + runningTaskShopGoodsDto.setPageSize(pageSize); + while(true){ + /** + * 循环开始查询店铺商品数据进行同步自营书品操作 + */ + Long pageNum = (long) ((page - 1) * pageSize); + runningTaskShopGoodsDto.setPageNum(pageNum); + List shopGoodsMapList = runningTaskByShopService.selectGetShopGoodsListByDto(runningTaskShopGoodsDto); + if(shopGoodsMapList.isEmpty()){ + break; + } + for (Map shopGoodsMap : shopGoodsMapList){ + Map successData = JsonUtil.transferToObj(shopGoodsMap.get("success_data").toString(),Map.class); + String artNo = successData.get("artNo") == null ? "" : successData.get("artNo").toString(); + String trilateralId = successData.get("trilateralId") == null ? "" : successData.get("trilateralId").toString(); + String isbn = successData.get("isbn") == null ? "" : successData.get("isbn").toString(); + if(StringUtils.isEmpty(isbn)){ + isbn = generate13DigitId(); + } + /** + * 定义任务日志对象 + */ + String callBackData = ""; + + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(taskBo.getId()); + runningTask.setShopId(Long.valueOf(shopId)); + runningTask.setGoodsId(0L); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setTaskName("同步至自营书品任务"); + runningTask.setPriority(255L); + runningTask.setTaskType("SYNCHRONIZE_TO_ERP"); + runningTask.setStatus("3"); + + try{ + //校验货号是否符合规则 +// Boolean artNoIsOk = ArtNoUtil.validateArtNo(artNo); + ZhishuShopGoodsVo zhishuShopGoodsVo = baseMapper.selectShopGoodsByProductId(trilateralId,userId); + + if(zhishuShopGoodsVo == null){ + //若根据货号未查询到则根据店铺id和平台id查询商品 + zhishuShopGoodsVo = baseMapper.selectShopGoodsByShopIdAndPlatformId(shopId.toString(),trilateralId); + } + if(zhishuShopGoodsVo != null){ + /** + * 当前商品在自营书品中存在 则执行修改操作 + */ + ZhishuShopGoods zhishuShopGoods = new ZhishuShopGoods(); + zhishuShopGoods.setId(zhishuShopGoodsVo.getId()); + //获取库存 + if(successData.get("stock") != null){ + Long stock = Long.parseLong(successData.get("stock").toString()); + //比较新旧库存是否一致 + if(Long.parseLong(zhishuShopGoodsVo.getInventory()) != stock){ + //库存不一致,则进行修改操作 + zhishuShopGoods.setInventory(stock); + //记录旧库存 + successData.put("oldStock", zhishuShopGoodsVo.getInventory()); + } + } + if (successData.get("totalPrice") != null){ + Long price = Long.parseLong(successData.get("totalPrice").toString()); + //比较新旧价格是否一致 + Long oldPrice = zhishuShopGoodsVo.getPrice().longValue(); + if (!oldPrice.equals(price)) { + //价格不一致,则进行修改操作 + zhishuShopGoods.setPrice(price); + //记录旧价格 + successData.put("oldPrice", oldPrice); + } + } + //进行修改库存 + if(zhishuShopGoods.getInventory() != null || zhishuShopGoods.getPrice() != null){ + int updateMark = baseMapper.updateById(zhishuShopGoods); + if(zhishuShopGoods.getInventory() != null && updateMark >= 1){ + StockChangeLog stockChangeLog = new StockChangeLog(); + stockChangeLog.setShopGoodsId(Long.parseLong(zhishuShopGoodsVo.getId())); + stockChangeLog.setType(5); + stockChangeLog.setBeforeInv(Long.parseLong(zhishuShopGoodsVo.getInventory())); //初始库存 + stockChangeLog.setAfterInv(Long.parseLong(successData.get("stock").toString())); + stockChangeLog.setCreateBy(zhishuShopGoodsVo.getUserId()); + stockChangeLog.setUpdateBy(zhishuShopGoodsVo.getUserId()); + stockChangeLog.setCreateTime(DateUtils.getNowDate()); + stockChangeLog.setUpdateTime(DateUtils.getNowDate()); + stockChangeLog.setDelFlag("0"); + stockChangeLogMapper.insert(stockChangeLog); + + //记录日志 + callBackData += "修改库存成功;"; + } + if(zhishuShopGoods.getPrice() != null && updateMark > 1){ + callBackData += "修改价格成功;"; + } + + if(updateMark == 0){ + callBackData += "修改自营商品失败;"; + } + } + //查看是否存在已发布商品记录 + ShopGoodsPublishedVo shopGoodsPublishedVo = shopGoodsPublishedService.queryByPlatformId(shopId.toString(),trilateralId); + if (shopGoodsPublishedVo == null || !shopGoodsPublishedVo.getPlatformId().equals(trilateralId)){ + //不存在,或者三方平台对不上的情况则新增已发布商品记录 + ShopGoodsPublishedBo shopGoodsPublishedBo = new ShopGoodsPublishedBo(); + shopGoodsPublishedBo.setShopId(shopId+""); + shopGoodsPublishedBo.setShopGoodsId(zhishuShopGoodsVo.getId()); + shopGoodsPublishedBo.setPlatformId(trilateralId); + shopGoodsPublishedBo.setCreateBy(zhishuShopGoodsVo.getUserId()); + shopGoodsPublishedBo.setCreateTime(DateUtils.getNowDate()); + shopGoodsPublishedService.insertByBo(shopGoodsPublishedBo); + //记录日志 + callBackData += "新增已发布记录成功;"; + } + }else{ + //不存在,则执行新增操作 + //新增标记为空,代表需要进行新增操作 + ZhishuShopGoods zhishuShopGoods = new ZhishuShopGoods(); + zhishuShopGoods.setUserId(userId); + zhishuShopGoods.setProductId(trilateralId); + zhishuShopGoods.setIsJoinDistribution(freightMap.get("allow_distribution") == null ? 0 : Integer.parseInt(freightMap.get("allow_distribution").toString())); + zhishuShopGoods.setDepotId(Long.parseLong(freightMap.get("did").toString())); + zhishuShopGoods.setGoodsName((String) successData.get("title")); + zhishuShopGoods.setIsbn(isbn); + zhishuShopGoods.setPrice(Long.parseLong(successData.get("totalPrice").toString())); + // successData.get("quality") + + Double quality = new BigDecimal(successData.get("quality").toString()).divide(new BigDecimal(10)).setScale(1, RoundingMode.HALF_UP).stripTrailingZeros().doubleValue(); + zhishuShopGoods.setConditionCode(successData.get("quality") == null ? "K" : CODE_MAP.get(quality)); + zhishuShopGoods.setInventory(Long.parseLong(successData.get("stock").toString())); + zhishuShopGoods.setBookPic((String) successData.get("img")); + zhishuShopGoods.setOriginalArtNo((String) successData.get("artNo")); + zhishuShopGoods.setIsArtNoConversion(1); + zhishuShopGoods.setCreateBy(userId); + zhishuShopGoods.setUpdateBy(userId); + zhishuShopGoods.setCreateTime(DateUtils.getNowDate()); + zhishuShopGoods.setUpdateTime(DateUtils.getNowDate()); + Double s = 85.0; + try{ + s = convertChineseToCode(successData.get("quality").toString()); + }catch (Exception e){ + s = Double.parseDouble(successData.get("quality").toString()); + System.out.println("获取品相异常:"+e.getMessage()+";更改赋值:"+s); + } + s = s / 10; + artNo = cnumberUtils.getArtNo(s, userId, successData.get("isbn").toString(), Long.parseLong(freightMap.get("did").toString()), Long.parseLong(freightMap.get("sid").toString()), Long.parseLong(freightMap.get("fid").toString()), null); + zhishuShopGoods.setArtNo(artNo); + boolean flag = baseMapper.insert(zhishuShopGoods) > 0; + if(flag){ + //记录日志 + callBackData += "同步成功;"; + /** + * 新增成功后,增加 库存操作记录、已发布商品记录、商品实拍图。 + * 若是无效isbn则需要增加书籍信息 + */ + //新增库存操作记录 + StockChangeLog stockChangeLog = new StockChangeLog(); + stockChangeLog.setShopGoodsId(Long.parseLong(zhishuShopGoods.getId())); + stockChangeLog.setType(5); + stockChangeLog.setBeforeInv(0L); //初始库存 + stockChangeLog.setAfterInv(Long.parseLong(successData.get("stock").toString())); + stockChangeLog.setCreateBy(zhishuShopGoods.getUserId()); + stockChangeLog.setUpdateBy(zhishuShopGoods.getUserId()); + stockChangeLog.setCreateTime(DateUtils.getNowDate()); + stockChangeLog.setUpdateTime(DateUtils.getNowDate()); + stockChangeLog.setDelFlag("0"); + stockChangeLogMapper.insert(stockChangeLog); + //已发布商品记录 + ShopGoodsPublishedBo shopGoodsPublishedBo = new ShopGoodsPublishedBo(); + shopGoodsPublishedBo.setShopId(shopId+""); + shopGoodsPublishedBo.setShopGoodsId(zhishuShopGoods.getId()); + shopGoodsPublishedBo.setPlatformId(trilateralId); + shopGoodsPublishedBo.setCreateBy(zhishuShopGoods.getUserId()); + shopGoodsPublishedBo.setUpdateBy(zhishuShopGoods.getUserId()); + shopGoodsPublishedBo.setCreateTime(DateUtils.getNowDate()); + shopGoodsPublishedBo.setUpdateTime(DateUtils.getNowDate()); + shopGoodsPublishedService.insertByBo(shopGoodsPublishedBo); + //商品实拍图 + if (successData.get("img") != null){ + ZhishuShopImagesBo zhishuShopImagesBo = new ZhishuShopImagesBo(); + zhishuShopImagesBo.setGoodsId(zhishuShopGoods.getId()); + zhishuShopImagesBo.setPath((String) successData.get("img")); + zhishuShopImagesService.insertByBo(zhishuShopImagesBo); + } + //书籍信息 判断isbn首个字符是不是6 + if(isbn.substring(0,1).equals("6")){ + ZhishuShopGoodsDetailBo zhishuShopGoodsDetailBo = new ZhishuShopGoodsDetailBo(); + zhishuShopGoodsDetailBo.setPid(Long.parseLong(zhishuShopGoods.getId())); + zhishuShopGoodsDetailBo.setAuthor(successData.get("author") == null ? "" : successData.get("author").toString()); + zhishuShopGoodsDetailBo.setPublisher(successData.get("publisher") == null ? "" : successData.get("publisher").toString()); + zhishuShopGoodsDetailBo.setPublishertime(successData.get("publisherTime") == null ? "" : successData.get("publisherTime").toString()); + zhishuShopGoodsDetailBo.setFormat(successData.get("format") == null ? "" : successData.get("format").toString()); + zhishuShopGoodsDetailBo.setWordage(successData.get("wordage") == null ? "" : successData.get("wordage").toString()); + zhishuShopGoodsDetailService.insertByBo(zhishuShopGoodsDetailBo); + } + } + } + if(StringUtils.isEmpty(callBackData)){ + callBackData = "商品已存在并且库存价格一致,不做处理"; + } + }catch (Exception e){ + e.printStackTrace(); + callBackData += "同步失败;"; + } + //记录数据日志 + runningTask.setSuccessData(JsonUtil.transferToJson(successData)); + runningTask.setCallBackData(callBackData); + runningTaskService.insert(runningTask); + } + //进行下100条数据 + page++; + } + } + + @Override + public void synchronousTask(ShopVo shopVo, TaskBo taskBo){ + + shopGoodsPublishedService.deleteByShopId(shopVo.getId()); + Long pageSize = 100L; + Long page = 1L; + RunningTaskShopGoodsDto runningTaskShopGoodsDto = new RunningTaskShopGoodsDto(); + runningTaskShopGoodsDto.setTableName("t_running_task_"+shopVo.getId()); + runningTaskShopGoodsDto.setTaskId(taskBo.getRelationId()); + runningTaskShopGoodsDto.setPageSize(pageSize); + while(true){ + Long pageNum = (long) ((page - 1) * pageSize); + runningTaskShopGoodsDto.setPageNum(pageNum); + List shopGoodsMapList = runningTaskByShopService.selectGetShopGoodsListByDto(runningTaskShopGoodsDto); + if(shopGoodsMapList.isEmpty()){ + break; + } + + + for (Map shopGoodsMap : shopGoodsMapList){ + + + Map successData = JsonUtil.transferToObj(shopGoodsMap.get("success_data").toString(),Map.class); + + RunningTask runningTask = new RunningTask(); + runningTask.setTaskId(taskBo.getId()); + runningTask.setShopId(shopVo.getId()); + runningTask.setGoodsId(0L); + runningTask.setRandomNum(System.currentTimeMillis()); + runningTask.setTaskName("同步至自营书品任务"); + runningTask.setPriority(255L); + runningTask.setTaskType("SYNCHRONOUS_TASK"); + runningTask.setStatus("3"); + runningTask.setSuccessData(JsonUtil.transferToJson(successData)); + + String artNo = successData.get("skuCode") == null ? "" : successData.get("skuCode").toString(); + if (StringUtils.isEmpty(artNo)){ + runningTask.setCallBackData("规格编码为空"); + }else{ + String trilateralId = successData.get("trilateralId") == null ? "" : successData.get("trilateralId").toString(); + ZhishuShopGoodsVo zhishuShopGoodsVo = baseMapper.selectShopGoodsByArtNoAndUserId(artNo,shopVo.getCreateBy()); + + if (zhishuShopGoodsVo != null){ + // 存在数据,查询是否存在已发布商品 + //查看是否存在已发布商品记录 + ShopGoodsPublishedVo shopGoodsPublishedVo = shopGoodsPublishedService.queryByPlatformId(shopVo.getId().toString(),trilateralId); + if (shopGoodsPublishedVo == null || !shopGoodsPublishedVo.getPlatformId().equals(trilateralId)){ + //不存在,或者三方平台对不上的情况则新增已发布商品记录 + ShopGoodsPublishedBo shopGoodsPublishedBo = new ShopGoodsPublishedBo(); + shopGoodsPublishedBo.setShopId(shopVo.getId().toString()); + shopGoodsPublishedBo.setShopGoodsId(zhishuShopGoodsVo.getId()); + shopGoodsPublishedBo.setPlatformId(trilateralId); + shopGoodsPublishedBo.setCreateBy(zhishuShopGoodsVo.getUserId()); + shopGoodsPublishedBo.setCreateTime(DateUtils.getNowDate()); + shopGoodsPublishedService.insertByBo(shopGoodsPublishedBo); + //记录日志 + runningTask.setCallBackData("商品对应成功"); + }else{ + runningTask.setCallBackData("已存在商品"); + } + }else{ + runningTask.setCallBackData("未对应到自营商品"); + } + } + runningTaskService.insert(runningTask); + } + page++; + } + } + + /** + * 生成13位ID:6 + 秒级时间戳 + 随机数 + * 格式:6 + 秒级时间戳(10位) + 随机数(2位) = 13位 + */ + public static String generate13DigitId() { + // 获取秒级时间戳(10位) + long timestamp = Instant.now().getEpochSecond(); + + // 生成2位随机数(00-99) + int randomNum = ThreadLocalRandom.current().nextInt(0, 100); + + // 格式化为2位数字,不足补0 + String randomPart = String.format("%02d", randomNum); + + // 拼接:6 + 时间戳 + 随机数 + return "6" + timestamp + randomPart; + } + + public Map uploadImg1(MultipartFile file ,String accessToken) { + + org.springframework.core.io.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(getUploadImgUrl(), "/upload", pddMap); + // Map map = InterfaceUtils.postFormObject("http://10.206.0.10: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(getImgResultUrl(), "/upload?token=" + accessToken + "&imageURL=" + imageUrl); + // String pddImage = InterfaceUtils.getInterface("http://10.206.0.10:8070", "/upload?token=" + accessToken + "&imageURL=" + imageUrl); + //调用pdd图片上传接口 + map.put("url", pddImage); + } else { + map.put("message", "图片上传失败"); + } + } + + return map; + } + + @Override + public Map uploadImg(MultipartFile file) { + String accessToken = configService.selectConfigByKey("image.token"); + Map map = PddUtils.pddImageUpload(file,accessToken); + System.out.println("图片上传"+ map); + return map; + } + + @Override + public void synShopImg(Long userId) { + ExecutorService executorService = Executors.newFixedThreadPool(100); + // 获取该店铺下的所有商品 + List zhishuShopGoodsVoList = baseMapper.selectShopGoodsByUser(userId); + List zhishuShopImagesList = Collections.synchronizedList(new ArrayList<>()); + List zhishuShopGoodsList = Collections.synchronizedList(new ArrayList<>()); + + // 创建CountDownLatch等待所有任务完成 + CountDownLatch latch = new CountDownLatch(zhishuShopGoodsVoList.size()); + + for (ZhishuShopGoodsVo bo : zhishuShopGoodsVoList) { + executorService.submit(() -> { + try { + ZhishuShopGoods add = MapstructUtils.convert(bo, ZhishuShopGoods.class); + add.setConditionCode(CHINESE_TO_CODE_MAP1.get(add.getConditionCode())); + Map map = new HashMap(); + // 修剪孔网图片url + map.put("filepath", add.getBookPic()); + map.put("goodsName", add.getGoodsName()); + map.put("isbn", add.getIsbn()); + map.put("isKW", true); + map.put("isNet", true); + InterfaceUtils.processImage(JSONObject.toJSONString(map)); + + String bookPic = fullBookPic(add); + add.setBookPic(bookPic); + try { + MultipartFile multipartFile = new UrlMultipartFile(bookPic, "book_cover.jpg"); + Map pddImg = uploadImg(multipartFile); + String pddImgUrl = (String) pddImg.get("url"); + + baseMapper.updateById(add); + + if (pddImgUrl != null) { + ZhishuShopImages zhishuShopImages = new ZhishuShopImages(); + zhishuShopImages.setGoodsId(add.getId()); + zhishuShopImages.setPath(pddImgUrl); + zhishuShopImages.setCreateBy(add.getUserId()); + zhishuShopImages.setUpdateBy(add.getUserId()); + zhishuShopImages.setCreateTime(DateUtils.getNowDate()); + zhishuShopImages.setUpdateTime(DateUtils.getNowDate()); + zhishuShopImages.setDelFlag("0"); + zhishuShopImagesList.add(zhishuShopImages); + } + } catch (IOException e) { + log.error("上传图片失败", e); + } + } finally { + latch.countDown(); + } + }); + } + /*try { + latch.await(); // 等待所有任务完成 + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + }*/ + + // baseMapper.updateBatchById(zhishuShopGoodsList); + zhishuShopImagesMapper.insertBatch(zhishuShopImagesList); + } + + @Override + public void synPddShopImg(Long userId) { + ExecutorService executorService = Executors.newFixedThreadPool(100); + // 获取该店铺下的所有商品 + List zhishuShopGoodsVoList = baseMapper.selectShopGoodsByUser(userId); + + for (ZhishuShopGoodsVo bo : zhishuShopGoodsVoList) { + executorService.submit(() -> { + + ZhishuShopGoods add = MapstructUtils.convert(bo, ZhishuShopGoods.class); + + try { + MultipartFile multipartFile = new UrlMultipartFile(bo.getBookPic(), "book_cover.jpg"); + Map pddImg = uploadImg(multipartFile); + String pddImgUrl = (String) pddImg.get("url"); + + if (pddImgUrl != null) { + ZhishuShopImages zhishuShopImages = new ZhishuShopImages(); + zhishuShopImages.setGoodsId(add.getId()); + zhishuShopImages.setPath(pddImgUrl); + zhishuShopImages.setCreateBy(add.getUserId()); + zhishuShopImages.setUpdateBy(add.getUserId()); + zhishuShopImages.setCreateTime(DateUtils.getNowDate()); + zhishuShopImages.setUpdateTime(DateUtils.getNowDate()); + zhishuShopImages.setDelFlag("0"); + zhishuShopImagesMapper.insert(zhishuShopImages); + } + } catch (IOException e) { + log.error("上传图片失败", e); + } + }); + } + } + + @Override + public Long getTaskDataNum(Long taskId) { + return this.baseMapper.getTaskDataNum(taskId); + } + + + /** + * 解析shipmentId,获取一、二、三级货区号 + * @param shipmentId 货号 + */ + private Integer parseShipmentId(String userId, String shipmentId) { + if (shipmentId != null && shipmentId.length() == 5) { + // 一级货区:前2位 + String firstLevel = shipmentId.substring(0, 2); + + char thirdChar = shipmentId.charAt(2); + String secondLevel; + String thirdLevel; + + if (Character.isDigit(thirdChar)) { + // 第三位是数字:第三位是二级货区,第四五位是三级货区 + secondLevel = shipmentId.substring(2, 3); + thirdLevel = shipmentId.substring(3, 5); + } else { + // 第三位是字母:第三四位是二级货区,第五位是三级货区 + secondLevel = shipmentId.substring(2, 4); + thirdLevel = shipmentId.substring(4, 5); + } + +// return waveDetailMapper.getIsJoinDistribution(userId, firstLevel, secondLevel, thirdLevel); + } + return null; + } +} + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopImagesServiceImpl.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopImagesServiceImpl.java new file mode 100644 index 0000000..0345323 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/impl/ZhishuShopImagesServiceImpl.java @@ -0,0 +1,137 @@ +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.zhishu.domain.ZhishuShopImages; +import org.dromara.zhishu.domain.bo.ZhishuShopImagesBo; +import org.dromara.zhishu.domain.vo.ZhishuShopImagesVo; +import org.dromara.zhishu.mapper.ZhishuShopImagesMapper; +import org.dromara.zhishu.service.IZhishuShopImagesService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 商品图片Service业务层处理 + * + * @author Lion Li + * @date 2025-03-13 + */ +@RequiredArgsConstructor +@Service +public class ZhishuShopImagesServiceImpl implements IZhishuShopImagesService { + + private final ZhishuShopImagesMapper baseMapper; + + /** + * 查询商品图片 + * + * @param id 主键 + * @return 商品图片 + */ + @Override + public ZhishuShopImagesVo queryById(String id){ + return baseMapper.selectVoById(id); + } + + @Override + public List selectShopImagesByShopId(String goodsId) { + return baseMapper.selectShopImagesByShopId(goodsId); + } + + /** + * 分页查询商品图片列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 商品图片分页列表 + */ + @Override + public TableDataInfo queryPageList(ZhishuShopImagesBo 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(ZhishuShopImagesBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(ZhishuShopImagesBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.orderByDesc(ZhishuShopImages::getId); + lqw.eq(StringUtils.isNotBlank(bo.getGoodsId()), ZhishuShopImages::getGoodsId, bo.getGoodsId()); + lqw.eq(StringUtils.isNotBlank(bo.getPath()), ZhishuShopImages::getPath, bo.getPath()); + return lqw; + } + + /** + * 新增商品图片 + * + * @param bo 商品图片 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(ZhishuShopImagesBo bo) { + ZhishuShopImages add = MapstructUtils.convert(bo, ZhishuShopImages.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改商品图片 + * + * @param bo 商品图片 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(ZhishuShopImagesBo bo) { + ZhishuShopImages update = MapstructUtils.convert(bo, ZhishuShopImages.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(ZhishuShopImages 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/strategy/InventorySynchronizedGFtrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedGFtrategy.java new file mode 100644 index 0000000..3404a05 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedGFtrategy.java @@ -0,0 +1,56 @@ +package org.dromara.zhishu.service.strategy; + +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.base.BaseException; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.dto.request.SoldOutRequest; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.mapper.ShopGoodsPublishedLogMapper; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.dromara.zhishu.service.IGoofishService; +import org.dromara.zhishu.service.IKongFzService; +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; + +@Service +public class InventorySynchronizedGFtrategy implements InventorySynchronizedStrategy { + + @Autowired + private IGoofishService goofishService; ; + + + @Autowired + private ZhishuShopGoodsMapper zhishuShopGoodsMapper; + + + + @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("数据异常")); + goofishService.goodUpdateStock(shop, goodsPublishedVo.getPlatformId(), zhishuShopGoods.getInventory().toString(), type); + } + + @Override + public void operatingGoodsSoldOut(ShopVo shop, ShopGoodsPublishedVo goodsPublishedVo, Integer platformType, Integer logType, Integer operationType, String orderSn) { + // SoldOutRequest soldOutRequest = new SoldOutRequest(shop.getToken(), goodsPublishedVo.getPlatformId()); + // R booleanR = kfzClient.soldOut(UrlUtil.getKfzServiceUrl(), soldOutRequest); + // ShopGoodsPublishedLog shopGoodsPublishedLog = new ShopGoodsPublishedLog(); + // shopGoodsPublishedLog.setShopGoodsId(Long.valueOf(goodsPublishedVo.getShopGoodsId())); + // shopGoodsPublishedLog.setShopGoodsPublishedId(goodsPublishedVo.getId()); + // shopGoodsPublishedLog.setPlatformId(goodsPublishedVo.getPlatformId()); + // shopGoodsPublishedLog.setAboutId(orderSn); + // shopGoodsPublishedLog.setLogType(logType); + // shopGoodsPublishedLog.setOperationType(operationType); + // shopGoodsPublishedLog.setPlatformType(platformType); + // shopGoodsPublishedLog.setStatus(R.isSuccess(booleanR) ? 0 : 1); + // shopGoodsPublishedLogMapper.insert(shopGoodsPublishedLog); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedKWStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedKWStrategy.java new file mode 100644 index 0000000..5ad40a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/InventorySynchronizedKWStrategy.java @@ -0,0 +1,58 @@ +package org.dromara.zhishu.service.strategy; + +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.base.BaseException; +import org.dromara.zhishu.domain.ShopGoodsPublishedLog; +import org.dromara.zhishu.domain.ZhishuShopGoods; +import org.dromara.zhishu.domain.dto.request.SoldOutRequest; +import org.dromara.zhishu.domain.vo.ShopGoodsPublishedVo; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.mapper.ShopGoodsPublishedLogMapper; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.dromara.zhishu.service.IKongFzService; +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; + +@Service +public class InventorySynchronizedKWStrategy implements InventorySynchronizedStrategy { + + @Autowired + private IKongFzService kongFzService; + + @Autowired + private KfzClient kfzClient; + + @Autowired + private ZhishuShopGoodsMapper zhishuShopGoodsMapper; + + @Autowired + private ShopGoodsPublishedLogMapper shopGoodsPublishedLogMapper; + + @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("数据异常")); + kongFzService.goodUpdateStock(shop.getToken(), goodsPublishedVo.getPlatformId(), zhishuShopGoods.getInventory().toString()); + } + + @Override + public void operatingGoodsSoldOut(ShopVo shop, ShopGoodsPublishedVo goodsPublishedVo, Integer platformType, Integer logType, Integer operationType, String orderSn) { + SoldOutRequest soldOutRequest = new SoldOutRequest(shop.getToken(), goodsPublishedVo.getPlatformId()); + R booleanR = kfzClient.soldOut(UrlUtil.getKfzServiceUrl(), soldOutRequest); + ShopGoodsPublishedLog shopGoodsPublishedLog = new ShopGoodsPublishedLog(); + shopGoodsPublishedLog.setShopGoodsId(Long.valueOf(goodsPublishedVo.getShopGoodsId())); + shopGoodsPublishedLog.setShopGoodsPublishedId(goodsPublishedVo.getId()); + shopGoodsPublishedLog.setPlatformId(goodsPublishedVo.getPlatformId()); + shopGoodsPublishedLog.setAboutId(orderSn); + shopGoodsPublishedLog.setLogType(logType); + shopGoodsPublishedLog.setOperationType(operationType); + shopGoodsPublishedLog.setPlatformType(platformType); + shopGoodsPublishedLog.setStatus(R.isSuccess(booleanR) ? 0 : 1); + shopGoodsPublishedLogMapper.insert(shopGoodsPublishedLog); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParseGFStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParseGFStrategy.java new file mode 100644 index 0000000..b730c8d --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParseGFStrategy.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.GoodsItemGFVo; +import org.dromara.zhishu.domain.vo.ItemListVo; +import org.springframework.stereotype.Service; + +@Service +public class ItemListJsonStringParseGFStrategy 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/ItemListJsonStringParseKWStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParseKWStrategy.java new file mode 100644 index 0000000..a93aedf --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParseKWStrategy.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.GoodsItemKfzVo; +import org.dromara.zhishu.domain.vo.ItemListVo; +import org.springframework.stereotype.Service; + +@Service +public class ItemListJsonStringParseKWStrategy 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/ItemListJsonStringParseStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParseStrategy.java new file mode 100644 index 0000000..c5fe1f3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ItemListJsonStringParseStrategy.java @@ -0,0 +1,9 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.zhishu.domain.vo.ItemListVo; + +public interface ItemListJsonStringParseStrategy { + + ItemListVo itemListJsonStringParse(String itemListStr); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderGFStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderGFStrategy.java new file mode 100644 index 0000000..b9437aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderGFStrategy.java @@ -0,0 +1,44 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryKWRequest; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryRequest; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.service.client.KfzClient; +import org.dromara.zhishu.util.InterfaceUtils; +import org.dromara.zhishu.util.UrlUtil; +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 OrderGFStrategy implements OrderStrategy { + + + + @Override + public List deliveryMethodList(Long shopId) { + return null; + } + + @Override + public Boolean orderDelivery(OrderDeliveryRequest request) { + return false; + } + + @Override + public Boolean syncKfzHistoryOrder(Long shopId, Integer days) { + Map orderParams = new HashMap<>(); + orderParams.put("shopId", shopId.toString()); + orderParams.put("days", days.toString()); + //访问go闲鱼服务 + String service = InterfaceUtils.postForm(UrlUtil.getgoofishServiceUrl(), "/huidiao/goofish/getAllGoofishOrderByDays", orderParams); + System.out.println("service:"+service); + + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderKWStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderKWStrategy.java new file mode 100644 index 0000000..0a55247 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderKWStrategy.java @@ -0,0 +1,57 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryKWRequest; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryRequest; +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 OrderKWStrategy implements OrderStrategy { + + @Autowired + private KfzClient kfzClient; + + @Override + public List deliveryMethodList(Long shopId) { + return kfzClient.deliveryMethodList(UrlUtil.getKfzServiceUrl(), shopId); + } + + @Override + public Boolean orderDelivery(OrderDeliveryRequest request) { + String methodId = request.getMethodId(); + OrderDeliveryKWRequest orderDeliveryKWRequest = new OrderDeliveryKWRequest(); + orderDeliveryKWRequest.setShopId(request.getShopId()); + orderDeliveryKWRequest.setOrderId(Long.valueOf(request.getOrderSn())); + String[] parts = methodId.split("_"); + // 确保分割后的数组有足够的元素 + if (parts.length == 2) { + String shippingId = parts[0]; // 第一部分是shippingId + String shippingCom = parts[1]; // 第二部分是shippingCom + orderDeliveryKWRequest.setShippingId(shippingId); + orderDeliveryKWRequest.setShippingCom(shippingCom); + if (shippingId.equals("other")) orderDeliveryKWRequest.setUserDefined(request.getUserDefined()); + } else { + String shippingId = parts[0]; // 第一部分是shippingId + orderDeliveryKWRequest.setShippingId(shippingId); + } + orderDeliveryKWRequest.setShipmentNum(request.getTrackingNumber()); + orderDeliveryKWRequest.setMoreShipmentNum(request.getMoreShipmentNum()); + R r = kfzClient.orderDelivery(UrlUtil.getKfzServiceUrl(), orderDeliveryKWRequest); + if (R.isError(r)) throw new ServiceException(r.getMsg()); + return r.getData(); + } + + @Override + public Boolean syncKfzHistoryOrder(Long shopId, Integer days) { + String result = kfzClient.fullSynchronizationOrder(UrlUtil.getKfzServiceUrl(), days, "manual", List.of(shopId)); + if (!result.equals("true")) throw new ServiceException("同步历史订单失败:店铺Id-" + shopId); + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderPddStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderPddStrategy.java new file mode 100644 index 0000000..a421331 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderPddStrategy.java @@ -0,0 +1,43 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryPddRequest; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryRequest; +import org.dromara.zhishu.service.client.PddClient; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class OrderPddStrategy implements OrderStrategy { + + @Autowired + private PddClient pddClient; + + @Override + public List deliveryMethodList(Long shopId) { + return pddClient.deliveryMethodList(UrlUtil.getPddServiceUrl()); + } + + @Override + public Boolean orderDelivery(OrderDeliveryRequest request) { + OrderDeliveryPddRequest orderDeliveryPddRequest = new OrderDeliveryPddRequest(); + BeanUtils.copyProperties(request, orderDeliveryPddRequest); + orderDeliveryPddRequest.setLogisticsId(Long.valueOf(request.getMethodId())); + R r = pddClient.orderDelivery(UrlUtil.getPddServiceUrl(), orderDeliveryPddRequest); + if (R.isError(r)) throw new ServiceException(r.getMsg()); + return r.getData(); + } + + @Override + public Boolean syncKfzHistoryOrder(Long shopId, Integer days) { + String result = pddClient.fullSynchronizationOrder(UrlUtil.getPddServiceUrl(), days, "manual", List.of(shopId)); + if (!result.equals("true")) throw new ServiceException("同步历史订单失败:店铺Id-" + shopId); + return true; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderStrategy.java new file mode 100644 index 0000000..19ecae0 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/OrderStrategy.java @@ -0,0 +1,16 @@ +package org.dromara.zhishu.service.strategy; + +import org.dromara.zhishu.domain.dto.response.LogisticsMethodResponse; +import org.dromara.zhishu.domain.dto.request.OrderDeliveryRequest; + +import java.util.List; + +public interface OrderStrategy { + + List deliveryMethodList(Long shopId); + + Boolean orderDelivery(OrderDeliveryRequest request); + + Boolean syncKfzHistoryOrder(Long shopId, Integer days); + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsWlnStrategy.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsWlnStrategy.java new file mode 100644 index 0000000..917ad8e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/service/strategy/ShopGoodsWlnStrategy.java @@ -0,0 +1,253 @@ +package org.dromara.zhishu.service.strategy; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.redis.utils.RedisUtils; +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.ZhishuShopGoods; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.domain.dto.request.ErpGoodsQueryOlnGoodsRequest; +import org.dromara.zhishu.domain.dto.request.GoodsComparisonRequest; +import org.dromara.zhishu.domain.dto.request.UpdateShopGoodsPriceRequest; +import org.dromara.zhishu.domain.dto.request.ZhishuShopGoodsRequest; +import org.dromara.zhishu.domain.dto.response.ErpGoodsQueryOlnGoodsResponse; +import org.dromara.zhishu.domain.dto.response.WlnBaseResponse; +import org.dromara.zhishu.domain.vo.ShopVo; +import org.dromara.zhishu.enums.TaskTypeEnum; +import org.dromara.zhishu.mapper.ShopMapper; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.dromara.zhishu.service.client.WlnClient; +import org.dromara.zhishu.service.impl.TaskServiceImpl; +import org.dromara.zhishu.util.CnumberUtils; +import org.dromara.zhishu.util.ExcelFileHandlerUtil; +import org.dromara.zhishu.util.ThreadPoolUtils; +import org.dromara.zhishu.util.UrlUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import static cn.dev33.satoken.SaManager.log; + +@Service +public class ShopGoodsWlnStrategy implements ShopGoodsStrategy { + + // 每隔多少秒续期一次 Redis 锁(比如 30 秒) + private static final int INITIAL_DELAY_AND_PERIOD = 30; + + @Autowired + private WlnClient wlnClient; + + @Autowired + private ShopMapper shopMapper; + + @Autowired + private ZhishuShopGoodsMapper zhishuShopGoodsMapper; + + @Autowired + private ScheduledExecutorService scheduledExecutorService; + + @Autowired + private TaskServiceImpl taskServiceImpl; + + @Async + @Override + public void synchronizationGoods(Long shopId) { + // 根据店铺Id查询店铺信息 + Shop shopInfo = new LambdaQueryChainWrapper<>(shopMapper) + .eq(Shop::getId, shopId) + .oneOpt().orElseThrow(() -> new ServiceException("查询不到店铺信息:" + shopId)); + // 获取当前时间 + LocalDateTime now = LocalDateTime.now(); + // 定义格式:YYYY-MM-DD HH:mm:ss + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + // 格式化当前时间 + String currentDateTime = now.format(formatter); + // 从Redis中获取上次同步时间 + String lastGoodsSynTime = (String) RedisUtils.getCacheObject("lastGoodsSynTime_" + shopInfo.getId()); + ThreadPoolUtils.execute(() -> { + List shopGoodsList = queryShopGoods(shopInfo.getAccount(), shopInfo.getPassword(), shopInfo.getShopNike(), lastGoodsSynTime); + List zhishuShopGoodsRequestList = new ArrayList<>(); + for (ErpGoodsQueryOlnGoodsResponse.Element spu : shopGoodsList) { + ZhishuShopGoodsRequest zhishuShopGoodsRequest = new ZhishuShopGoodsRequest(); + zhishuShopGoodsRequest.setUserId(shopInfo.getCreateBy().toString()); + zhishuShopGoodsRequest.setProductId(spu.getItemId()); + zhishuShopGoodsRequest.setStock(0L); + zhishuShopGoodsRequest.setCreateBy(shopInfo.getCreateBy()); + zhishuShopGoodsRequest.setInventory(0); + zhishuShopGoodsRequest.setGoodsName(spu.getTitle()); + zhishuShopGoodsRequest.setBookPic(spu.getPic()); + if (ObjectUtil.isNotEmpty(spu.getSkus())) { + for (ErpGoodsQueryOlnGoodsResponse.Element.Sku sku : spu.getSkus()) { + zhishuShopGoodsRequest.setGoodsName(sku.getName()); + zhishuShopGoodsRequest.setItemNumber(sku.getSkuId()); + if (ObjectUtil.isNotEmpty(sku.getPic())) zhishuShopGoodsRequest.setBookPic(sku.getPic()); + zhishuShopGoodsRequestList.add(zhishuShopGoodsRequest); + } + } else { + zhishuShopGoodsRequestList.add(zhishuShopGoodsRequest); + } + } + GoodsComparisonRequest request = new GoodsComparisonRequest(); + request.setShopId(shopId); + request.setUserId(shopInfo.getCreateBy()); + request.setZhishuShopGoodsRequestList(zhishuShopGoodsRequestList); + request.setCurrentDateTime(currentDateTime); + goodsComparison(request); + }); + } + + // 获取万里牛商品列表 + public List queryShopGoods(String appKey, String appSecret, String shopNick, String lastGoodsSynTime) { + Boolean pageQueryFlag = true; + List shopGoodsList = new ArrayList<>(); + ErpGoodsQueryOlnGoodsRequest request = new ErpGoodsQueryOlnGoodsRequest(); + request.setShopNick(shopNick); + while (pageQueryFlag) { + WlnBaseResponse response = wlnClient.erpGoodsQueryOlnGoods(UrlUtil.getWlnServiceUrl(), appKey, appSecret, request); + if (response.getCode() != 0) throw new ServiceException("获取万里牛商品列表失败:" + response.getMessage()); + if (ObjectUtil.isNotEmpty(response.getData())) { + shopGoodsList.addAll(response.getData().getElements()); + } + request.setPage(request.getPage() + 1); + pageQueryFlag = response.getData().getNext(); + } + return shopGoodsList; + } + + + // 比对店铺商品信息并生成Excel文件 + public void goodsComparison(GoodsComparisonRequest request) { + Long shopId = request.getShopId(); + Long userId = request.getUserId(); + List zhishuShopGoodsRequestList = request.getZhishuShopGoodsRequestList(); + // 尝试获取锁 + String lockKey = "WriteExcelKey_" + shopId; + String lockValue = "WriteExcelLock"; + Duration lockExpireDuration = Duration.ofMinutes(2); // 设置锁的过期时间为2分钟 + String writeExcelLock = RedisUtils.getCacheObject(lockKey); + // 若获取存在说明存在读取该文件的线程,则直接返回,不进行后续操作 + if (ObjectUtil.isNotEmpty(writeExcelLock)) throw new ServiceException("已在处理该文件,请勿重复操作"); + System.out.println("获取到redis锁,执行读取文件操作"); + // 若不存在,则设置锁,并执行后续操作 + RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration); + ScheduledExecutorService scheduler = null; + ScheduledFuture future = null; + try { + scheduler = Executors.newScheduledThreadPool(1); + // 设置一个定时任务来不断延长锁的过期时间 + Runnable renewLockTask = () -> { + RedisUtils.setCacheObject(lockKey, lockValue, lockExpireDuration); + System.out.println("Redis锁过期时间已更新"); + }; + // 启动定时任务 + future = scheduler.scheduleAtFixedRate(renewLockTask, 0, INITIAL_DELAY_AND_PERIOD, TimeUnit.SECONDS); + + // 使用并发流处理 + List changedData = Collections.synchronizedList(new ArrayList<>()); + List newData = Collections.synchronizedList(new ArrayList<>()); + + for (ZhishuShopGoodsRequest zhishuShopGoodsRequest : zhishuShopGoodsRequestList) { + if (!ObjectUtil.isEmpty(zhishuShopGoodsRequest.getItemNumber())) { + // 查出数据库是否存在数据 + List list = new LambdaQueryChainWrapper<>(zhishuShopGoodsMapper) + .eq(ZhishuShopGoods::getItemNumber, zhishuShopGoodsRequest.getItemNumber()) + .list(); + if (!ObjectUtil.isNotEmpty(list)) { + newData.add(zhishuShopGoodsRequest); + } + } else { + // 查出数据库是否存在数据 + List list = new LambdaQueryChainWrapper<>(zhishuShopGoodsMapper) + .eq(ZhishuShopGoods::getProductId, zhishuShopGoodsRequest.getProductId()) + .list(); + if (!ObjectUtil.isNotEmpty(list)) { + newData.add(zhishuShopGoodsRequest); + } + } + } + + List fileNameList = new ArrayList<>(); + // 分别指定新增和修改的数据生成的Excel文件存储路径,文件名称前缀,并写到该路径下 + if (!changedData.isEmpty()) { + fileNameList.add("Changed_" + shopId + "_0.xlsx"); + ExcelFileHandlerUtil.handleExport(changedData, UrlUtil.getUrl(), "Changed", shopId.toString(), ZhishuShopGoodsRequest.class); + } + if (!newData.isEmpty()) { + fileNameList.add("New_" + shopId + "_0.xlsx"); + ExcelFileHandlerUtil.handleExport(newData, UrlUtil.getUrl(), "New", shopId.toString(), ZhishuShopGoodsRequest.class); + } + + + RedisUtils.setCacheObject("lastGoodsSynTime_" + shopId, request.getCurrentDateTime()); + + if (!newData.isEmpty() || !changedData.isEmpty()) { + // 根据店铺Id查询店铺信息 + Shop shopInfo = new LambdaQueryChainWrapper<>(shopMapper) + .eq(Shop::getId, shopId) + .oneOpt().orElseThrow(() -> new ServiceException("查询不到店铺信息:" + shopId)); + // 将任务信息插入到数据库中,创建一条任务 + TaskBo taskBo = new TaskBo(); + taskBo.setTaskType(TaskTypeEnum.SYNC_GOODS_WLN.getCode()); + taskBo.setShopIds(shopId.toString()); + taskBo.setShopNames(shopInfo.getShopName()); + taskBo.setFileName(String.join("/", fileNameList)); + taskBo.setDataNum((long) zhishuShopGoodsRequestList.size()); + taskBo.setTaskStatus("0"); + taskBo.setStatus("0"); + taskBo.setCreateBy(userId); + taskServiceImpl.insertByBo(taskBo); + } + + // 发送消息给前端告知拉取下来的数据已比对完毕 + scheduledExecutorService.schedule(() -> + + { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage("已拉取到商品数据总计:" + zhishuShopGoodsRequestList.size() + "条,新增:" + newData.size() + "条新数据,更新:" + changedData.size() + "条数据"); + dto.setUserIds(List.of(userId)); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); + } catch (Exception e) { + // 捕获其他未知异常 + log.error("商品导入写入Excel过程中发生异常: {}", e.getMessage(), e); + throw new ServiceException(e.getMessage()); + } finally { + // 取消定时任务 + if (future != null) { + future.cancel(false); + } + // 关闭线程池 + if (scheduler != null) { + scheduler.shutdownNow(); + } + // 确保释放锁 + RedisUtils.deleteObject(lockKey); + System.out.println("已释放redis锁"); + } + + } + + @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/util/ArtNoUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ArtNoUtil.java new file mode 100644 index 0000000..febb3f1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ArtNoUtil.java @@ -0,0 +1,99 @@ +package org.dromara.zhishu.util; + +import org.dromara.common.core.utils.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 货号工具类 + */ +public class ArtNoUtil { + + public Map parseArtNo(String artNo) { + /** + * 从货号前五位解析 一级 二级 三级 货区编码 + */ + Map result = new HashMap<>(); + + if (artNo == null || artNo.length() < 5) { + throw new IllegalArgumentException("货号长度不能少于5位"); + } + + String depotFive = artNo.substring(0, 5); + + // 1.字符串前两位是一级货区 + String depotLevel = depotFive.substring(0, 2); + result.put("depotLevel", depotLevel); + + // 2.字符串第三位如果是数字 则二级货区1位 ,字符串如果是字母 则 二级货区2位 + String shelvesLevel; + String freightLevel; + + char freightChar = depotFive.charAt(2); + if (Character.isDigit(freightChar)) { + // 二级货区1位 + shelvesLevel = String.valueOf(freightChar); + // 3.如果二级货区编码只有一位 则三级货区是两位 + freightLevel = depotFive.substring(3, 5); + } else { + // 二级货区2位 + shelvesLevel = depotFive.substring(2, 4); + // 3.如果二级货区两位 则三级货区一位 + freightLevel = depotFive.substring(4, 5); + } + + result.put("shelvesLevel", shelvesLevel); + result.put("freightLevel", freightLevel); + + return result; + } + + /** + * 校验货号是否符合规则 + * @param artNo 货号 + * @return 是否符合规则 + */ + public static boolean validateArtNo(String artNo) { + // 长度校验 + if ( StringUtils.isEmpty(artNo) || artNo.length() < 19) { + return false; + } + + String depotFive = artNo.substring(0, 5); + + // 校验前两位(一级货区) + String depotLevel = depotFive.substring(0, 2); + // 这里可以根据实际需求添加对一级货区的具体校验 + + char thirdChar = depotFive.charAt(2); + + // 第一种情况:第三位是数字 + if (Character.isDigit(thirdChar)) { + // 二级货区1位(第三位),三级货区2位(第四、五位) + String freightLevel = depotFive.substring(3, 5); + + // 校验三级货区格式:纯数字 或者 第四位是字母+第五位是数字 + char fourthChar = freightLevel.charAt(0); + char fifthChar = freightLevel.charAt(1); + + // 情况1:纯数字 + boolean isAllDigits = Character.isDigit(fourthChar) && Character.isDigit(fifthChar); + + // 情况2:第四位是字母 + 第五位是数字 + boolean isLetterAndDigit = Character.isLetter(fourthChar) && Character.isDigit(fifthChar); + + return isAllDigits || isLetterAndDigit; + } + // 第二种情况:第三位是字母 + else if (Character.isLetter(thirdChar)) { + // 二级货区2位(第三、四位),三级货区1位(第五位) + // 第四位不需要管,直接校验第五位是否是数字 + char fifthChar = depotFive.charAt(4); + return Character.isDigit(fifthChar); + } + + // 如果第三位既不是数字也不是字母,返回false + return false; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/Base64Utils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/Base64Utils.java new file mode 100644 index 0000000..03341a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/Base64Utils.java @@ -0,0 +1,56 @@ +package org.dromara.zhishu.util; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Base64; + +public class Base64Utils { + + /** + * 从指定URL读取CSV文件并返回Base64编码字符串 + * + * @param csvUrl CSV文件的网络路径 + * @return Base64编码的文件内容 + * @throws IOException 网络连接或文件读取异常 + */ + public static String readCsvAndEncodeToBase64(String csvUrl) throws IOException { + HttpURLConnection connection = null; + try { + URL url = new URL(csvUrl); + connection = (HttpURLConnection) url.openConnection(); + + // 设置请求属性 + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); // 连接超时5秒 + connection.setReadTimeout(10000); // 读取超时10秒 + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + + // 检查响应码 + int responseCode = connection.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_OK) { + throw new IOException("Failed to download file. HTTP response code: " + responseCode); + } + + // 读取文件内容并转换为Base64 + try (InputStream inputStream = connection.getInputStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream()) { + + byte[] data = new byte[1024]; + int bytesRead; + + while ((bytesRead = inputStream.read(data)) != -1) { + buffer.write(data, 0, bytesRead); + } + + byte[] fileBytes = buffer.toByteArray(); + return Base64.getEncoder().encodeToString(fileBytes); + } + } finally { + if (connection != null) { + connection.disconnect(); + } + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/CnumberUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/CnumberUtils.java new file mode 100644 index 0000000..a902a78 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/CnumberUtils.java @@ -0,0 +1,804 @@ +package org.dromara.zhishu.util; + + +import com.baomidou.mybatisplus.core.toolkit.Assert; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.zhishu.domain.TDepot; +import org.dromara.zhishu.domain.TFreight; +import org.dromara.zhishu.domain.TShelves; +import org.dromara.zhishu.domain.vo.FreightGoodsCountVo; +import org.dromara.zhishu.mapper.TDepotMapper; +import org.dromara.zhishu.mapper.TShelvesMapper; +import org.dromara.zhishu.mapper.ZhishuShopGoodsMapper; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.apache.commons.lang3.ObjectUtils.isEmpty; + +/** + * CnumberUtils 类用于生成货号 + */ +@Component +@Log4j2 +@RequiredArgsConstructor +public class CnumberUtils { + @Resource + TDepotMapper tDepotMapper; + @Resource + TShelvesMapper tShelvesMapper; + @Resource + ZhishuShopGoodsMapper baseMapper; + //品相对应的数值 + private static final double[] CONDITION_CODES={1,2,3,4,5,6,6.5,7,7.5,8,8.5,9,9.5,10}; + // 品相对应的字母标识 + private static final String[] CONDITION_CODE={"A","B","C","D","E","F","G","H","I","J","K","L","M","N"}; + + // 品相对应的中文标识 + private static final String[] CHINESE_CODE={"一品","二品","三品","四品","五品","六品","六五品","七品","七五品","八品","八五品","九品","九五品","全新"}; + + //字母转数值 + private static final Map QUALITY_MAP = new HashMap<>(); + static { + QUALITY_MAP.put("A", "10"); + QUALITY_MAP.put("B", "20"); + QUALITY_MAP.put("C", "30"); + QUALITY_MAP.put("D", "40"); + QUALITY_MAP.put("E", "50"); + QUALITY_MAP.put("F", "60"); + QUALITY_MAP.put("G", "65"); + QUALITY_MAP.put("H", "70"); + QUALITY_MAP.put("I", "75"); + QUALITY_MAP.put("J", "80"); + QUALITY_MAP.put("K", "85"); + QUALITY_MAP.put("L", "90"); + QUALITY_MAP.put("M", "95"); + QUALITY_MAP.put("N", "100"); + + QUALITY_MAP.put("10","A"); + QUALITY_MAP.put("20","B"); + QUALITY_MAP.put("30","C"); + QUALITY_MAP.put("40","D"); + QUALITY_MAP.put("50","E"); + QUALITY_MAP.put("60","F"); + QUALITY_MAP.put("65","G"); + QUALITY_MAP.put("70","H"); + QUALITY_MAP.put("75","I"); + QUALITY_MAP.put("80","J"); + QUALITY_MAP.put("85","K"); + QUALITY_MAP.put("90","L"); + QUALITY_MAP.put("95","M"); + QUALITY_MAP.put("100","N"); + + QUALITY_MAP.put("一品","10"); + QUALITY_MAP.put("二品","20"); + QUALITY_MAP.put("三品","30"); + QUALITY_MAP.put("四品","40"); + QUALITY_MAP.put("五品","50"); + QUALITY_MAP.put("六品","60"); + QUALITY_MAP.put("六五品","65"); + QUALITY_MAP.put("七品","70"); + QUALITY_MAP.put("七五品","75"); + QUALITY_MAP.put("八品","80"); + QUALITY_MAP.put("八五品","85"); + QUALITY_MAP.put("九品","90"); + QUALITY_MAP.put("九五品","95"); + QUALITY_MAP.put("全新","100"); + } + //数字转中文 + public static final Map NUM_CHINESE_MAP = new HashMap<>(); + static { + NUM_CHINESE_MAP.put("10","一品"); + NUM_CHINESE_MAP.put("20","二品"); + NUM_CHINESE_MAP.put("30","三品"); + NUM_CHINESE_MAP.put("40","四品"); + NUM_CHINESE_MAP.put("50","五品"); + NUM_CHINESE_MAP.put("60","六品"); + NUM_CHINESE_MAP.put("65","六五品"); + NUM_CHINESE_MAP.put("70","七品"); + NUM_CHINESE_MAP.put("75","七五品"); + NUM_CHINESE_MAP.put("80","八品"); + NUM_CHINESE_MAP.put("85","八五品"); + NUM_CHINESE_MAP.put("90","九品"); + NUM_CHINESE_MAP.put("95","九五品"); + NUM_CHINESE_MAP.put("100","全新"); + } + private static final String BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + + private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private static final int BASE = 62; + + + /** + * 单品上书获取货号 + * + * @param conCode 品相 + * @param userId 用户ID + * @param isbn ISBN号 + * @param depotId 仓库ID + * @param sheId 货架ID + * @param freId 自由区ID + * @return 生成的货号 + */ + public String getArtNo(Double conCode, Long userId, String isbn, Long depotId, Long sheId, Long freId,String Series) { + + if (conCode == null) { + throw new IllegalArgumentException("品相和用户ID不能为空"); + } + // 获取条件码 + String conditionCode = getConditionCode(conCode); + String goodNumber = ""; + String depotCode = ""; + String sheCode = ""; + String freCode = ""; + String newisbn=""; + // ISBN 处理逻辑 + if (StringUtils.isEmpty(isbn)) { + String newisbn1 = generateRandomIsbn(); + newisbn = convertISBN(newisbn1); + saveIsbn(newisbn1,newisbn); +// String oldisbn = revertRandomISBN(newisbn); + } else { + if(isbn.length() < 13) { + String newIsbnCon = convert8To13(isbn); + newisbn=convertISBN(newIsbnCon); + saveIsbn(newIsbnCon,newisbn); +// String oldisbn = revertISBN(newisbn); + // 判断数据库中是否有oldisbn和newisbn的数据 +// Integer number = tDepotMapper.selectByNewIsbn(Long.parseLong(isbn), Long.parseLong(newisbn)); +//// // 如果数据库中没有oldisbn和newisbn的数据,则插入数据 +// if (number == 0) { +// tDepotMapper.insertIsbn(Long.parseLong(isbn), Long.parseLong(newisbn)); +// } + }else if(isbn.length()==13){ + newisbn= convertISBN(isbn); + saveIsbn(isbn,newisbn); + // String oldisbn = revertISBN(newisbn); +// newisbn=isbn; + } + } + // 仓库id不能为空 + if(depotId==null){ + throw new RuntimeException("仓库ID不能为空"); + } + //二级货区必须存在 + List sheCount= baseMapper.selectSheCount(depotId); + if(sheCount.size()==0){ + throw new RuntimeException("二级货区为空"); + } + //三级货区必须存在 + List freCount=baseMapper.selectFreCount1(sheCount); + if(freCount.size()==0){ + throw new RuntimeException("三级货区为空"); + } + Map map=new HashMap<>(); + //查询出货架编码sheCode与之匹配货架编码freCode + sheCount.forEach(she -> { + // 跳过无效code长度(非1位或2位) + if (she.getCode().length() != 1 && she.getCode().length() != 2) { + return; // 在forEach中相当于continue + } + // 查询货架编码 + List tFreight = baseMapper.selectBySId(she.getId()); + if (tFreight == null) { + return; // 跳过空数据 + } + for (int i = 0; i < tFreight.size(); i++) { + if(tFreight.get(i).getCode() == null){ + return; // 跳过空数据 + } + // 核心匹配逻辑,将符合的数据添加到map中 + if ((she.getCode().length() == 2 && tFreight.get(i).getCode().length() == 1) || + (she.getCode().length() == 1 && tFreight.get(i).getCode().length() == 2)) { + map.put(tFreight.get(i).getId(), she.getId()); + } + } + }); + // 判断map是否为空 + if(map.isEmpty()){ + throw new RuntimeException("货区不存在"); + } + + // 根据不同 ID 情况生成对应的代码 + if (isEmpty(depotId)) { + depotCode = tDepotMapper.selectByCode(userId, depotId); + sheCode = tShelvesMapper.selectFreCode(depotCode, userId); + freCode = String.valueOf(generateRandomNumber(1, 5)); + } else if (isEmpty(sheId)) { + // 1. 转换为可随机访问的Entry集合 + List> entries = new ArrayList<>(map.entrySet()); + // 2. 线程安全随机选择(Java 8+) + if (!entries.isEmpty()) { + Map.Entry randomEntry = entries.get( + ThreadLocalRandom.current().nextInt(entries.size()) + ); + freId = randomEntry.getKey(); + sheId = randomEntry.getValue(); + } + depotCode = tDepotMapper.selectByCode(userId, depotId); + sheCode = tShelvesMapper.selectSCode(sheId); + freCode = tShelvesMapper.selectByFreCode(freId); +// freCode = String.valueOf(generateRandomNumber(1, 5)); + } else if (isEmpty(freId)) { + // 1. 转换为可随机访问的Entry集合 + List> entries = new ArrayList<>(map.entrySet()); + // 2. 线程安全随机选择(Java 8+) + if (!entries.isEmpty()) { + Map.Entry randomEntry = entries.get( + ThreadLocalRandom.current().nextInt(entries.size()) + ); + freId = randomEntry.getKey(); + sheId = randomEntry.getValue(); + } + depotCode = tDepotMapper.selectByCode(userId, depotId); + sheCode = tShelvesMapper.selectSCode(sheId); + freCode = tShelvesMapper.selectByFreCode(freId); +// freCode = String.valueOf(generateRandomNumber(1, 5)); + } else { + depotCode = tDepotMapper.selectByCode(userId, depotId); + sheCode = tShelvesMapper.selectSCode(sheId); + freCode = tShelvesMapper.selectByFreCode(freId); + } + // 构建最终的货号 + goodNumber = buildArtNo(depotCode, sheCode, freCode, conditionCode, newisbn, Series); + return goodNumber; + } + + + + /** + * Excel表上传生成货号 + * @param conCode + * @param userId + * @param isbn + * @param depotId + * @param sheId + * @param freId + * @param Series + * @param tDepotList + * @param tShelvesList + * @param tFreightList + * @return + */ + public String getArtNo(Double conCode, Long userId, String isbn, Long depotId, Long sheId, Long freId,String Series,List tDepotList ,List tShelvesList,List tFreightList){ + // 检查必要参数 + if (conCode == null) { + throw new IllegalArgumentException("品相和用户ID不能为空"); + } + // 获取条件码 + String conditionCode = getConditionCode(conCode); + String goodNumber = ""; + String depotCode = ""; + String sheCode = ""; + String freCode = ""; + String newisbn=""; + // ISBN 处理逻辑 + if (StringUtils.isEmpty(isbn)) { + String newisbnCon = generateRandomIsbn(); + newisbn = convertISBN(newisbnCon); +// saveIsbn(newisbnCon,newisbn); +// 解压isbn + // String oldisbn = revertRandomISBN(newisbn); + } else { + if(isbn.length() < 13) { + String newisbnCon = convert8To13(isbn); + newisbn = convertISBN(newisbnCon); +// saveIsbn(isbn,newisbnCon); + // String oldisbn = revertISBN(newisbn); + }else if(isbn.length()==13){ + newisbn= convertISBN(isbn); +// String oldisbn = revertISBN(newisbn); +// saveIsbn(isbn,newisbn); + } + } + int randomIndex = ThreadLocalRandom.current().nextInt(tDepotList.size()); + if (isEmpty(depotId)) { + depotCode= tDepotList.get(randomIndex).getCode(); + sheCode = getShe(tDepotList.get(randomIndex).getId(),sheId,tShelvesList); + freCode = String.valueOf(generateRandomNumber(1, 5)); + }else if (isEmpty(sheId)) { + for ( TDepot tDepot : tDepotList){ + if (tDepot.getId().equals(depotId)) { + depotCode = tDepot.getCode(); + sheCode = getShe(tDepot.getId(),sheId,tShelvesList); + } + } + freCode = String.valueOf(generateRandomNumber(1, 5)); + }else if (isEmpty(freId)) { + for ( TDepot tDepot : tDepotList){ + if (tDepot.getId().equals(depotId)) { + depotCode = tDepot.getCode(); + } + } + sheCode = getShe(depotId,sheId,tShelvesList); + freCode = String.valueOf(generateRandomNumber(1, 5)); + }else { + for ( TDepot tDepot : tDepotList){ + if (tDepot.getId().equals(depotId)) { + depotCode = tDepot.getCode(); + } + } + sheCode = getShe(depotId,sheId,tShelvesList); + freCode = getFre(sheId,freId,tFreightList); + } + // 构建最终的货号 + goodNumber = buildArtNo(depotCode, sheCode, freCode, conditionCode, newisbn, Series); + return goodNumber; + } + +// 保存原始和压缩后的isbn数据 +//@Transactional +private void saveIsbn(String newisbnCon,String oldisbn){ + // 判断数据库中是否有oldisbn和newisbn的数据 + Integer number = tDepotMapper.selectByNewIsbn(Long.parseLong(newisbnCon), oldisbn); + // 如果数据库中没有oldisbn和newisbn的数据,则插入数据 + if (number == 0) { + tDepotMapper.insertIsbn(Long.parseLong(newisbnCon),oldisbn); + } + } + + + /** + * 获取货架编码sheCode + * @param depotId + * @param sheId + * @param tShelvesList + * @return + */ + private String getShe(Long depotId,Long sheId,List tShelvesList) { + String sheCode=""; + if(sheId!=null){ + for ( TShelves tShelves : tShelvesList){ + if (tShelves.getId().equals(sheId)) { + sheCode = tShelves.getCode(); + } + } + }else{ + List list= tShelvesList.stream().filter(tShelves -> tShelves.getDepotId().equals(depotId)).collect(Collectors.toList()); + int randomIndex = ThreadLocalRandom.current().nextInt(list.size()); + sheCode=list.get(randomIndex).getCode(); + } + return sheCode; + } + + + /** + * 获取货位编码freCode + * @param shelvesId + * @param freightId + * @param tFreightList + * @return + */ + private String getFre(Long shelvesId,Long freightId,List tFreightList) { + String freCode=""; + if(freightId!=null){ + for ( TFreight tFreight : tFreightList){ + if (tFreight.getId().equals(freightId)) { + freCode = tFreight.getCode(); + } + } + }else{ + List list= tFreightList.stream().filter(tFreight -> tFreight.getShelvesId().equals(shelvesId)).collect(Collectors.toList()); + int randomIndex = ThreadLocalRandom.current().nextInt(list.size()-1); + freCode=list.get(randomIndex).getCode(); + } + return freCode; + } + + + + // 生成A-Z或0-9的随机字符 +// public static char generateRandomChar() { +// int randomChoice = ThreadLocalRandom.current().nextInt(36); // 0-35 +// if (randomChoice < 26) { +// // 生成A-Z(ASCII码65-90) +// return (char) (randomChoice + 65); +// } else { +// // 生成0-9(ASCII码48-57),或直接数字转字符 +// return (char) (randomChoice - 26 + 48); +// } +// } + + + + + // 辅助方法:生成随机13位 ISBN + public static String generateRandomIsbn() { + StringBuilder sb = new StringBuilder(13); + ThreadLocalRandom random = ThreadLocalRandom.current(); + //国定第一个字符为6 + sb.append(678); + for (int i = 0; i < 10; i++) { + sb.append(random.nextInt(10)); // 生成0-9随机数 + } + return sb.toString(); + } + + + + /** + * 生成指定范围内的随机数 + * + * @param min 最小值 + * @param max 最大值 + * @return 随机数 + */ + private int generateRandomNumber(int min, int max) { + Random random=new Random(); + return random.nextInt(max - min + 1) + min; + } + + + + /** + * 构建货号 + * + * @param depotCode 仓库代码 + * @param sheCode 货架代码 + * @param freCode 自由区代码 + * @param conditionCode 品相 + * @param isbn ISBN号 + * @return 拼接后的货号 + */ + private String buildArtNo(String depotCode, String sheCode, String freCode, String conditionCode, String isbn,String Series) { + + //Series为空时,默认为A + if(isEmpty(Series)){ + Series="A"; + } +// 毫秒级时间戳 + long timestamp = System.currentTimeMillis(); + String time = encodeBase62(timestamp); + StringBuilder builder = new StringBuilder(); + builder.append(depotCode).append(sheCode).append(freCode).append(conditionCode).append(isbn).append(Series).append(time); + return builder.toString(); + } + + + // 品相映射表 + public static final Map CODE_MAP = IntStream.range(0, CONDITION_CODES.length).boxed().collect(Collectors.toMap( + i -> CONDITION_CODES[i], //键:数字标识(如"1") + i -> CONDITION_CODE[i], //值:字母标识(如"A") + (oldVal, newVal) -> oldVal, () -> new TreeMap<>(Comparator.comparingDouble(Double::doubleValue)))); + + + + public static final Map CHINESE_TO_CODE_MAP = IntStream.range(0, CHINESE_CODE.length).boxed().collect(Collectors.toMap( + i -> CHINESE_CODE[i], // 键:中文标识(如"一品") + i -> CONDITION_CODE[i], // 值:字母标识(如"A") + (oldVal, newVal) -> oldVal, + LinkedHashMap::new)); // 保持插入顺序 + + + public String convertChineseToCode(String chineseName) { + String code = CHINESE_TO_CODE_MAP.get(chineseName); + if (code == null) { + throw new IllegalArgumentException("无效的中文品名: " + chineseName); + } + return code; + } + + + /** + * 品相 字母对应 数字 + */ + public static String getQualityNum(String qualityStr){ + return QUALITY_MAP.getOrDefault(qualityStr, "UNDEFINED"); + } + + /** + * 根据输入的数值获取对应的条件代码 + * + * @param input 输入的数值,用于查找对应的条件代码 + * @return 对应的条件代码,如果找不到则返回"UNDEFINED" + */ + public static String getConditionCode(double input) { + return CODE_MAP.getOrDefault(input, "UNDEFINED"); + } + + /** + * 将ISBN-8转换为ISBN-13 + * + * @param isbn8 ISBN-8格式的字符串 + * @return ISBN-13格式的字符串 + * @throws IllegalArgumentException 如果输入的ISBN-8格式不正确,则抛出异常 + */ + public static String convert8To13(String isbn8) { + // 移除所有非数字字符 + String cleaned = isbn8.replaceAll("[^0-9]", ""); + + // 验证输入长度 + if (cleaned.length() != 8) { + throw new IllegalArgumentException("ISBN-8必须包含8位数字"); + } + + // 在前面添加978前缀 + String prefix = "978" + cleaned.substring(0, 7)+"00"; + // 计算新的校验位 + int checkDigit = calculateCheckDigit13(prefix); + // 返回完整的ISBN-13 + return prefix + checkDigit; + } + + /** + * 计算ISBN-13的校验位 + * + * @param digits ISBN-13的前12位数字 + * @return 计算得到的校验位 + */ + private static int calculateCheckDigit13(String digits) { + int sum = 0; + + for (int i = 0; i < digits.length(); i++) { + int digit = Character.getNumericValue(digits.charAt(i)); + // 奇数位(从0开始计数)乘以1,偶数位乘以3 + sum += (i % 2 == 0) ? digit * 1 : digit * 3; + } + int remainder = sum % 10; + return (remainder == 0) ? 0 : 10 - remainder; + } + + /** + * 书籍自动分配货区 + * + * @param freightGoodsCountList 货区商品数量列表 调用ZhishuShopGoodsMapper的selectFreightGoodsNumber()方法获得 + * @return 自动分配货区结果 + */ + public static FreightGoodsCountVo autoAllocatingAreas(List freightGoodsCountList) { + Assert.isTrue(!freightGoodsCountList.isEmpty(), "该用户下或没有库房区域,请检查后重试"); + // 找到最低的商品数量 + int minGoodsCount = Integer.MAX_VALUE; + for (FreightGoodsCountVo item : freightGoodsCountList) { + if (item.getGoodsCount() < minGoodsCount) { + minGoodsCount = item.getGoodsCount(); + } + } + // 收集所有具有最低商品数量的记录 + List minGoodsCountItems = new ArrayList<>(); + for (FreightGoodsCountVo item : freightGoodsCountList) { + if (item.getGoodsCount() == minGoodsCount) { + minGoodsCountItems.add(item); + } + } + // 如果有多个相同最低数量的记录,随机选择一个 + if (!minGoodsCountItems.isEmpty()) { + Random random = new Random(); + return minGoodsCountItems.get(random.nextInt(minGoodsCountItems.size())); + } + // 在正常情况下不会到达这里 + return null; + } + + + + + /** + * ISBN压缩 + * + * @param originalISBN 原始的ISBN + * @return 转换后的ISBN + */ + public static String convertISBN(String originalISBN) { + // 提取ISBN的前四位 + String firstFour = originalISBN.substring(0, 4); + // 提取ISBN的后九位 + String lastNine = originalISBN.substring(4, 13); + + // 对前四位进行编码 + String encodedFirstFour = encodeFirstFour(firstFour); + // 对后九位进行编码 + String encodedLastNine = encodeLastNine(lastNine); + // 返回编码后的ISBN + return encodedFirstFour + encodedLastNine; + } + + //正常isbn全部解压 + public static String revertISBN(String convertedISBN) { + String encodedFirstFour = convertedISBN.substring(0, 1); + String encodedLastNine = convertedISBN.substring(1, 6); + + String decodedFirstFour = decodeFirstFour(encodedFirstFour); + String decodedLastNine = decodeLastNine(encodedLastNine); + + return decodedFirstFour + decodedLastNine; + } + + //自定义isbn全部解压 + public static String revertRandomISBN(String convertedISBN) { + String encodedFirstFour = convertedISBN.substring(0, 1); + String encodedLastNine = convertedISBN.substring(1, 6); + + String decodedFirstFour = decodeRandomFirstFour(encodedFirstFour); + String decodedLastNine = decodeLastNine(encodedLastNine); + + return decodedFirstFour + decodedLastNine; + } + + /** + * 将字符串中的前四位数字转换为对应的字母 + * 此方法旨在处理特定格式的数据转换,将数字字符串的每一位数字映射到字母, + * 以便用于可能的编码或加密需求每个数字对应字母的规则是基于ASCII码, + * 数字0对应字母'A',1对应'B',以此类推 + * + * @param firstFour 一个包含四位数字的字符串如果输入的字符串不全为数字或者长度不是四, + * 将抛出IllegalArgumentException异常 + * @return 转换后的由字母组成的字符串 + * @throws IllegalArgumentException 如果输入字符串中包含非数字字符,抛出此异常 + */ + private static String encodeFirstFour(String firstFour) { + StringBuilder sb = new StringBuilder(); + if(firstFour.equals("9777")){ + sb.append('a'); + } + // 常规编码逻辑(9780-9789 → A-Z) + if (firstFour.startsWith("978") && firstFour.length() == 4) { + int lastDigit = firstFour.charAt(3) - '0'; + if (lastDigit >= 0 && lastDigit <= 9) { + sb.append((char) ('A' + lastDigit)); +// return String.valueOf((char)('A' + lastDigit)); + } + } + if (firstFour.startsWith("678") && firstFour.length() == 4) { + int lastDigit = firstFour.charAt(3) - '0'; + if (lastDigit >= 0 && lastDigit <= 9) { + sb.append((char) ('A' + lastDigit)); + } + } + return sb.toString(); + } + + +// 解压正常isbn前1位 + private static String decodeFirstFour(String encoded) { + StringBuilder sb = new StringBuilder(); + //将encoded转换为字符 + char encod = encoded.charAt(0); + if(encod==97){ + sb.append("9777"); + }else{ + // 校验输入范围(A-J) + if (encod < 'A' || encod > 'J') { + throw new IllegalArgumentException("输入字母必须为A-J之间"); + }else{ + // 计算数字部分(A=0, B=1,... J=9) + int digit = encod - 'A'; + String con= "978" + digit; + sb.append(con); + } + } + + // 返回构建好的字符串 + return sb.toString(); + } + + + // 解压自定义isbn前1位 + private static String decodeRandomFirstFour(String encoded) { + StringBuilder sb = new StringBuilder(); + //将encoded转换为字符 + char encod = encoded.charAt(0); + + int digit = encod - 'A'; + String con= "678" + digit; + sb.append(con); + // 返回构建好的字符串 + return sb.toString(); + } + + + + /** + * 将最后九位数字编码为Base64字符串 + * 此方法首先验证输入的最后九位数字是否有效,然后将其转换为Base64编码的字符串 + * 选择Base64编码是因为它可以在不增加存储空间的情况下,有效处理数字信息 + * 为何使用5作为toBase64的第二个参数:这里的5是根据具体的编码需求和目标字符集大小来选择的, + * 由于Base64字符集有64个字符,使用5个字符可以表示的数字范围与9位数字相符 + * + * @param lastNine 一个字符串,包含最后九位数字 + * @return 编码后的Base64字符串 + * @throws IllegalArgumentException 如果输入的数字不是9位 + */ + private static String encodeLastNine(String lastNine) { + // 验证输入的最后九位数字是否为有效的9位数字 + validateNineDigits(lastNine); + // 将验证过的字符串转换为长整型数字,以便进行后续的编码处理 + long number = Long.parseLong(lastNine); + // 使用Base64编码方式将数字编码为字符串,这里指定编码长度为5 + return toBase64(number, 5); + } + + private static String toBase64(long number, int length) { + char[] chars = new char[length]; + for (int i = length - 1; i >= 0; i--) { + chars[i] = BASE64_CHARS.charAt((int) (number % 64)); + number /= 64; + } + if (number != 0) { + throw new IllegalArgumentException("Number too large"); + } + return new String(chars); + } + +// isbn前4位压缩 + private static String decodeLastNine(String encoded) { + long number = fromBase64(encoded); + return String.format("%09d", number); + } + + +// 压缩毫秒级时间戳 + private static long fromBase64(String encoded) { + // 前置校验 + if (encoded == null || encoded.length() != 5) { + throw new IllegalArgumentException("必须为5位编码字符串"); + } + + // 解码计算 + long result = 0; + for (char c : encoded.toCharArray()) { + int index = BASE64_CHARS.indexOf(c); + if (index == -1) throw new IllegalArgumentException("非法字符: " + c); + if (result > (Long.MAX_VALUE - 63) / 64) { + throw new ArithmeticException("数值溢出"); + } + result = result * 64 + index; + } + return result; + } + + private static void validateNineDigits(String s) { + // 使用正则表达式检查字符串是否为9位数字 + if (!s.matches("\\d{9}")) { + // 如果不是9位数字,抛出异常并提示必须为9位数字 + throw new IllegalArgumentException("必须为9位数字"); + } + } + + + + + + /** + * 编码为 base62,结果填充至长度 7 + */ + public static String encodeBase62(long num) { + // 特殊情况处理:当输入数字为0时,直接返回编码字符的第一个字符 + if (num == 0) { + return CHARS.substring(0, 1); + } + + StringBuilder sb = new StringBuilder(); + // 循环将输入数字除以基数,并将余数转换为对应的Base62字符添加到字符串构建器中 + while (num > 0) { + long rem = num % BASE; + sb.append(CHARS.charAt((int) rem)); + num /= BASE; + } + // 将字符串构建器中的字符反转,以获得正确的编码顺序 + String encoded = sb.reverse().toString(); + // 填充到7位 + // 确保编码后的字符串长度至少为7位,不足7位时在前面补0 + return String.format("%7s", encoded).replace(' ', '0'); + } + + /** + * 解码 base62 字符串为 long 数值 + */ + public static long decodeBase62(String s) { + long num = 0; + for (char c : s.toCharArray()) { + num = num * BASE + CHARS.indexOf(c); + } + return num; + } + + +} + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ContentUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ContentUtils.java new file mode 100644 index 0000000..21272b9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ContentUtils.java @@ -0,0 +1,104 @@ +package org.dromara.zhishu.util; + +import com.hankcs.hanlp.HanLP; +import com.hankcs.hanlp.seg.common.Term; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + + +public class ContentUtils { + + + + /** + * 在章节词(如 第一、第1)前插入换行符 + */ + public static String insertLineBreakBeforeChapter(String text) { + // 匹配 "第一章"、"第一节"、"第1章"、"第12节" + return text.replaceAll("(第[一二三四五六七八九十零百千万]+[章|节]|第\\d+[章|节])", "\n$1"); } + + /** + * 判断字符串是否为章节标题格式,如: + * 第一章、第一节、第一、第1章、第1节 + */ + public static boolean isChapterTitle(String word) { + return word.matches("第[一二三四五六七八九十零百千万]+[章|节]") || // 中文数字 + 章/节 + word.matches("第\\d+[章|节]"); // 阿拉伯数字 + 章/节 + } + + public static String applyLineBreaks(String text) { + List sentences = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + +// // 先预处理文本,在章节词前加换行符 + String processedText = insertLineBreakBeforeChapter(text); + + List terms = HanLP.segment(processedText); + for (Term term : terms) { + if (term.word.equals("。") || term.word.equals("!") || term.word.equals("?") || term.word.equals(",")) { + // 标点断句逻辑保持不变 + sb.append(term.word); + sentences.add(sb.toString()); + sb = new StringBuilder(); + } else { + sb.append(term.word); + } + } + + // 添加最后一段未闭合的内容 + if (sb.length() > 0) { + //根据 \n 换行符 截断生成数组 + String[] words = sb.toString().split("\n"); + for(int i=0;i> readLargeCsvAsMap(String fileUrl, int page, int pageSize) throws Exception { + List> result = new ArrayList<>(); + HttpURLConnection connection = (HttpURLConnection) new URL(fileUrl).openConnection(); + + try (InputStreamReader isr = new InputStreamReader(connection.getInputStream()); + CSVReader reader = new CSVReader(isr)) { + + // 读取表头 + String[] headers = reader.readNext(); + if (headers == null) return result; + + // 跳过前N行(不加载到内存) + long skipLines = (page - 1) * pageSize; + while (skipLines-- > 0 && reader.readNext() != null); + + // 读取当前页 + String[] line; + int count = 0; + while (count < pageSize && (line = reader.readNext()) != null) { + Map row = new HashMap<>(); + for (int i = 0; i < headers.length; i++) { + row.put(headers[i], i < line.length ? line[i] : null); + } + result.add(row); + count++; + } + } finally { + connection.disconnect(); + } + return result; + } + + public static List queryCsvData(String csvUrl, Long taskId) { + // 读取CSV文件 + List csvData = null; + try { + csvData = readCsvFromUrl(csvUrl); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (CsvException e) { + throw new RuntimeException(e); + } + + // 处理数据并分组统计 + Map resultMap = new HashMap<>(); + + // 跳过表头行 + for (int i = 1; i < csvData.size(); i++) { + String[] row = csvData.get(i); + + // 解析CSV行数据 + Long currentTaskId = Long.parseLong(row[1]); + Long shopId = Long.parseLong(row[9]); + String status = row[5]; + + // 只处理指定taskId的数据 + if (!currentTaskId.equals(taskId)) { + continue; + } + + // 创建分组键 + String groupKey = shopId + "_" + status; + + // 更新统计结果 + RunningTaskNumVo vo = resultMap.computeIfAbsent(groupKey, k -> { + RunningTaskNumVo newVo = new RunningTaskNumVo(); + newVo.setTaskId(taskId); + newVo.setShopId(shopId); + newVo.setStatus(status); + newVo.setAllNum(0); + return newVo; + }); + + vo.setAllNum(vo.getAllNum() + 1); + } + + return new ArrayList<>(resultMap.values()); + } + + private static List readCsvFromUrl(String csvUrl) throws IOException, CsvException { + URL url = new URL(csvUrl); + try (CSVReader reader = new CSVReaderBuilder(new InputStreamReader(url.openStream())) + .withSkipLines(0) // 不跳过任何行,包括表头 + .build()) { + return reader.readAll(); + } + } + + + /** + * 查询店铺日志 + */ + public static List queryTaskDataFromCsv(String csvUrl, Long taskId, Long shopId) { + List result = new ArrayList<>(); + Map groupMap = new HashMap<>(); + + try (CSVReader reader = new CSVReader(new InputStreamReader(new URL(csvUrl).openStream()))) { + // 读取CSV头 + String[] headers = reader.readNext(); + if (headers == null) return result; + + // 确定各字段索引 + int taskIdIndex = findIndex(headers, "task_id"); + int shopIdIndex = findIndex(headers, "shop_id"); + int statusIndex = findIndex(headers, "status"); + int callbackIndex = findIndex(headers, "call_back_data"); + + String[] line; + while ((line = reader.readNext()) != null) { + // 解析字段 + Long currentTaskId = Long.parseLong(line[taskIdIndex]); + Long currentShopId = Long.parseLong(line[shopIdIndex]); + int status = Integer.parseInt(line[statusIndex]); + String callBackData = line[callbackIndex]; + + // 应用过滤条件 + if (!currentTaskId.equals(taskId) || + !currentShopId.equals(shopId) || + status == 0 || status == 1 || status == 2) { + continue; + } + + // 处理call_back_data分组逻辑 + String processedCallback = processCallbackData(callBackData); + + // 创建分组键 + String groupKey = status + "_" + processedCallback; + + // 更新统计结果 + RunningTaskNumVo vo = groupMap.computeIfAbsent(groupKey, k -> { + RunningTaskNumVo newVo = new RunningTaskNumVo(); + newVo.setTaskId(taskId); + newVo.setShopId(shopId); + newVo.setStatus(String.valueOf(status)); + newVo.setMsg(processedCallback); + newVo.setAllNum(0); + return newVo; + }); + + vo.setAllNum(vo.getAllNum() + 1); + } + } catch (Exception e) { + e.printStackTrace(); + System.out.println("处理CSV文件时出错"); + } + + result.addAll(groupMap.values()); + return result; + } + + private static String processCallbackData(String callBackData) { + if (callBackData == null) { + return ""; + } + if (callBackData.contains("上传成功")) { + return "上传成功"; + } else if (callBackData.contains("属性[ISBN编号]校验错误")) { + return "属性[ISBN编号]校验错误"; + } + return callBackData; + } + + private static int findIndex(String[] headers, String columnName) { + for (int i = 0; i < headers.length; i++) { + if (columnName.equalsIgnoreCase(headers[i])) { + return i; + } + } + throw new IllegalArgumentException("CSV中未找到列: " + columnName); + } + + public static List> readCsvAsMap(String fileUrl) throws Exception { + List> result = new ArrayList<>(); + HttpURLConnection connection = (HttpURLConnection) new URL(fileUrl).openConnection(); + + try (InputStreamReader isr = new InputStreamReader(connection.getInputStream()); + CSVReader reader = new CSVReaderBuilder(isr).build()) { + + // 读取表头 + String[] headers = reader.readNext(); + if (headers == null) return result; + + // 读取所有数据行 + String[] line; + while ((line = reader.readNext()) != null) { + Map row = new HashMap<>(); + for (int i = 0; i < headers.length; i++) { + row.put(headers[i], i < line.length ? line[i] : null); + } + result.add(row); + } + } finally { + connection.disconnect(); + } + return result; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DateUtilsUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DateUtilsUtils.java new file mode 100644 index 0000000..110c149 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DateUtilsUtils.java @@ -0,0 +1,102 @@ +package org.dromara.zhishu.util; + + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; + +/** + * 文件处理工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DateUtilsUtils { + + public static String getNowDate() { + // 获取当前日期和时间 + LocalDateTime now = LocalDateTime.now(); + + // 自定义日期时间格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + // 格式化日期和时间 + String formattedDateTime = now.format(formatter); + + return formattedDateTime; + } + + /** + * 根据传入的几个月,获取几个月后的当前时间 + * + * @param months 月份数量 + * @return 几个月后的日期时间,Date类型 + */ + public static Date getNextMonths(int months) { + // 获取当前日期和时间 + LocalDateTime now = LocalDateTime.now(); + + // 获取几个月后的日期和时间 + LocalDateTime futureMonth = now.plusMonths(months); + + // 转换为Date类型 + return Date.from(futureMonth.atZone(java.time.ZoneId.systemDefault()).toInstant()); + } + + /** + * 获取偏移天数的当前时间,格式为 yyyy-MM-dd HH:mm:ss + * + * @param dayOffset 天数偏移量 + * 0:当前时间 + * 1:当前时间 + 30天 + * -1:当前时间 - 30天 + * @return 格式化后的日期时间字符串 + */ + public static String getDateTimeWithOffset(int dayOffset) { + // 获取当前日期和时间 + LocalDateTime now = LocalDateTime.now(); + + // 计算偏移天数(乘以30) + int offsetDays = dayOffset * 30; + + // 根据偏移量调整日期 + LocalDateTime targetDateTime = now.plusDays(offsetDays); + + // 自定义日期时间格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + // 格式化日期和时间 + return targetDateTime.format(formatter); + } + + + /** + * 将日期字符串(格式:yyyy-MM-dd HH:mm:ss)转换为10位时间戳(秒级) + * 支持自定义格式 + * + * @param dateTimeStr 日期时间字符串 + * @param pattern 日期时间格式,例如 "yyyy-MM-dd HH:mm:ss" + * @return 10位时间戳(秒数),如果转换失败返回0 + */ + public static long dateStringToTimestamp10(String dateTimeStr, String pattern) { + if (dateTimeStr == null || dateTimeStr.trim().isEmpty() || pattern == null) { + return 0; + } + + try { + // 定义日期时间格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); + // 将字符串解析为LocalDateTime + LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr, formatter); + // 转换为时间戳(秒级) + return localDateTime.atZone(ZoneId.systemDefault()).toEpochSecond(); + } catch (Exception e) { + // 日志记录异常,可根据需要处理 + return 0; + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DecryptUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DecryptUtils.java new file mode 100644 index 0000000..f38f285 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/DecryptUtils.java @@ -0,0 +1,247 @@ +package org.dromara.zhishu.util; + +import org.dromara.zhishu.domain.dto.SuccessDataItemDto; +import org.springframework.util.StringUtils; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; + +/** + * 商品导出数据解密工具类 + * 对应 Python 脚本的解密逻辑 + */ +public class DecryptUtils { + + // 固定主密钥的 Base64 表示 (对应 Python 中的 MASTER_KEY_BASE64) + private static final String MASTER_KEY_BASE64 = "sx3ad0ApTJnKTSByRWwJQG/gO8CiCYzLjHTTMza0Aw0="; + + // Nonce 长度:8字节 + private static final int NONCE_BYTES = 8; + + // 需要解密的字段名列表 + private static final String[] ENCRYPTED_FIELDS = {"isbn", "goodsCode", "title", "skuCode"}; + + // 主密钥 + private static byte[] masterKey; + + static { + try { + masterKey = Base64.getDecoder().decode(MASTER_KEY_BASE64); + if (masterKey.length != 32) { + throw new RuntimeException("主密钥长度错误:期望 32 字节,实际 " + masterKey.length + " 字节"); + } + } catch (Exception e) { + throw new RuntimeException("初始化解密密钥失败", e); + } + } + + /** + * 解密单个加密字段值(增加判断) + */ + private static String decryptField(String encryptedValue) throws Exception { + if (!StringUtils.hasText(encryptedValue)) { + return encryptedValue; + } + + // 关键:如果不是加密数据,直接返回原值 + if (!isEncryptedData(encryptedValue)) { + System.out.println("[debug] 跳过非加密数据: " + encryptedValue); + return encryptedValue; + } + + try { + // 1. Base64 URL-Safe 解码 + String base64Str = encryptedValue + .replace('-', '+') + .replace('_', '/'); + + int padLen = (4 - (base64Str.length() % 4)) % 4; + base64Str += "=".repeat(padLen); + + byte[] raw = Base64.getDecoder().decode(base64Str); + + // 2. 检查长度 + if (raw.length < NONCE_BYTES) { + throw new IllegalArgumentException("密文长度不足"); + } + + // 3. 分离 nonce 和密文 + byte[] nonce = new byte[NONCE_BYTES]; + byte[] ciphertext = new byte[raw.length - NONCE_BYTES]; + System.arraycopy(raw, 0, nonce, 0, NONCE_BYTES); + System.arraycopy(raw, NONCE_BYTES, ciphertext, 0, ciphertext.length); + + // 4. 构造 IV + byte[] iv = new byte[16]; + System.arraycopy(nonce, 0, iv, 0, NONCE_BYTES); + + // 5. AES-CTR 解密 + SecretKeySpec keySpec = new SecretKeySpec(masterKey, "AES"); + IvParameterSpec ivSpec = new IvParameterSpec(iv); + + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); + + byte[] decrypted = cipher.doFinal(ciphertext); + + // 6. UTF-8 解码 + String result = new String(decrypted, StandardCharsets.UTF_8); + + // 7. 验证解密结果(可选) + if (!StringUtils.hasText(result)) { + System.err.println("[warn] 解密结果为空,可能密钥错误"); + } + + return result; + + } catch (Exception e) { + // 解密失败时返回原值,而不是抛出异常 + System.err.println("[warn] 解密失败,保留原值: " + encryptedValue + ", 原因: " + e.getMessage()); + return encryptedValue; + } + } + + /** + * 解密 SuccessDataItemDto 列表中的加密字段 + * + * @param dtoList 需要解密的 DTO 列表 + * @throws Exception 解密失败时抛出异常 + */ + public static void decryptDtoList(List dtoList) throws Exception { + if (dtoList == null || dtoList.isEmpty()) { + return; + } + + int decryptedCount = 0; + int skippedCount = 0; + + for (SuccessDataItemDto dto : dtoList) { + try { + // 解密 ISBN + if (StringUtils.hasText(dto.getIsbn())) { + try { + dto.setIsbn(decryptField(dto.getIsbn())); + decryptedCount++; + } catch (Exception e) { + skippedCount++; + System.err.println("[warn] ISBN 解密失败: " + e.getMessage()); + } + } + + // 解密商品编码 + if (StringUtils.hasText(dto.getGoodsCode())) { + try { + dto.setGoodsCode(decryptField(dto.getGoodsCode())); + decryptedCount++; + } catch (Exception e) { + skippedCount++; + System.err.println("[warn] 商品编码 解密失败: " + e.getMessage()); + } + } + + // 解密商品名称 + if (StringUtils.hasText(dto.getTitle())) { + try { + dto.setTitle(decryptField(dto.getTitle())); + decryptedCount++; + } catch (Exception e) { + skippedCount++; + System.err.println("[warn] 商品名称 解密失败: " + e.getMessage()); + } + } + + // 解密规格编码 + if (StringUtils.hasText(dto.getSkuCode())) { + try { + dto.setSkuCode(decryptField(dto.getSkuCode())); + decryptedCount++; + } catch (Exception e) { + skippedCount++; + System.err.println("[warn] 规格编码 解密失败: " + e.getMessage()); + } + } + + } catch (Exception e) { + System.err.println("[warn] 处理 DTO 时发生错误: " + e.getMessage()); + } + } + + System.out.println("解密完成:解密 " + decryptedCount + " 个字段,跳过 " + skippedCount + " 个字段"); + } + + /** + * 判断字符串是否为加密数据 + * 特征:包含Base64字符、长度>12、不是纯数字或纯字母 + */ + private static boolean isEncryptedData(String value) { + if (!StringUtils.hasText(value)) { + return false; + } + + // 长度至少大于12字节(8字节nonce + 至少4字节密文) + if (value.length() < 12) { + return false; + } + + // 纯数字的ISBN不是加密数据 + if (value.matches("\\d+")) { + return false; + } + + // 纯字母(如书名)不是加密数据 + if (value.matches("[a-zA-Z\\s\\u4e00-\\u9fa5]+")) { + return false; + } + + // 包含Base64特征字符 + return value.matches("^[A-Za-z0-9+/_-]+=*$"); + } + + + /** + * 获取主密钥指纹(用于验证) + * + * @return 密钥 SHA-256 前8位 + */ + public static String getKeyFingerprint() { + try { + java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256"); + byte[] hash = digest.digest(masterKey); + StringBuilder hexString = new StringBuilder(); + for (int i = 0; i < Math.min(4, hash.length); i++) { + String hex = Integer.toHexString(0xff & hash[i]); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } catch (Exception e) { + return "unknown"; + } + } + + /** + * 测试方法:验证解密功能 + */ + public static void main(String[] args) { + System.out.println("主密钥指纹: " + getKeyFingerprint()); + System.out.println("预期指纹: 63c70bdd"); + + // 测试用例:使用第一行数据的加密值 + String testIsbn = "m4Z6uhZiuc5-lDmv6p97FglNap0u"; + String testGoodsCode = "m4Z6uhZiuc5-lDmv6p97FglNap0u"; + String testTitle = "中学教材全练:九年级化学"; + String testSkuCode = "y4P9HTM8ThQ1BD7to7mC-4vhK-OI36Jh7Q"; + + try { + System.out.println("\n测试解密:"); + System.out.println("原始 ISBN: " + testIsbn); + // 注意:这里测试需要的是加密后的数据,示例中的是明文,实际使用时会自动解密 + } catch (Exception e) { + System.err.println("测试失败: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EasyExcelUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EasyExcelUtil.java new file mode 100644 index 0000000..7591f99 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EasyExcelUtil.java @@ -0,0 +1,700 @@ +package org.dromara.zhishu.util; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.opencsv.CSVReader; +import com.opencsv.CSVWriterBuilder; +import com.opencsv.ICSVWriter; +import lombok.RequiredArgsConstructor; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.utils.file.FileUtils; +import org.dromara.common.json.utils.JsonUtils; + +import java.io.*; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +import com.alibaba.fastjson.JSON; +import org.dromara.zhishu.domain.vo.BookEditIsOnsaleVo; +import org.dromara.zhishu.domain.vo.BookEditPriceVo; +import org.dromara.zhishu.domain.vo.BookEditStockVo; +import org.dromara.zhishu.domain.vo.BookVo; +import org.dromara.zhishu.service.client.FileClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + + +/** + * EasyExcel工具类 + * + * @author CWW + * @date 2024/12/18 16:46 + */ +@RequiredArgsConstructor +@Component +public class EasyExcelUtil { + + private static final String UTF_8 = "UTF-8"; + + /** + * 读取文件数据,并返回一个包含指定类型数据的列表。 + * + * @param inputStream 文件对象输入流 + * @param clazz 数据对象的类型 + * @param 泛型类型,表示数据对象的类型 + * @return 包含解析后数据对象的列表 + */ + public static List readMultipartFile(InputStream inputStream, Class clazz) { + // 用于存储解析后的数据对象 + final List dataList = new ArrayList<>(); + + EasyExcel.read(inputStream, clazz, new AnalysisEventListener() { + @Override + public void invoke(T data, AnalysisContext analysisContext) { + // 每一条数据解析都会调用此方法 + // 将解析后的数据对象添加到 dataList中 + dataList.add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext analysisContext) { + // 读取完成后可以进行一些操作 + } + }).sheet(0).doRead(); // 读取 Excel 文件中的第一个工作表 + + // 返回解析后数据对象的列表 + return dataList; + } + + + /** + * 将数据列表写入 Excel 文件,并设置表头 + * + * @param filePath 文件路径 + * @param data 数据列表 + * @param headMap 表头配置,键为字段名,值为表头显示名称 + */ + public static void writeExcel(String filePath, List> data, Map headMap) { + try ( + Workbook workbook = new XSSFWorkbook(); + FileOutputStream fileOut = new FileOutputStream(filePath)) { + Sheet sheet = workbook.createSheet("Sheet1"); + // 创建表头 + Row headerRow = sheet.createRow(0); + Cell headerCell = headerRow.createCell(0); + headerCell.setCellValue("书号"); + Cell headerCell4 = headerRow.createCell(1); + headerCell4.setCellValue("书名"); + Cell headerCell1 = headerRow.createCell(2); + headerCell1.setCellValue("价格"); + Cell headerCell2 = headerRow.createCell(3); + headerCell2.setCellValue("库存"); + Cell headerCell3 = headerRow.createCell(4); + headerCell3.setCellValue("日志"); + Cell headerCell5 = headerRow.createCell(5); + headerCell5.setCellValue("三方平台商品id"); + workbook.write(fileOut); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 将 Map 列表转换为 JSON 字符串并存储到文本文件中 + * + * @param fileName 文件名称 + * @param data 数据列表 + */ + public static void writeJsonToFile(String fileName, List> data) { + try { + String filePath = UrlUtil.getUrl() + fileName; + // 获取文件路径的父目录 + Path parentDir = Paths.get(filePath).getParent(); + // 如果父目录不存在,则创建它 + if (parentDir != null && !Files.exists(parentDir)) { + Files.createDirectories(parentDir); + } + + // 将 Map 列表转换为 JSON 字符串 + String jsonString = JSON.toJSONString(data); + + // 将 JSON 字符串写入文件 + try (FileWriter fileWriter = new FileWriter(filePath)) { + fileWriter.write(jsonString); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void writeJsonToFile(String fileName, String jsonString) { + try { + jsonString = jsonString == null ? "" : jsonString; + String filePath = UrlUtil.getUrl() + fileName; + // 获取文件路径的父目录 + Path parentDir = Paths.get(filePath).getParent(); + // 如果父目录不存在,则创建它 + if (parentDir != null && !Files.exists(parentDir)) { + Files.createDirectories(parentDir); + } + + // 将 JSON 字符串写入文件 + try (FileWriter fileWriter = new FileWriter(filePath)) { + fileWriter.write(jsonString); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取text文本文件中的字符串 + * + * @param filePath + * @return + */ + public static List> readFileContent(String filePath) { + StringBuilder contentBuilder = new StringBuilder(); + try { + Path path = Paths.get(filePath); + List lines = Files.readAllLines(path); + for (String line : lines) { + contentBuilder.append(line).append(System.lineSeparator()); + } + } catch (IOException e) { + e.printStackTrace(); + } + List> mapList = JsonUtils.parseObject(contentBuilder.toString(), List.class); + return mapList; + } + + public static String readFileContentString(String filePath) { + StringBuilder contentBuilder = new StringBuilder(); + try { + Path path = Paths.get(filePath); + // 先判断文件是否存在 + if (!Files.exists(path)) { + return ""; + } + List lines = Files.readAllLines(path); + for (String line : lines) { + contentBuilder.append(line).append(System.lineSeparator()); + } + } catch (IOException e) { + e.printStackTrace(); + return ""; + } + return contentBuilder.toString(); + } + + + /** + * 根据文件路径持续写入数据 + * + * @param excelFilePath 文件路径 + */ + public static void continuousWriting(String excelFilePath, List list) { + try ( + FileInputStream fis = new FileInputStream(excelFilePath); + Workbook workbook = new XSSFWorkbook(fis)) { + // 获取第一个工作表 + Sheet sheet = workbook.getSheetAt(0); + // 创建一行 + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + // 创建单元格并写入数据 + for (int i = 0; i < list.size(); i++) { + Cell cell = row.createCell(i); + cell.setCellValue(list.get(i)); + } + // 写入文件 + try (FileOutputStream fos = new FileOutputStream(excelFilePath)) { + workbook.write(fos); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 导出数据到Excel文件的通用方法。 + * + * @param 数据对象类型 + * @param basePath 文件保存的基础路径 + * @param fileName 文件名(包括扩展名) + * @param data 要导出的数据列表 + * @param sheetName Excel工作表名称 + * @param headClazz 数据对象类,用于映射Excel列标题 + */ + public static void exportToExcel(String basePath, String fileName, List data, String sheetName, Class headClazz) { + // 确保目录存在 + new File(basePath).mkdirs(); + + String filePath = basePath + fileName; + + try { + // 使用 EasyExcel 写入数据 + EasyExcel.write(filePath, headClazz) + .sheet(sheetName.length() > 31 ? sheetName.substring(0, 31) : sheetName) + .doWrite(data); + } catch (Exception e) { + // 处理异常 + e.printStackTrace(); + // 可以在这里添加更多的错误处理逻辑,例如记录日志、通知等 + throw new RuntimeException("导出Excel文件失败", e); + } + } + + public static List> convertExcelToMap(String filePath) { + List> result = new ArrayList<>(); + + try (FileInputStream fileInputStream = new FileInputStream(new File(filePath)); + Workbook workbook = new XSSFWorkbook(fileInputStream)) { + + Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表 + Iterator rowIterator = sheet.iterator(); + + // 获取表头(第一行) + Row headerRow = rowIterator.next(); + List headers = new ArrayList<>(); + for (Cell cell : headerRow) { + headers.add(cell.getStringCellValue()); + } + + // 遍历数据行 + while (rowIterator.hasNext()) { + Row row = rowIterator.next(); + Map rowMap = new HashMap<>(); + + for (int i = 0; i < headers.size(); i++) { + Cell cell = row.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); + rowMap.put(headers.get(i), getCellValue(cell)); + } + + result.add(rowMap); + } + + } catch (IOException e) { + e.printStackTrace(); + } + + return result; + } + + + /** + * 从URL读取Excel文件并转换为指定类型的对象列表 + * @param url Excel文件的URL地址 + * @param clazz 要转换的目标类类型 + * @param 泛型类型 + * @return 读取后的对象列表 + * @throws RuntimeException 当读取失败时抛出 + */ + public static List readExcelFromUrl(String url, Class clazz) { + try (InputStream inputStream = new URL(url).openStream()) { + return EasyExcel.read(inputStream) + .head(clazz) + .sheet() + .doReadSync(); + } catch (Exception e) { + throw new RuntimeException("读取Excel失败: " + e.getMessage(), e); + } + } + + + + private static Object getCellValue(Cell cell) { + switch (cell.getCellType()) { + case STRING: + return cell.getStringCellValue(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + return cell.getLocalDateTimeCellValue(); + } else { + return cell.getNumericCellValue(); + } + case BOOLEAN: + return cell.getBooleanCellValue(); + case FORMULA: + return cell.getCellFormula(); + default: + return ""; + } + } + + public static void writeTxtMsgLog(Long taskId, Integer totalNum, Integer executedNum) { + StringBuffer stringBuffer = new StringBuffer(); + String str = "开始执行文件" + System.lineSeparator() + + "开始进行数据加载" + System.lineSeparator() + + "数据加载完毕" + System.lineSeparator() + + "正在执行" + System.lineSeparator() + + "已执行数据:" + executedNum + "条" + System.lineSeparator() + + "待执行数据:" + (totalNum - executedNum) + "条" + System.lineSeparator(); + stringBuffer.append(str); + if (executedNum.equals(totalNum)) { + stringBuffer.append("文件执行完成"); + } + // 记录日志 + EasyExcelUtil.writeJsonToFile(taskId + "-msg.txt", stringBuffer.toString()); + } + + public static void writeTxtLog(Long taskId, Long shopId, String shopName, Integer total, Integer executedNum) { + List> mapList = new ArrayList<>(); + Map map = new HashMap<>(); + map.put("shopId", shopId); + map.put("shopName", shopName); + map.put("num", executedNum); + // 计算百分比 + map.put("progress", CountUtils.calculatePercentage(total, executedNum)); + map.put("createTime", DateUtilsUtils.getNowDate()); + map.put("updateTime", DateUtilsUtils.getNowDate()); + map.put("taskId", taskId); + mapList.add(map); + // 写入txt文件中 + EasyExcelUtil.writeJsonToFile(taskId + ".txt", mapList); + } + + /** + * 存储任务中店铺里的日志类型进度 + * + * @param taskId + * @param shopId + * @param shopName + * @param logName + * @param mark + * @param total + */ + public static void writeDetailTxtLog(Long taskId, Long shopId, String shopName, Integer total, Integer executedNum, String logName, String mark) { + String filePath = UrlUtil.getUrl() + taskId + "" + shopId + ".txt"; + // true为txt文件中不存在店铺信息,false代表存在 + Boolean bool = true; + List> mapList = new ArrayList<>(); + if (FileUtils.isFileExists(filePath)) { + mapList = EasyExcelUtil.readFileContent(filePath); + // txt文本不为空,则遍历List对象,查看是否存在店铺id,存在,则数量+1,不存在则添加 + for (Map map : mapList) { + if (map.get("logName").equals(logName)) { + bool = false; + map.put("num", executedNum); + map.put("progress", CountUtils.calculatePercentage(total, executedNum)); + } + } + } + if (bool) { + Map map = new HashMap<>(); + map.put("shopId", shopId); + map.put("shopName", shopName); + map.put("num", executedNum); + // 计算百分比 + map.put("progress", CountUtils.calculatePercentage(total, executedNum)); + map.put("taskId", taskId); + map.put("logName", logName); + map.put("mark", mark); + mapList.add(map); + } + // 写入txt文件中 + EasyExcelUtil.writeJsonToFile(taskId + "" + shopId + ".txt", mapList); + } + + + + /** + * 将 List> 转换为CSV并上传到资源服务器 + * + * @param fileName 文件名(如 output.csv) + * @param dataList 数据列表 + * @param headers 表头字段(用于生成列名) + * @return 是否上传成功 + */ + public static boolean writeMapsToCsvWithHeader(String fileName, List> dataList, + List headers, FileClient fileClient,Long mallId) { + try { + // 1. 将数据转换为CSV格式的字符串 + StringWriter stringWriter = new StringWriter(); + try (ICSVWriter csvWriter = new CSVWriterBuilder(stringWriter) + .build()) { + // 写入表头 + csvWriter.writeNext(headers.toArray(new String[0])); + // 写入数据 + for (Map data : dataList) { + String[] row = new String[headers.size()]; + for (int j = 0; j < headers.size(); j++) { + String header = headers.get(j); + Object value = data.get(header); + // 如果是 sku_list 字段,转换为 JSON 字符串 + if ("sku_list".equals(header) && value instanceof List) { + row[j] = JSON.toJSONString(value); // 转换为 JSON 字符串 + } else { + row[j] = value != null ? value.toString() : ""; + } + } + csvWriter.writeNext(row); + } + } + // 2. 将CSV内容转换为Base64 + String csvContent = stringWriter.toString(); + String base64Content = Base64.getEncoder().encodeToString(csvContent.getBytes(StandardCharsets.UTF_8)); + + // 3. 上传到资源服务器 + R result = fileClient.upload(UrlUtil.getFileServiceUrl(), base64Content, "ShopGoodsDataCSV/"+mallId, fileName); + + return R.isSuccess(result); + + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + // public static void writeMapsToCsvWithHeader(String filePath, List> dataList, List headers, boolean append) { + // Path path = Paths.get(filePath); + // Path parentDir = path.getParent(); + // + // try { + // // 1. 创建父目录(如果不存在) + // if (parentDir != null && !Files.exists(parentDir)) { + // Files.createDirectories(parentDir); + // } + // + // // 2. 创建文件(如果不存在) + // if (!Files.exists(path)) { + // Files.createFile(path); + // } + // + // // 3. 使用 BufferedWriter + OpenCSV 高性能写入 + // try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8); + // ICSVWriter csvWriter = new CSVWriterBuilder(writer) + // .withQuoteChar('"') // 替换为实际字符 + // .withEscapeChar('\\') // 替换为实际字符 + // .build()) { + // + // // 写入表头(仅在文件为空或非追加模式下写入) + // if (!append || Files.size(path) == 0) { + // csvWriter.writeNext(headers.toArray(new String[0])); + // } + // + // // 4. 倒序遍历 dataList + // for (int i = dataList.size() - 1; i >= 0; i--) { + // Map data = dataList.get(i); + // String[] row = new String[headers.size()]; + // for (int j = 0; j < headers.size(); j++) { + // Object value = data.get(headers.get(j)); + // row[j] = value != null ? value.toString() : ""; + // } + // csvWriter.writeNext(row); + // } + // + // } + // } catch (IOException e) { + // e.printStackTrace(); + // } + // } + + /** + * 分页读取 CSV 文件内容 + * + * @param fileBase64Str 文件Base64编码 + * @param page 当前页码(从1开始) + * @param pageSize 每页行数 + * @param hasHeader 是否有表头(true=第一行是标题) + * @return 当前页的数据(List>),key是列名,value是单元格值 + */ + public static List> readCsvWithPagination(String fileBase64Str, + int page, + int pageSize, + boolean hasHeader) { + List> currentPageData = new ArrayList<>(); + + if (page < 1 || pageSize < 1) { + throw new IllegalArgumentException("页码和每页行数必须大于等于1"); + } + + try { + + // 如果是Base64编码,需要解码 + byte[] decodedBytes = Base64.getDecoder().decode(fileBase64Str); + String csvContent = new String(decodedBytes, StandardCharsets.UTF_8); + + // 使用CSVReader读取内容 + try (CSVReader reader = new CSVReader(new StringReader(csvContent))) { + List allRows = reader.readAll(); + int totalRows = allRows.size(); + + // 计算起始行号(跳过表头) + int startRow = hasHeader ? 1 : 0; + int endRow = Math.min(startRow + (page - 1) * pageSize + pageSize, totalRows); + + // 获取当前页的行数据 + for (int i = startRow + (page - 1) * pageSize; i < endRow; i++) { + String[] row = allRows.get(i); + Map rowMap = new HashMap<>(); + + // 如果有表头,则用表头字段作为key,否则用"col_0", "col_1"... + if (hasHeader && !allRows.isEmpty()) { + String[] header = allRows.get(0); + for (int j = 0; j < row.length; j++) { + if (j < header.length) { + rowMap.put(header[j], j < row.length ? row[j] : ""); + } else { + rowMap.put("col_" + j, j < row.length ? row[j] : ""); + } + } + } else { + for (int j = 0; j < row.length; j++) { + rowMap.put("col_" + j, row[j]); + } + } + + currentPageData.add(rowMap); + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return currentPageData; + } + // public static List> readCsvWithPagination(String filePath, int page, int pageSize, boolean hasHeader) { + // List> currentPageData = new ArrayList<>(); + // Path path = Paths.get(filePath); + // + // if (page < 1 || pageSize < 1) { + // throw new IllegalArgumentException("页码和每页行数必须大于等于 1"); + // } + // + // try (CSVReader reader = new CSVReader(new FileReader(path.toFile()))) { + // List allRows = reader.readAll(); + // int totalRows = allRows.size(); + // + // // 计算起始行号(跳过表头) + // int startRow = hasHeader ? 1 : 0; + // int endRow = Math.min(startRow + (page - 1) * pageSize + pageSize, totalRows); + // + // // 获取当前页的行数据 + // for (int i = startRow + (page - 1) * pageSize; i < endRow; i++) { + // String[] row = allRows.get(i); + // Map rowMap = new HashMap<>(); + // + // // 如果有表头,则用表头字段作为 key,否则用 "col_0", "col_1" ... + // if (hasHeader && !allRows.isEmpty()) { + // String[] header = allRows.get(0); + // for (int j = 0; j < row.length; j++) { + // if (j < header.length) { + // rowMap.put(header[j], j < row.length ? row[j] : ""); + // } else { + // rowMap.put("col_" + j, j < row.length ? row[j] : ""); + // } + // } + // } else { + // for (int j = 0; j < row.length; j++) { + // rowMap.put("col_" + j, row[j]); + // } + // } + // + // currentPageData.add(rowMap); + // } + // + // } catch (Exception e) { + // e.printStackTrace(); + // } + // + // return currentPageData; + // } + + /** + * 获取 CSV 文件中除第一行标题外的总行数 + * + * @param base64Content CSV 文件的 Base64 编码内容 + * @return 除标题行外的数据行数(-1 表示出错,0 表示文件为空) + */ + public static int getRowCountWithoutHeader(String base64Content) { + if (base64Content == null || base64Content.isEmpty()) { + System.err.println("Base64 内容为空"); + return -1; + } + + try { + // 解码 Base64 内容 + byte[] decodedBytes = Base64.getDecoder().decode(base64Content); + String csvContent = new String(decodedBytes, StandardCharsets.UTF_8); + + try (CSVReader reader = new CSVReader(new StringReader(csvContent))) { + List allRows = reader.readAll(); + + if (allRows.isEmpty()) { + System.out.println("CSV 内容为空"); + return 0; + } + + // 假设第一行是标题行,返回剩余行数 + return allRows.size() - 1; + } + } catch (IllegalArgumentException e) { + System.err.println("Base64 解码失败"); + e.printStackTrace(); + return -1; + } catch (Exception e) { + System.err.println("解析 CSV 内容失败"); + e.printStackTrace(); + return -1; + } + } + // public static int getRowCountWithoutHeader(String filePath) { + // Path path = Paths.get(filePath); + // + // if (!Files.exists(path)) { + // System.err.println("文件不存在:" + filePath); + // return -1; + // } + // + // try (CSVReader reader = new CSVReader(new FileReader(path.toFile()))) { + // List allRows = reader.readAll(); + // + // // 如果文件有标题行,则减去一行 + // if (!allRows.isEmpty()) { + // return allRows.size() - 1; // 减去标题行 + // } else { + // System.out.println("文件为空"); + // return 0; + // } + // } catch (Exception e) { + // System.err.println("读取文件失败:" + filePath); + // e.printStackTrace(); + // return -1; + // } + // } + + /** + * 如果文件存在,则删除该文件 + * + * @param filePath 文件路径 + * @return 如果文件被成功删除或不存在,返回 true;否则返回 false + */ + public static boolean deleteFileIfExist(String filePath) { + Path path = Paths.get(filePath); + + try { + if (Files.exists(path)) { + Files.delete(path); // 删除文件 + System.out.println("文件已删除:" + filePath); + return true; + } else { + System.out.println("文件不存在,无需删除:" + filePath); + return true; + } + } catch (IOException e) { + System.err.println("删除文件失败:" + filePath); + e.printStackTrace(); + return false; + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EnvironmentVariableCredentialsProvider2.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EnvironmentVariableCredentialsProvider2.java new file mode 100644 index 0000000..8330aaa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/EnvironmentVariableCredentialsProvider2.java @@ -0,0 +1,34 @@ +package org.dromara.zhishu.util; + +import com.aliyun.oss.common.auth.Credentials; +import com.aliyun.oss.common.auth.CredentialsProvider; +import com.aliyun.oss.common.auth.DefaultCredentials; +import com.aliyun.oss.common.auth.InvalidCredentialsException; +import com.aliyun.oss.common.utils.StringUtils; + +public class EnvironmentVariableCredentialsProvider2 implements CredentialsProvider { + + public EnvironmentVariableCredentialsProvider2() { + } + + @Override + public void setCredentials(Credentials credentials) { + + } + + @Override + public Credentials getCredentials() { + String accessKeyId = "LTAI5tAsqEnyKfXngHep4X96"; + String secretAccessKey = "rO8ADdtgQ1ddp6EzJHPCvNpviGfP3r"; + String sessionToken = ""; + if (accessKeyId != null && !accessKeyId.equals("")) { + if (secretAccessKey != null && !secretAccessKey.equals("")) { + return new DefaultCredentials(accessKeyId, secretAccessKey, sessionToken); + } else { + throw new InvalidCredentialsException("Secret access key should not be null or empty."); + } + } else { + throw new InvalidCredentialsException("Access key id should not be null or empty."); + } + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ExcelFileHandlerUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ExcelFileHandlerUtil.java new file mode 100644 index 0000000..ac3ecfc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ExcelFileHandlerUtil.java @@ -0,0 +1,462 @@ +package org.dromara.zhishu.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.fastjson.JSONObject; +import com.aliyuncs.utils.IOUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.*; +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +@Slf4j +public class ExcelFileHandlerUtil { + + /** + * 处理导出 + * + * @param data + * @param type + * @param shopId + */ + public static void handleExport(List data, String basePath, String type, String shopId, Class clazz) { + if (ObjectUtil.isNotEmpty(data)) { + // 拼接文件名称 + String fileName = type + "_" + shopId + "_0.xlsx"; + // 拼接导出Excel的默认第一个sheet页名称 + String sheetName = type + "_" + shopId + "_0"; + // 用EasyExcel导出工具类,将数据写入Excel文件 + EasyExcelUtil.exportToExcel(basePath, fileName, data, sheetName, clazz); + } + } + + // 方法一:同步写入 Excel 文件 + public static void syncWriteRecord(String baseDir, String prefix, List records, String sheetName) { + try { + // 构造完整文件路径 + String filename = prefix + "_0.xlsx"; + File dir = new File(baseDir); + if (!dir.exists()) { + dir.mkdirs(); // 如果目录不存在,则创建目录 + } + String fullPath = baseDir + filename; + File file = new File(fullPath); + + Workbook workbook; + Sheet sheet; + + // 判断文件是否存在并打开或创建工作簿 + if (file.exists()) { + try (FileInputStream fis = new FileInputStream(file)) { + workbook = WorkbookFactory.create(fis); + } + } else { + workbook = new XSSFWorkbook(); + } + + // 确保有指定名称的sheet,如果没有就创建 + if (workbook.getSheetIndex(sheetName) == -1) { + sheet = workbook.createSheet(sheetName); + createHeaderRow(sheet, records.get(0)); + } else { + sheet = workbook.getSheet(sheetName); + } + + // 写入数据行 + int nextRowNum = sheet.getLastRowNum() + 1; + for (T record : records) { + Row row = sheet.createRow(nextRowNum++); + writeDataRow(row, record); + } + + // 写入文件 + try (FileOutputStream fos = new FileOutputStream(file)) { + workbook.write(fos); + } + + workbook.close(); + } catch (Exception e) { + log.error("写入Excel错误-{}", JSONObject.toJSONString(e)); + } + } + + // 创建表头行(仅在新建 sheet 时调用) + private static void createHeaderRow(Sheet sheet, T record) { + Row headerRow = sheet.createRow(0); + Field[] fields = record.getClass().getDeclaredFields(); + + for (int i = 0; i < fields.length; i++) { + fields[i].setAccessible(true); + Cell cell = headerRow.createCell(i); + cell.setCellValue(fields[i].getName()); + } + } + + // 将记录对象的数据写入到指定的行中 + private static void writeDataRow(Row row, T record) throws IllegalAccessException { + Field[] fields = record.getClass().getDeclaredFields(); + + for (int i = 0; i < fields.length; i++) { + fields[i].setAccessible(true); + Cell cell = row.createCell(i); + Object value = fields[i].get(record); + setValueToCell(cell, value); + } + } + + // 设置单元格值 + private static void setValueToCell(Cell cell, Object value) { + if (value instanceof String) { + cell.setCellValue((String) value); + } else if (value instanceof Number) { + cell.setCellValue(((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + cell.setCellValue((Boolean) value); + } else if (value instanceof java.util.Date) { + cell.setCellValue((java.util.Date) value); + } else { + cell.setCellValue(value != null ? value.toString() : ""); + } + } + + // 方法二:批量删除指定文件夹下名称前缀相同的文件 + public static void deleteFilesByPrefix(String baseDir, String prefix) { + File dir = new File(baseDir); + if (!dir.exists() || !dir.isDirectory()) { + return; + } + + // 遍历目录下的所有文件 + for (File file : Objects.requireNonNull(dir.listFiles())) { + if (file.isFile() && file.getName().startsWith(prefix)) { + boolean deleted = file.delete(); + System.out.println((deleted ? "已删除:" : "删除失败:") + file.getAbsolutePath()); + } + } + } + + /** + * 读取指定目录下以 prefix 开头的 Excel 文件,并将其解析为指定 Java 对象列表 + * + * @param baseDir 目标目录 + * @param prefix 文件名前缀 + * @param clazz Java对象类型 + * @return 解析后的Java对象列表 + */ + public static List readExcelWithPrefix(String baseDir, String prefix, Class clazz) { + List result = new ArrayList<>(); + File dir = new File(baseDir); + + if (!dir.exists() || !dir.isDirectory()) { + log.warn("目录不存在或无效: {}", baseDir); + return result; + } + + // 查找匹配的Excel文件 + File targetFile = null; + for (File file : Objects.requireNonNull(dir.listFiles())) { + if (file.isFile() && file.getName().startsWith(prefix) && file.getName().endsWith(".xlsx")) { + targetFile = file; + break; + } + } + + if (targetFile == null) { + log.info("未找到以 {} 开头的 Excel 文件", prefix); + return result; + } + + try (Workbook workbook = WorkbookFactory.create(targetFile)) { + Sheet sheet = workbook.getSheetAt(0); // 只读取第一个sheet + Iterator rowIterator = sheet.iterator(); + + if (!rowIterator.hasNext()) { + log.warn("Excel 文件为空: {}", targetFile.getAbsolutePath()); + return result; + } + + Row headerRow = rowIterator.next(); // 跳过表头 + Map headerMap = new HashMap<>(); + + // 构建列索引 -> 字段名的映射 + headerRow.forEach(cell -> { + int columnIndex = cell.getColumnIndex(); + String fieldName = cell.getStringCellValue(); + headerMap.put(columnIndex, fieldName); + }); + + // 获取类字段并设置可访问 + Field[] fields = clazz.getDeclaredFields(); + Map fieldMap = new HashMap<>(); + for (Field field : fields) { + field.setAccessible(true); + fieldMap.put(field.getName(), field); + } + + // 读取数据行 + while (rowIterator.hasNext()) { + Row dataRow = rowIterator.next(); + T instance = clazz.getDeclaredConstructor().newInstance(); + + dataRow.forEach(cell -> { + int colIndex = cell.getColumnIndex(); + String fieldName = headerMap.get(colIndex); + Field field = fieldMap.get(fieldName); + + if (field != null) { + try { + Object value = getCellValue(cell, field.getType()); + field.set(instance, value); + } catch (Exception e) { + log.warn("设置字段 [{}] 值失败: {}", fieldName, e.getMessage()); + } + } + }); + + result.add(instance); + } + + log.info("成功从文件 {} 中读取 {} 条记录", targetFile.getName(), result.size()); + + } catch (Exception e) { + log.error("读取Excel文件异常: {}", JSONObject.toJSONString(e)); + } + + return result; + } + + /** + * 根据 Cell 和目标类型提取对应值 + */ + private static Object getCellValue(Cell cell, Class targetType) throws Exception { + if (targetType.equals(String.class)) { + return cell.getCellType() == CellType.STRING ? cell.getStringCellValue() : cell.toString(); + } else if (Number.class.isAssignableFrom(targetType)) { + if (cell.getCellType() == CellType.NUMERIC) { + return cell.getNumericCellValue(); + } else { + String text = cell.toString(); + if (targetType.equals(Integer.class) || targetType.equals(int.class)) { + return Integer.parseInt(text); + } else if (targetType.equals(Long.class) || targetType.equals(long.class)) { + return Long.parseLong(text); + } else if (targetType.equals(Double.class) || targetType.equals(double.class)) { + return Double.parseDouble(text); + } else if (targetType.equals(Float.class) || targetType.equals(float.class)) { + return Float.parseFloat(text); + } + } + } else if (targetType.equals(Boolean.class) || targetType.equals(boolean.class)) { + return cell.getBooleanCellValue(); + } else if (targetType.equals(java.util.Date.class)) { + return cell.getDateCellValue(); + } + + return cell.toString(); // 默认返回字符串表示 + } + + /** + * 根据指定目录和多个 type 类型,读取所有符合命名规则的 Excel 文件, + * 并按照 type -> shopId -> 数据列表 的结构返回。 + * + * @param baseDir 目标目录 + * @param types 允许读取的 type 列表(如 ["New", "Update"]) + * @param clazz Java对象类型 + * @return 嵌套Map: Map>> + */ + public static Map>> readExcelByTypeAndShopId( + String baseDir, + Collection types, + Class clazz) { + Map>> result = new HashMap<>(); + + File dir = new File(baseDir); + if (!dir.exists() || !dir.isDirectory()) { + log.warn("目录不存在或无效: {}", baseDir); + return result; + } + + for (File file : Objects.requireNonNull(dir.listFiles())) { + if (!file.isFile() || !file.getName().endsWith(".xlsx")) continue; + + String fileName = file.getName(); + if (!fileName.startsWith("Error_")) continue; + + String[] parts = fileName.replace(".xlsx", "").split("_"); + if (parts.length < 5) continue; // Error + type + shopId + threadId + index + + String type = parts[1]; + String shopIdStr = parts[2]; + + if (!types.contains(type)) continue; + + Long shopId; + try { + shopId = Long.valueOf(shopIdStr); + } catch (NumberFormatException e) { + log.warn("无法解析 shopId: {}", shopIdStr); + continue; + } + + // 构造 prefix(去掉最后的 _0.xlsx) + String prefix = fileName.substring(0, fileName.lastIndexOf('_')); + + List dataList = readExcelWithPrefix(baseDir, prefix, clazz); + + result.computeIfAbsent(type, k -> new ConcurrentHashMap<>()) + .computeIfAbsent(shopId, k -> new ArrayList<>()) + .addAll(dataList); + } + + log.info("成功读取 {} 个类型的数据", result.size()); + return result; + } + + /** + * 追加数据到Excel文件(保持与EasyExcel相同的表头格式) + * @param baseDir 基础目录 + * @param prefix 文件名前缀(格式:Type_ShopId) + * @param records 要追加的数据列表 + * @param clazz 数据类型 + */ + public static void appendToExcel(String baseDir, String prefix, List records, Class clazz) { + if (CollUtil.isEmpty(records)) { + return; + } + + FileOutputStream fos = null; + Workbook workbook = null; + try { + // 构造完整文件路径 + String filename = prefix + ".xlsx"; + File dir = new File(baseDir); + if (!dir.exists()) { + dir.mkdirs(); + } + String fullPath = baseDir + File.separator + filename; + File file = new File(fullPath); + + // 1. 准备表头(模仿EasyExcel的样式) + List headers = new ArrayList<>(); + Map fieldOrder = new HashMap<>(); + + // 解析类注解获取表头信息(与EasyExcel相同逻辑) + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + if (excelProperty != null) { + String[] value = excelProperty.value(); + String header = value.length > 0 ? value[0] : field.getName(); + headers.add(header); + fieldOrder.put(field.getName(), excelProperty.index()); + } + } + + // 2. 处理工作簿 + if (file.exists()) { + // 已有文件:追加模式 + try (FileInputStream fis = new FileInputStream(file)) { + workbook = WorkbookFactory.create(fis); + } + + Sheet sheet = workbook.getSheet(prefix); + if (sheet == null) { + sheet = workbook.createSheet(prefix); + // 创建与EasyExcel相同的表头 + createEasyExcelStyleHeader(sheet, headers); + } + } else { + // 新文件 + workbook = new XSSFWorkbook(); + Sheet sheet = workbook.createSheet(prefix); + // 创建与EasyExcel相同的表头 + createEasyExcelStyleHeader(sheet, headers); + } + + // 3. 追加数据 + Sheet sheet = workbook.getSheet(prefix); + int lastRowNum = sheet.getLastRowNum(); + int startRow = (lastRowNum == 0 && sheet.getRow(0) != null) ? 1 : lastRowNum + 1; + + // 按字段顺序写入数据 + for (int i = 0; i < records.size(); i++) { + T record = records.get(i); + Row row = sheet.createRow(startRow + i); + + for (Field field : fields) { + field.setAccessible(true); + ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + if (excelProperty != null) { + int colIndex = excelProperty.index(); + Object value = field.get(record); + Cell cell = row.createCell(colIndex); + setCellValue(cell, value); + } + } + } + + // 4. 写入文件(增量写入) + fos = new FileOutputStream(file); + workbook.write(fos); + + } catch (Exception e) { + log.error("追加数据到Excel文件错误", e); + throw new RuntimeException("导出Excel文件失败", e); + } finally { + IOUtils.closeQuietly(workbook); + IOUtils.closeQuietly(fos); + } + } + + /** + * 创建与EasyExcel风格一致的表头 + */ + private static void createEasyExcelStyleHeader(Sheet sheet, List headers) { + Row headerRow = sheet.createRow(0); + + // 设置表头样式(模仿EasyExcel的默认样式) + CellStyle headerStyle = sheet.getWorkbook().createCellStyle(); + Font font = sheet.getWorkbook().createFont(); + font.setBold(true); + font.setFontHeightInPoints((short) 12); + headerStyle.setFont(font); + headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + headerStyle.setBorderBottom(BorderStyle.THIN); + + // 写入表头 + for (int i = 0; i < headers.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers.get(i)); + cell.setCellStyle(headerStyle); + // 自动调整列宽 + sheet.autoSizeColumn(i); + } + } + + /** + * 设置单元格值(类型处理) + */ + private static void setCellValue(Cell cell, Object value) { + if (value == null) { + cell.setCellValue(""); + } else if (value instanceof Number) { + cell.setCellValue(((Number) value).doubleValue()); + } else if (value instanceof Boolean) { + cell.setCellValue((Boolean) value); + } else if (value instanceof Date) { + cell.setCellValue((Date) value); + // 设置日期格式 + CellStyle style = cell.getSheet().getWorkbook().createCellStyle(); + style.setDataFormat(cell.getSheet().getWorkbook().createDataFormat().getFormat("yyyy-MM-dd HH:mm:ss")); + cell.setCellStyle(style); + } else { + cell.setCellValue(value.toString()); + } + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ExpressCompanyDetector.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ExpressCompanyDetector.java new file mode 100644 index 0000000..31826ba --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ExpressCompanyDetector.java @@ -0,0 +1,378 @@ +package org.dromara.zhishu.util; + +import java.util.*; +import java.util.regex.Pattern; + +/** + * 纯本地快递公司识别工具 + * 不依赖外部API,基于规则识别 + */ +public class ExpressCompanyDetector { + + // 快递公司信息类 + public static class ExpressInfo { + private String code; // 公司编码 + private String name; // 公司名称 + + public ExpressInfo(String code, String name) { + this.code = code; + this.name = name; + } + + public String getCode() { return code; } + public String getName() { return name; } + + } + + // 快递公司规则定义 + private static class ExpressRule { + String code; + String name; + List patterns; + int priority; // 优先级,数字越小优先级越高 + + ExpressRule(String code, String name, String[] regexes, int priority) { + this.code = code; + this.name = name; + this.patterns = new ArrayList<>(); + for (String regex : regexes) { + this.patterns.add(Pattern.compile(regex)); + } + this.priority = priority; + } + + boolean matches(String trackingNumber) { + for (Pattern pattern : patterns) { + if (pattern.matcher(trackingNumber).matches()) { + return true; + } + } + return false; + } + } + + // 规则库(按优先级排序) + private static final List RULES = new ArrayList<>(); + + static { + // 初始化规则库(规则越具体,优先级越高) + initializeRules(); + } + + private static void initializeRules() { + // 高优先级规则:精确匹配的特定规则 + + // 1. 中通快递 (ZTO) + RULES.add(new ExpressRule("zhongtong", "中通快递", new String[]{ + "^78\\d{12}$", // 14位,78开头(你的例子) + "^7[3-8]\\d{11}$", // 13位,73-78开头 + "^7[3-8]\\d{9}$", // 11位,73-78开头 + "^ZTO\\d{10,}$", // ZTO开头 + "^ZT\\d{10,}$", // ZT开头 + "^75\\d{8}$", // 10位,75开头 + "^73\\d{10}$", // 12位,73开头 + "^77\\d{10}$", // 12位,77开头 + "^\\d{10}$", // 10位纯数字(中通常见) + "^\\d{12}$" // 12位纯数字(中通常见) + }, 1)); + + // 2. 顺丰速运 (SF) + RULES.add(new ExpressRule("shunfeng", "顺丰速运", new String[]{ + "^SF\\d{13}$", // SF+13位数字 + "^SF\\d{10}$", // SF+10位数字 + "^1[0-2]\\d{10}$", // 10、11、12开头+10位数字 + "^00\\d{10}$", // 00开头+10位数字 + "^118\\d{9}$", // 118开头+9位数字 + "^SF\\w{2}\\d{8}$", // SF+2字母+8数字 + "^SF\\d{12}$" // SF+12位数字 + }, 1)); + + // 3. 圆通速递 (YTO) + RULES.add(new ExpressRule("yuantong", "圆通速递", new String[]{ + "^YT\\d{10,}$", // YT开头 + "^YTO\\d{10,}$", // YTO开头 + "^8[0-6]\\d{8}$", // 80-86开头+8位数字(10位) + "^8[0-6]\\d{10}$", // 80-86开头+10位数字(12位) + "^1[0-9]\\d{11}$", // 10-19开头+11位数字(13位) + "^[DV]\\d{10}$", // D或V开头+10位数字 + "^Y\\d{10}$" // Y开头+10位数字 + }, 2)); + + // 4. 申通快递 (STO) + RULES.add(new ExpressRule("shentong", "申通快递", new String[]{ + "^ST\\d{10,}$", // ST开头 + "^STO\\d{10,}$", // STO开头 + "^SHEX\\d{8,}$", // SHEX开头 + "^7[7-8]\\d{10}$", // 77或78开头+10位数字(12位) + "^33\\d{10}$", // 33开头+10位数字 + "^55\\d{10}$", // 55开头+10位数字 + "^66\\d{10}$", // 66开头+10位数字 + "^88\\d{10}$" // 88开头+10位数字 + }, 2)); + + // 5. 韵达快递 (YD) + RULES.add(new ExpressRule("yunda", "韵达快递", new String[]{ + "^YD\\d{10,}$", // YD开头 + "^YUNDA\\d{8,}$", // YUNDA开头 + "^39\\d{11}$", // 39开头+11位数字(13位) + "^19\\d{11}$", // 19开头+11位数字 + "^15\\d{11}$", // 15开头+11位数字 + "^55\\d{11}$", // 55开头+11位数字 + "^17\\d{11}$", // 17开头+11位数字 + "^1[2-9]\\d{11}$", // 12-19开头+11位数字 + "^\\d{13}$" // 13位纯数字 + }, 2)); + + // 6. 京东物流 (JD) + RULES.add(new ExpressRule("jd", "京东物流", new String[]{ + "^JD\\d{10,}$", // JD开头 + "^JDX\\d{9,}$", // JDX开头 + "^JDL\\d{9,}$", // JDL开头 + "^JDV\\d{9,}$", // JDV开头 + "^VA\\d{9}$", // VA开头+9位数字 + "^JD\\d{11}$", // JD+11位数字 + "^J\\d{12}$" // J+12位数字 + }, 3)); + + // 7. 极兔速递 (JT) + RULES.add(new ExpressRule("jtexpress", "极兔速递", new String[]{ + "^JT\\d{10,}$", // JT开头 + "^JTSD\\d{8,}$", // JTSD开头 + "^JITU\\d{8,}$", // JITU开头 + "^JT\\d{12}$", // JT+12位数字 + "^J\\d{13}$" // J+13位数字 + }, 3)); + + // 8. 邮政EMS (EMS) + RULES.add(new ExpressRule("ems", "邮政EMS", new String[]{ + "^1\\d{12}$", // 1开头+12位数字(13位) + "^E\\d{13}$", // E开头+13位数字 + "^9[0-9]\\d{10}$", // 90-99开头+10位数字(12位) + "^EMS\\d{9,}$", // EMS开头 + "^9\\d{11}$", // 9开头+11位数字(12位) + "^CN\\d{13}$" // CN开头+13位数字 + }, 3)); + + // 9. 百世快递 (BS) + RULES.add(new ExpressRule("baishiwuliu", "百世快递", new String[]{ + "^BS\\d{9,}$", // BS开头 + "^HT\\d{9,}$", // HT开头 + "^HTKY\\d{8,}$", // HTKY开头 + "^12\\d{10}$", // 12开头+10位数字 + "^A\\d{10}$", // A开头+10位数字 + "^\\d{12}$" // 12位纯数字(默认) + }, 4)); + + // 10. 德邦快递 (DBL) + RULES.add(new ExpressRule("debangwuliu", "德邦快递", new String[]{ + "^DB\\d{9,}$", // DB开头 + "^DBL\\d{8,}$", // DBL开头 + "^DEPPON\\d{8,}$", // DEPPON开头 + "^[0-9]{8}$", // 8位纯数字 + "^[0-9]{10}$", // 10位纯数字 + "^[0-9]{12}$", // 12位纯数字 + "^5\\d{9}$" // 5开头+9位数字 + }, 4)); + + // 11. 其他快递公司(优先级较低) + RULES.add(new ExpressRule("zhaijisong", "宅急送", new String[]{ + "^ZJS\\d{9,}$" // ZJS开头 + }, 5)); + + RULES.add(new ExpressRule("guoeryue", "天天快递", new String[]{ + "^TT\\d{9,}$", // TT开头 + "^6\\d{9}$" // 6开头+9位数字 + }, 5)); + + RULES.add(new ExpressRule("qf", "全峰快递", new String[]{ + "^QF\\d{9,}$", // QF开头 + "^QFKD\\d{8,}$" // QFKD开头 + }, 5)); + + RULES.add(new ExpressRule("uc", "优速快递", new String[]{ + "^UC\\d{9,}$" // UC开头 + }, 5)); + + RULES.add(new ExpressRule("yz", "邮政包裹", new String[]{ + "^9\\d{11}$", // 9开头+11位数字 + "^YZ\\d{10,}$" // YZ开头 + }, 5)); + } + + /** + * 识别快递公司(主方法) + * @param trackingNumber 快递单号 + * @return ExpressInfo对象,包含公司信息和置信度 + */ + public static ExpressInfo detect(String trackingNumber) { + if (trackingNumber == null || trackingNumber.trim().isEmpty()) { + return new ExpressInfo("unknown", "未知快递"); + } + + String cleanNumber = trackingNumber.trim().toUpperCase(); + + // 1. 首先尝试精确匹配(高优先级规则) + for (ExpressRule rule : RULES) { + if (rule.matches(cleanNumber)) { + return new ExpressInfo(rule.code, rule.name); + } + } + + // 2. 如果没有精确匹配,尝试模糊匹配 + ExpressInfo fuzzyMatch = fuzzyDetect(cleanNumber); + if (fuzzyMatch != null) { + return fuzzyMatch; + } + + // 3. 最终无法识别 + return new ExpressInfo("unknown", "未知快递"); + } + + /** + * 模糊匹配(当精确匹配失败时使用) + */ + private static ExpressInfo fuzzyDetect(String trackingNumber) { + // 纯数字单号的模糊识别 + if (trackingNumber.matches("^\\d+$")) { + return detectNumericOnly(trackingNumber); + } + + // 包含字母的模糊识别 + if (trackingNumber.matches("^[A-Z]+\\d+$")) { + return detectWithLetters(trackingNumber); + } + + return null; + } + + /** + * 纯数字单号识别 + */ + private static ExpressInfo detectNumericOnly(String number) { + int length = number.length(); + String prefix2 = length >= 2 ? number.substring(0, 2) : ""; + String prefix3 = length >= 3 ? number.substring(0, 3) : ""; + + // 根据长度和前缀猜测 + Map commonPatterns = new HashMap<>(); + + // 10位单号 + if (length == 10) { + commonPatterns.put("75", "中通快递"); + commonPatterns.put("73", "中通快递"); + commonPatterns.put("80", "圆通速递"); + commonPatterns.put("82", "圆通速递"); + } + + // 12位单号 + if (length == 12) { + commonPatterns.put("77", "申通快递"); + commonPatterns.put("88", "申通快递"); + commonPatterns.put("33", "申通快递"); + commonPatterns.put("12", "百世快递"); + commonPatterns.put("39", "韵达快递"); + commonPatterns.put("19", "韵达快递"); + } + + // 13位单号 + if (length == 13) { + commonPatterns.put("1", "邮政EMS"); + commonPatterns.put("39", "韵达快递"); + commonPatterns.put("19", "韵达快递"); + commonPatterns.put("10", "顺丰速运"); + } + + // 14位单号(你的例子) + if (length == 14) { + if (prefix2.equals("78")) { + return new ExpressInfo("zhongtong", "中通快递"); + } + } + + // 根据前缀匹配 + for (Map.Entry entry : commonPatterns.entrySet()) { + if (number.startsWith(entry.getKey())) { + String code = getCodeByName(entry.getValue()); + return new ExpressInfo(code, entry.getValue()); + } + } + + // 根据长度猜测 + switch (length) { + case 10: return new ExpressInfo("zhongtong", "中通快递"); + case 12: return new ExpressInfo("baishiwuliu", "百世快递"); + case 13: return new ExpressInfo("ems", "邮政EMS"); + case 14: return new ExpressInfo("zhongtong", "中通快递"); + default: return null; + } + } + + /** + * 包含字母的单号识别 + */ + private static ExpressInfo detectWithLetters(String trackingNumber) { + // 提取字母前缀 + String prefix = trackingNumber.replaceAll("^(\\D+).*$", "$1"); + + Map prefixMap = new HashMap<>(); + prefixMap.put("SF", "顺丰速运"); + prefixMap.put("JD", "京东物流"); + prefixMap.put("YT", "圆通速递"); + prefixMap.put("YTO", "圆通速递"); + prefixMap.put("ST", "申通快递"); + prefixMap.put("STO", "申通快递"); + prefixMap.put("ZT", "中通快递"); + prefixMap.put("ZTO", "中通快递"); + prefixMap.put("YD", "韵达快递"); + prefixMap.put("JT", "极兔速递"); + prefixMap.put("EMS", "邮政EMS"); + prefixMap.put("BS", "百世快递"); + prefixMap.put("DB", "德邦快递"); + prefixMap.put("ZJS", "宅急送"); + prefixMap.put("TT", "天天快递"); + + for (Map.Entry entry : prefixMap.entrySet()) { + if (prefix.startsWith(entry.getKey())) { + String code = getCodeByName(entry.getValue()); + return new ExpressInfo(code, entry.getValue()); + } + } + + return null; + } + + /** + * 根据公司名称获取编码 + */ + private static String getCodeByName(String name) { + Map nameToCode = new HashMap<>(); + nameToCode.put("中通快递", "zhongtong"); + nameToCode.put("顺丰速运", "shunfeng"); + nameToCode.put("圆通速递", "yuantong"); + nameToCode.put("申通快递", "shentong"); + nameToCode.put("韵达快递", "yunda"); + nameToCode.put("京东物流", "jd"); + nameToCode.put("极兔速递", "jtexpress"); + nameToCode.put("邮政EMS", "ems"); + nameToCode.put("百世快递", "baishiwuliu"); + nameToCode.put("德邦快递", "debangwuliu"); + nameToCode.put("宅急送", "zhaijisong"); + nameToCode.put("天天快递", "guoeryue"); + nameToCode.put("全峰快递", "qf"); + nameToCode.put("优速快递", "uc"); + nameToCode.put("邮政包裹", "yz"); + + return nameToCode.getOrDefault(name, "unknown"); + } + + /** + * 获取所有支持的快递公司 + */ + public static List getSupportedCompanies() { + Set companies = new LinkedHashSet<>(); + for (ExpressRule rule : RULES) { + companies.add(rule.name); + } + return new ArrayList<>(companies); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/FileUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/FileUtil.java new file mode 100644 index 0000000..bc349af --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/FileUtil.java @@ -0,0 +1,233 @@ +package org.dromara.zhishu.util; + +import com.pdd.pop.sdk.common.util.JsonUtil; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.Base64; +import java.util.Date; +import java.util.List; +import java.util.Map; + + +public class FileUtil { + + /** + * 判断指定路径下的指定文件是否存在 + * + * @param filePath 文件的完整路径(包括文件名和扩展名) + * @return 存在返回 true,不存在返回 false + */ + public static boolean isFileExists(String filePath) { + if (filePath == null || filePath.trim().isEmpty()) { + return false; + } + + File file = new File(filePath); + return file.exists() && file.isFile(); + } + + public static boolean fileDelete(String filePath) { + if (filePath == null || filePath.trim().isEmpty()) { + return false; + } + + File file = new File(filePath); + if (file.exists() && file.isFile()) { + if (file.delete()) { + System.out.println("原文件删除成功: " + filePath); + return true; + } else { + System.err.println("尝试删除原文件时发生错误: " + filePath); + return false; + } + } else { + System.err.println("未找到原文件或不是文件: " + filePath); + return false; + } + } + + /** + * 校验文件大小是否超过指定值 + * @param filePath 文件路径 + * @return 如果文件大小超过最大值返回 true,否则返回 false + */ + public static boolean isFileSizeExceeds(String filePath) { + long maxSize = 1024 * 1024 * 2; // 2MB + File file = new File(filePath); + if (file.exists() && file.isFile()) { + return file.length() > maxSize; + } + return false; + } + + /** + * 根据路径获取TXT文件内容,如果文件不存在则创建。 + * + * @param filePath 文件的路径 + * @param contentToAppend 要追加的内容 + * @return 文件的完整内容 + */ + public static String processTxtFile(String filePath, String contentToAppend) { + try { + File file = new File(filePath); + + // 确保父目录存在 + if (!file.getParentFile().exists()) { + if (!file.getParentFile().mkdirs()) { + throw new IOException("无法创建目标目录: " + file.getParent()); + } + } + + // 如果文件不存在,则创建 + 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 String convertToBase64(MultipartFile file) { + try { + InputStream inputStream = new ByteArrayInputStream(file.getBytes()); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + byte[] buffer = new byte[1024]; + int bytesRead; + + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + byte[] byteArray = outputStream.toByteArray(); + return Base64.getEncoder().encodeToString(byteArray); + } catch (Exception e) { + // 处理异常 + e.printStackTrace(); + return null; + } + } + + + /** + * 通用参数日志记录方法 + * @param methodName 方法名称 + * @param parameters 可变参数,可以传入任意数量的参数 + */ + public static void logParameters(String methodName, Object... parameters) { + FileWriter fileWriter = null; + BufferedWriter bufferedWriter = null; + + try { + // 获取当前项目路径 + String projectPath = System.getProperty("user.dir"); + String logDirPath = projectPath + File.separator + methodName; + File logDir = new File(logDirPath); + + // 创建目录(如果不存在) + if (!logDir.exists()) { + logDir.mkdirs(); + } + + // 查找可用的日志文件(不超过50MB) + File logFile = findAvailableLogFile(logDir); + + // 创建文件写入器(追加模式) + fileWriter = new FileWriter(logFile, true); + bufferedWriter = new BufferedWriter(fileWriter); + + // 构建日志内容 + StringBuilder logContent = new StringBuilder(); + logContent.append("=== Method Parameter Log ===\n"); + logContent.append("Time: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())).append("\n"); + logContent.append("Method: ").append(methodName).append("\n"); + + // 记录所有参数 + logContent.append("Parameters:\n"); + if (parameters != null && parameters.length > 0) { + for (int i = 0; i < parameters.length; i++) { + Object param = parameters[i]; + String paramJson = JsonUtil.transferToJson(param); + logContent.append(" Parameter ").append(i + 1).append(": ").append(paramJson).append("\n"); + } + } else { + logContent.append(" No parameters\n"); + } + + logContent.append("=============================\n\n"); + + // 写入日志 + bufferedWriter.write(logContent.toString()); + bufferedWriter.flush(); + + } catch (Exception e) { + // 日志记录失败不应该影响主流程,只打印错误信息 + e.printStackTrace(); + } finally { + // 关闭资源 + try { + if (bufferedWriter != null) { + bufferedWriter.close(); + } + if (fileWriter != null) { + fileWriter.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 查找可用的日志文件(不超过50MB) + * @param logDir 日志目录 + * @return 可用的日志文件 + */ + private static File findAvailableLogFile(File logDir) { + // 基础日志文件名 + String baseFileName = "stock_sync_log"; + String fileExtension = ".txt"; + + // 首先检查当前日期的最新文件 + String currentDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); + String todayFileName = baseFileName + "_" + currentDate + fileExtension; + File todayFile = new File(logDir, todayFileName); + + // 如果文件不存在,直接返回新文件 + if (!todayFile.exists()) { + return todayFile; + } + + // 如果文件存在且小于50MB,则使用该文件 + if (todayFile.length() < 50 * 1024 * 1024) { // 50MB in bytes + return todayFile; + } + + // 如果今天的文件已满,创建带序号的新文件 + int fileIndex = 1; + File newFile; + do { + String newFileName = baseFileName + "_" + currentDate + "_" + fileIndex + fileExtension; + newFile = new File(logDir, newFileName); + fileIndex++; + } while (newFile.exists() && newFile.length() >= 50 * 1024 * 1024); + + return newFile; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ImageUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ImageUtils.java new file mode 100644 index 0000000..31d2e71 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ImageUtils.java @@ -0,0 +1,172 @@ +package org.dromara.zhishu.util; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ImageUtils { + + private static final String CACHE_DIR = System.getProperty("java.io.tmpdir"); // 获取系统缓存目录 + private static final String IMAGE_PATH = CACHE_DIR + File.separator; // 图片完整路径 + + /** + * 生成图片并保存到缓存文件夹 + * + * @param text 要显示的字符串 + * @param width 图片宽度 + * @param height 图片高度 + * @param fileName 文件名称 例如 123.jpg + */ + public static String generateImage(String text, int width, int height,String fileName) { + // 创建一个白底的BufferedImage + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, width, height); + + // 设置字体和颜色 + Font font = new Font("Alibaba PuHuiTi", Font.BOLD, 40); + g2d.setFont(font); + g2d.setColor(Color.BLACK); + + // 计算字符串的宽度和高度 + FontMetrics fm = g2d.getFontMetrics(); + int textWidth = fm.stringWidth(text); + int textHeight = fm.getHeight(); + + // 计算字符串的绘制位置 + int x = (width - textWidth) / 2; + int y = (height - textHeight) / 2 + fm.getAscent(); + + // 绘制字符串 + g2d.drawString(text, x, y); + + // 释放资源 + g2d.dispose(); + + // 保存图片到缓存文件夹 + try { + File outputFile = new File(IMAGE_PATH+fileName); + ImageIO.write(image, "jpg", outputFile); + return IMAGE_PATH+fileName; + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + + 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 (Exception e) { + return false; + } + } + + /** + * 判断文件是否存在 + * + * @param absolutePath 文件的绝对路径 + * @return 如果文件存在返回 true,否则返回 false + */ + public static boolean isFileExists(String absolutePath) { + Path path = Paths.get(absolutePath); + return Files.exists(path); + } + + public static boolean isImageExistsWithGet(String imageUrl) { + try { + URL url = new URL(imageUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + connection.setRequestProperty("User-Agent", "Java Client"); + + int responseCode = connection.getResponseCode(); + return responseCode == HttpURLConnection.HTTP_OK; + } catch (Exception e) { + return false; + } + } + + /** + * 生成图片,左上开头 + * @param text + * @param width + * @param height + * @param fileName + * @return + */ + public static String generateMultiLineImage(String text, int width,int height, String fileName) { + String[] lines = text.split("\n"); + + // 设置字体样式 + Font font = new Font("Alibaba PuHuiTi", Font.BOLD, 20); + + // 创建临时图像用于计算字体大小 + BufferedImage tempImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2dTemp = tempImage.createGraphics(); + g2dTemp.setFont(font); + FontMetrics fm = g2dTemp.getFontMetrics(); + int lineHeight = fm.getHeight(); + int ascent = fm.getAscent(); + g2dTemp.dispose(); + + // 创建实际图像 + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, width, height); + g2d.setFont(font); + g2d.setColor(Color.BLACK); + + // 绘制文本 + int y = 10 + ascent; + int lineCount = 0; + + for (String line : lines) { + if (y + lineHeight > height) { + // 如果超出高度,则画 ... + if (lineCount == 0) { + // 整段都放不下,尝试截断 + String truncated = ContentUtils.truncateLineToFit(line, width, fm, "..."); + g2d.drawString(truncated, 10, y); + } else { + g2d.drawString("...", 10, y); + } + break; + } + + g2d.drawString(line, 10, y); + y += lineHeight + 5; // 每行间距 5px + lineCount++; + } + + g2d.dispose(); + + // 保存图片到缓存文件夹 + try { + File outputFile = new File(IMAGE_PATH+fileName); + ImageIO.write(image, "jpg", outputFile); + return IMAGE_PATH+fileName; + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/JsonExporterUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/JsonExporterUtils.java new file mode 100644 index 0000000..8fb2590 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/JsonExporterUtils.java @@ -0,0 +1,49 @@ +package org.dromara.zhishu.util; + +import cn.hutool.json.JSONUtil; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +/** + * 导出json文件工具类 + */ +public class JsonExporterUtils { + + /** + * 导出json文件方法 + * + * @param data 导出数据对象 + * @param filename 导出文件名称 + * @param + * @return + * @throws IOException + */ + public static ResponseEntity exportJsonAsFile(List data, String filename) throws IOException { + if (data == null || data.isEmpty()) { + throw new IllegalArgumentException("Data cannot be null or empty."); + } + + // 将列表转换为JSON字符串 + String jsonStr = JSONUtil.toJsonStr(data); + + // 将JSON字符串写入ByteArrayOutputStream + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(jsonStr.getBytes()); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + + // 设置响应头,让浏览器知道这是一个文件下载 + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename); + headers.setContentType(MediaType.APPLICATION_JSON); + + return new ResponseEntity<>(new InputStreamResource(in), headers, HttpStatus.OK); + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/KongfzApiUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/KongfzApiUtils.java new file mode 100644 index 0000000..b89b01a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/KongfzApiUtils.java @@ -0,0 +1,85 @@ +package org.dromara.zhishu.util; + +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.*; + +@Component +@Log4j2 +@RequiredArgsConstructor +public class KongfzApiUtils { + 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; + + + /** + * 生成当前时间字符串 + */ + public static String getCurrentDateTime() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + sdf.setTimeZone(TimeZone.getTimeZone("GMT+8")); + return sdf.format(new Date()); + } + + /** + * 生成签名 + */ + + public static String generateSign(Map params, String secretKey) { + StringBuilder paramStr = new StringBuilder(); + for (Map.Entry entry : params.entrySet()) { + paramStr.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + paramStr.append("secret=").append(secretKey); + MessageDigest md = null; + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + byte[] digest = md.digest(paramStr.toString().getBytes()); + StringBuilder sb = new StringBuilder(); + for (byte b : digest) { + sb.append(String.format("%02x", b & 0xff)); + } + return sb.toString(); + } + + public static Map buildKongfzParams(String appId, String secretKey) throws NoSuchAlgorithmException { + Map params = new HashMap<>(); + params.put("method", "kongfz.shop.simple.get"); + params.put("appId", appId); + // 若需要授权,设置 accessToken + // params.put("accessToken", "YOUR_ACCESS_TOKEN"); + params.put("datetime", getCurrentDateTime()); + params.put("format", "json"); + params.put("v", "1.0"); + params.put("signMethod", "md5"); + String sign = generateSign(params, secretKey); + params.put("sign", sign); + params.put("simplify", "0"); + return params; +} + + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ListUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ListUtils.java new file mode 100644 index 0000000..2671c46 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ListUtils.java @@ -0,0 +1,34 @@ +package org.dromara.zhishu.util; + +import java.util.*; +import java.util.stream.Collectors; + +public class ListUtils { + + /** + * 根据两个字段组合去重 + * + * @param list 数据列表 + * @param key1 第一个字段名 + * @param key2 第二个字段名 + * @return 去重后的列表 + */ + public static List> removeDuplicatesByTwoKeys( + List> list, String key1, String key2) { + + Set> seen = new HashSet<>(); + List> result = new ArrayList<>(); + + for (Map map : list) { + if (map.containsKey(key1) && map.containsKey(key2)) { + List compositeKey = Arrays.asList(map.get(key1), map.get(key2)); + if (!seen.contains(compositeKey)) { + seen.add(compositeKey); + result.add(map); + } + } + } + + return result; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/LoginUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/LoginUtils.java new file mode 100644 index 0000000..7f896d6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/LoginUtils.java @@ -0,0 +1,31 @@ +// 创建新文件: org.dromara.zhishu.util.LoginUtils.java +package org.dromara.zhishu.util; + +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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; + +import org.dromara.zhishu.domain.PddLoginVo; +import org.dromara.zhishu.domain.PddLoginVo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static cn.dev33.satoken.SaManager.log; + +@Component +@RequiredArgsConstructor +public class LoginUtils { + +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/NewTaskUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/NewTaskUtils.java new file mode 100644 index 0000000..a5856aa --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/NewTaskUtils.java @@ -0,0 +1,22 @@ +package org.dromara.zhishu.util; + +import com.pdd.pop.sdk.common.util.JsonUtil; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NewTaskUtils { + + public static String newTaskPost(String taskId,String shopId,List bodyList){ + Map requestShopDataMap = new HashMap(); + requestShopDataMap.put("shopId",shopId); + requestShopDataMap.put("data", JsonUtil.transferToJson(bodyList)); + String shopDataListStr = InterfaceUtils.postForm("http://119.45.237.193:14008","/shopGoods/getShopGoods",requestShopDataMap); + // String shopDataListStr = InterfaceUtils.postForm("http://localhost:18099","/shopGoods/getShopGoods",requestShopDataMap); + List shopDataList = JsonUtil.transferToObj(shopDataListStr,List.class); + String response = InterfaceUtils.postTaskBodyWithSign(UrlUtil.getNewTaskUrl(), "/task/setTaskBody", taskId.toString(), shopDataList); + System.out.println("新发布任务发布"+bodyList.size()+"条"+";查询后数据:"+shopDataList.size()+"条"); + return response; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/OcrUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/OcrUtil.java new file mode 100644 index 0000000..efec0d4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/OcrUtil.java @@ -0,0 +1,42 @@ +package org.dromara.zhishu.util; + +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import com.tencentcloudapi.common.AbstractModel; + +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.ocr.v20181119.OcrClient; + +/** + * ocr工具类 + */ +@Component +@Log4j2 +@RequiredArgsConstructor +public class OcrUtil { + + public OcrClient upload(MultipartFile file){ +// try{ + // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 + // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性 + // 以下代码示例仅供参考,建议采用更安全的方式来使用密钥 + // 请参见:https://cloud.tencent.com/document/product/1278/85305 + // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 + Credential cred = new Credential("AKID4ECwSkodEbjdIiusAJFE3e2DB3h7IIFy", "av2zkGaoobBYheNs8AyXu3yd7PTccPnz"); + // 使用临时密钥示例 + // Credential cred = new Credential("SecretId", "SecretKey", "Token"); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("ocr.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + OcrClient client = new OcrClient(cred, "", clientProfile); + return client; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddResultUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddResultUtil.java new file mode 100644 index 0000000..3ede6fe --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PddResultUtil.java @@ -0,0 +1,16 @@ +package org.dromara.zhishu.util; + +import jakarta.servlet.http.HttpServletRequest; + +import java.util.HashMap; +import java.util.Map; + +public class PddResultUtil { + + public static Map getPddHeaderMap(HttpServletRequest request){ + Map headers = new HashMap<>(); + headers.put("X-PDD-Pati", request.getHeader("X-PDD-Pati")); // 从请求头获取 + headers.put("X-PDD-PageCode", request.getHeader("X-PDD-PageCode")); // 自定义 Head + return headers; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PricingUrlUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PricingUrlUtil.java new file mode 100644 index 0000000..e254839 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/PricingUrlUtil.java @@ -0,0 +1,181 @@ +package org.dromara.zhishu.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.core.type.TypeReference; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.List; + +@Component +@Log4j2 +@RequiredArgsConstructor +public class PricingUrlUtil { + + private String publicKeyStr= "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqmdgZjjpySFAd+3Go33tshTOhRcSl6Sl4x8bR5vrEzsvFqQQW+VXLco0E1jy9dIR4NguRIGWOowi/4EU5PEM3ZVrXQCxCnyyqIuuDtY9QNTh5DTn60aDOLEL2X7+mvICgFg+VAKPik+8fBSUfzcGiLqFlx+VhUAkq9hCyd/wtYInuAxPSoCr8F2cmI4/V6sAhVUkHUZhJvWlyDLUpYKOGgYM4rXjCXXKrPO0FNf1iY70AWACSJmXUwBVuIRYWfTRVOvzEPWkp/tuqir/XcvMfKKVU5/eCr8abNVIG99HTF1iKvQPdQUldAyk5z9YPV5IwAbrjlEACmJ5JvuT3bypewIDAQAB"; + private String privateKeyStr= "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCqZ2BmOOnJIUB37cajfe2yFM6FFxKXpKXjHxtHm+sTOy8WpBBb5VctyjQTWPL10hHg2C5EgZY6jCL/gRTk8QzdlWtdALEKfLKoi64O1j1A1OHkNOfrRoM4sQvZfv6a8gKAWD5UAo+KT7x8FJR/NwaIuoWXH5WFQCSr2ELJ3/C1gie4DE9KgKvwXZyYjj9XqwCFVSQdRmEm9aXIMtSlgo4aBgziteMJdcqs87QU1/WJjvQBYAJImZdTAFW4hFhZ9NFU6/MQ9aSn+26qKv9dy8x8opVTn94Kvxps1Ugb30dMXWIq9A91BSV0DKTnP1g9XkjABuuOUQAKYnkm+5PdvKl7AgMBAAECggEAY0xmYmsb4PadiMVokXEaiEGTrv6o+PEbMeS4ktwK+mPsprboSYS1bpt8CSI2QoUtoeaX35fcITX0VwuzT04gfydJLyLuB/xuZ8Utoru5agQjtkYWN4YZhXm2PAHDACuyxXOmrnHnj2OzpGKhvhgkmJyIqG3hRYsBU5psIRN8Q2gnCarhiB948YDu6EfvFJPv0ET9T+mzQWLmMVz+lorepfcXV1Wwvr0awRPfyS2s7te9AW4GYEzKN9ijZx05XnYOSgh/hD82iqh+poPXiqamhZGcQBQ8CveVbyNatTpbZYca8gXByOIipSEqg3UVQ2rnd/hYAh4VKSagyKXtFt7REQKBgQDgjGtbit3JK8jJuQTWBqgNHWphc1/4tAidjWeEF1NBi0NZuSZiVLoh9J794lO67psAZheZV70gXD9pHF7tiSESTIsHZiOtU9rrEVACc6EHJIeBrmB4oNWvzzix5S0S6RZxLYm5oiEoNjXSfqcFqCHGiT3lnxUhSp3JywlcIx0QZQKBgQDCRYEMt+u0Hp8JbhxhHx5Z87dZRJe0AGRQXnz3blxq+MTIVB6oj6NKBxPN6BmNLGI/xnxO8XTog5JCv9SZRZpY6eZmdCt2sVK2k2i1kxpd3sLjlbFTNnyC9RJFeZMjIlvW03KmDu0VBDf4CW/zSP3aej+vgxvOZesYcgI9isoEXwKBgEmrJ+mflIXUfIpZzhFdm7K5zNXt4TWZ8x2lb6mxcVoWk2ETUll+TJapR6Qppai1cVrfI6zmUSEVwqP8b9RkYdo8DHy/8MKDuVXXlzVGtDTAskhEalgJBDIqvQH4GyKSIA+/jei+HTyxFFVbwfYkI/ibvBfiai9C6KN0njyBNJ7VAoGAVgDZCZ1efmXT+CPD8ocJM78+GwnPswM9ZYr+/bbguQaabyk2TV8RZdNORCiNLz9H233uSDCClfCxTlWIM7ZphxU9R3wERc5olKUbhM6zrHzSgFgjoXgMlRkTVqhkp/gs+iSvq64N7PDqKidbZTOaFh9qlDORmsTp1++Y6E/J8TcCgYEA0cszTR9OuvrQDpiX5PW+HB66GIxuEFBCla0HphtV16i/tzXnIaZ6q2hf1e9qejO3lOIzi3e1PVHOuMIemzl17batonERhBIjDYEtGraFyaHSgkp+zRdjPGj8A0dq7iwdv0M4ravQcF9dVvfEucVhN3XSJXSqdJRSoZzOvRZH4VY="; + private static final String AES_ALGORITHM = "AES/GCM/NoPadding"; + private static final String RSA_ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; + private static final int GCM_IV_LENGTH = 12; + private static final int GCM_TAG_LENGTH = 16; + + + + + + /** + * 加密List集合 + * @param plaintextList 原始文本列表 + * @return Base64编码的加密数据 + */ + public String encryptList(List plaintextList) throws Exception { + // 将List转换为JSON字符串 + ObjectMapper mapper = new ObjectMapper(); + String jsonString = mapper.writeValueAsString(plaintextList); + + // 使用现有的加密方法加密JSON字符串 + return encrypt(jsonString); + } + + + /** + * 解密List集合 + * @param encryptedData Base64编码的加密数据 + * @return 原始文本列表 + */ + public List decryptList(String encryptedData) throws Exception { + // 先解密得到JSON字符串 + String jsonString = decrypt(encryptedData); + + // 将JSON字符串转换回List + ObjectMapper mapper = new ObjectMapper(); + return mapper.readValue(jsonString, new TypeReference>() {}); + } + + + + /** + * 加密方法(不限长度) + * @param plaintext 原始文本 + // * @param publicKeyStr RSA公钥(Base64编码) + * @return Base64编码的加密数据 + */ + public String encrypt(String plaintext) throws Exception { + // 1. 生成随机的AES密钥 + KeyGenerator keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); // AES-256 + SecretKey aesKey = keyGen.generateKey(); + + // 2. 使用AES加密数据 + byte[] iv = new byte[GCM_IV_LENGTH]; + SecureRandom random = new SecureRandom(); + random.nextBytes(iv); + + Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM); + GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); + aesCipher.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec); + byte[] encryptedData = aesCipher.doFinal(plaintext.getBytes("UTF-8")); + + // 3. 使用RSA加密AES密钥 + PublicKey publicKey = getPublicKey(publicKeyStr); + Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM); + rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey); + byte[] encryptedAesKey = rsaCipher.doFinal(aesKey.getEncoded()); + + // 4. 组合IV + 加密的AES密钥 + 加密的数据 + ByteBuffer byteBuffer = ByteBuffer.allocate( + GCM_IV_LENGTH + encryptedAesKey.length + encryptedData.length + ); + byteBuffer.put(iv); + byteBuffer.put(encryptedAesKey); + byteBuffer.put(encryptedData); + + // 5. 返回Base64编码结果 + return Base64.getEncoder().encodeToString(byteBuffer.array()); + } + + private static PublicKey getPublicKey(String publicKeyStr) throws Exception { + byte[] encodedKey = Base64.getDecoder().decode(publicKeyStr); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); + } + // 解密方法 + public String decrypt(String encryptedData) throws Exception { + // 1. 解码Base64并分离各部分 + //将encryptedData中的空格转为+号 + String encryptedData1 = encryptedData.replace(" ", "+"); + byte[] decoded = Base64.getDecoder().decode(encryptedData1); + ByteBuffer byteBuffer = ByteBuffer.wrap(decoded); + + byte[] iv = new byte[GCM_IV_LENGTH]; + byteBuffer.get(iv); + + // RSA密钥长度决定加密后的AES密钥长度(2048位密钥加密后是256字节) + byte[] encryptedAesKey = new byte[256]; + byteBuffer.get(encryptedAesKey); + + byte[] remainingData = new byte[byteBuffer.remaining()]; + byteBuffer.get(remainingData); + + // 2. 使用RSA解密AES密钥 + byte[] encodedPrivateKey = Base64.getDecoder().decode(privateKeyStr); + PrivateKey privateKey = KeyFactory.getInstance("RSA") + .generatePrivate(new PKCS8EncodedKeySpec(encodedPrivateKey)); + + Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM); + rsaCipher.init(Cipher.DECRYPT_MODE, privateKey); + byte[] aesKeyBytes = rsaCipher.doFinal(encryptedAesKey); + SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES"); + + // 3. 使用AES解密数据 + GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv); + Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM); + aesCipher.init(Cipher.DECRYPT_MODE, aesKey, ivSpec); + + byte[] decryptedData = aesCipher.doFinal(remainingData); + return new String(decryptedData, StandardCharsets.UTF_8); + } + + + /** + * 获取加密后的URL + * + * @param url 原始URL + * @return 加密后的URL + */ + public String getPricingUrl(String url) { + try { + String encryptedUrl = encrypt(url); + return encryptedUrl; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 获取加密后的URL + * + * @param url 原始URL + * @return 加密后的URL + */ + public String getPricingUrlList(List url) { + try { + String encryptedUrl = encryptList(url); + return encryptedUrl; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/RunningLogUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/RunningLogUtils.java new file mode 100644 index 0000000..33055b4 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/RunningLogUtils.java @@ -0,0 +1,134 @@ +package org.dromara.zhishu.util; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.poi.ss.formula.functions.T; +import org.aspectj.lang.ProceedingJoinPoint; +import org.dromara.common.core.utils.DateUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.zhishu.domain.bo.RunningLogFileBo; +import org.dromara.zhishu.domain.vo.ProductForm; +import org.dromara.zhishu.service.IRunningLogFileService; + +import java.math.BigDecimal; +import java.util.Map; + +public class RunningLogUtils { + + private static IRunningLogFileService runningLogFileService; + + private RunningLogUtils(){} + + public static void init(IRunningLogFileService service) { + runningLogFileService = service; + } + + + public static Object runningLog(ProceedingJoinPoint joinPoint, Map data , String content,String fileType){ + //日志记录 用户id + String userId = data.get("userId").toString(); + String methodName = joinPoint.getSignature().getName(); + // 1.根据文件类型获取文件最大顺序 + String maxOrder = runningLogFileService.selectMaxFileOrderByFileTypeAndCreateBy(fileType,userId); + content = "【"+fileType + "】" + content; + Object result = ""; + try{ + /** + * 调用日志方法 + */ + maxOrder = RunningLogUtils.editRunning(fileType,"【日志开始,方法名称:"+methodName+"】"+content,maxOrder,userId); + maxOrder = RunningLogUtils.editRunning(fileType,"【执行参数】"+ JsonUtils.toJsonString(data),maxOrder,userId); + // 执行方法 + result = joinPoint.proceed(); + maxOrder = RunningLogUtils.editRunning(fileType,"【返回参数】"+JsonUtils.toJsonString(result),maxOrder,userId); + +// //获取成功日志文件 +// //获取当前日期 +// String successNum = EasyExcelUtil.readFileContentString(UrlUtil.getUrl()+"log/"+DateUtils.dataYMD()+"_successNumLog.txt"); +// successNum = successNum.replaceAll("\r\n", ""); +// if(StringUtils.isEmpty(successNum)){ +// successNum = "1"; +// }else{ +// successNum = new BigDecimal(successNum).add(new BigDecimal(1)).toString(); +// } +// //记录成功数据日志 +// EasyExcelUtil.writeJsonToFile("log/"+DateUtils.dataYMD()+"_successNumLog.txt",successNum); + + }catch (Throwable e){ + String msgAll = ExceptionUtils.getStackTrace(e); + maxOrder = RunningLogUtils.editRunning(fileType,"【系统异常】【异常方法】"+methodName,maxOrder,userId); + maxOrder = RunningLogUtils.editRunning(fileType,"【系统异常】【异常内容】"+msgAll,maxOrder,userId); +// //获取失败日志文件 +// String errorNum = EasyExcelUtil.readFileContentString(UrlUtil.getUrl()+"log/"+DateUtils.dataYMD()+"_errorNumLog.txt"); +// errorNum = errorNum.replaceAll("\r\n", ""); +// if(StringUtils.isEmpty(errorNum)){ +// errorNum = "1"; +// }else{ +// errorNum = new BigDecimal(errorNum).add(new BigDecimal(1)).toString(); +// } +// //记录失败日志 +// EasyExcelUtil.writeJsonToFile("log/"+DateUtils.dataYMD()+"_errorNumLog.txt",errorNum); + } finally { + maxOrder = RunningLogUtils.editRunning(fileType,"【日志结束,方法名称:"+methodName+"】"+content,maxOrder,userId); + + } + return result; + } + + /** + * 编写运行日志 + * @param fileTyle 文件类型 + * @param context 日志内容 + * @param maxOrder 文件最大顺序 + */ + public static String editRunning(String fileTyle,String context,String maxOrder,String userId){ + /** + * 处理日志 + * 时间+日志信息 + */ + context = "【"+DateUtils.getTime() + "】" + context; + /** + * 执行文件 + */ + String path = UrlUtil.getUrl() + "log/"; + String fileName = fileTyle + "_" + userId + "_"; + + if(StringUtils.isEmpty(maxOrder)){ + maxOrder = "1"; + + //生成新的文件名 + fileName += maxOrder; + //新增数据 + RunningLogFileBo bo = new RunningLogFileBo(); + bo.setFileName(fileName+".txt"); + bo.setFileType(fileTyle); + bo.setFileOrder(maxOrder); + bo.setCreateBy(Long.parseLong(userId)); + runningLogFileService.insertByBo(bo); + }else{ + // 2.根据 "文件类型+最大顺序" 生成文件名获取文件 + fileName += maxOrder; + // 3.判断文件大小,达到最大大小,则生成新的文件 + String pathMark = path + fileName + ".txt"; + + if(FileUtil.isFileSizeExceeds(pathMark)){ + //超过2M 则生成新文件 + maxOrder = new BigDecimal(maxOrder).add(new BigDecimal(1)).toString(); + //生成新的文件名 + fileName = fileTyle + "_" + userId + "_" + maxOrder; + //新增数据 + RunningLogFileBo bo = new RunningLogFileBo(); + bo.setFileName(fileName+".txt"); + bo.setFileType(fileTyle); + bo.setFileOrder(maxOrder); + bo.setCreateBy(Long.parseLong(userId)); + runningLogFileService.insertByBo(bo); + } + } + path = path+fileName+".txt"; + //处理好文件名称,写入文件 + FileUtil.processTxtFile(path,context); + + return maxOrder; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/TaskRunnable.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/TaskRunnable.java new file mode 100644 index 0000000..76c3e28 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/TaskRunnable.java @@ -0,0 +1,62 @@ +package org.dromara.zhishu.util; + + + +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.zhishu.domain.bo.TaskBo; +import org.dromara.zhishu.service.IPddService; +import org.dromara.zhishu.service.ITaskService; +import org.dromara.zhishu.service.IZhishuShopGoodsService; +import org.springframework.context.ApplicationContext; + +import java.util.Map; + +public class TaskRunnable implements Runnable { + + private final ITaskService taskService; + private ApplicationContext applicationContext; + + private final Map map; + private final TaskBo taskBo; + private final LoginUser user; + private final String type; + + + + public TaskRunnable(ITaskService taskService, Map map, TaskBo taskBo, LoginUser user,ApplicationContext applicationContext,String type) { + this.taskService = taskService; + this.map = map; + this.taskBo = taskBo; + this.user = user; + this.applicationContext = applicationContext; + this.type = type; + } + @Override + public void run() { + ITaskService taskService = applicationContext.getBean(ITaskService.class); + if(type.equals("1")){ + // 发布任务 + taskService.addGoods(map,taskBo,user.getUserId()); + }else if(type.equals("2")){ + //表格更新价格任务 + taskService.editGoodsPrice(map,taskBo,user.getUserId()); + }else if(type.equals("4")){ + //表格更新库存 + taskService.editGoodsStock(map,taskBo,user.getUserId()); + }else if(type.equals("5")){ + //修改商品上下架状态 + taskService.editGoodsIsOnSale(map,taskBo,user.getUserId()); + }else if(type.equals("6")){ + //手动同步库存任务 + taskService.stockSynchronize(map,taskBo,user.getUserId()); + }else if (type.equals("7")){ + //更新商品数据 + taskService.updateGoodsTask(map,taskBo,user.getUserId()); + } else{ + //核价任务 + taskService.addGoodsCenter(map,taskBo,user.getUserId()); + } + } +} + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ThreadPoolUtils.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ThreadPoolUtils.java new file mode 100644 index 0000000..98c916f --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/ThreadPoolUtils.java @@ -0,0 +1,74 @@ +package org.dromara.zhishu.util; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.*; + +/** + * 自定义线程创建工具类,创建线程池后不需要关闭 + * + * @author liangxn + */ +public class ThreadPoolUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(ThreadPoolUtils.class); + private static ThreadPoolExecutor threadPool = null; + private static final String POOL_NAME = "myPool"; + // 等待队列长度 + private static final int BLOCKING_QUEUE_LENGTH = 20000; + // 闲置线程存活时间 + private static final int KEEP_ALIVE_TIME = 60 * 1000; + + private ThreadPoolUtils() { + throw new IllegalStateException("utility class"); + } + + + /** + * 无返回值直接执行 + * + * @param runnable 需要运行的任务 + */ + public static void execute(Runnable runnable) { + getThreadPool().execute(runnable); + } + + /** + * 有返回值执行 + * 主线程中使用Future.get()获取返回值时,会阻塞主线程,直到任务执行完毕 + * + * @param callable 需要运行的任务 + */ + public static Future submit(Callable callable) { + return getThreadPool().submit(callable); + } + + public static synchronized ThreadPoolExecutor getThreadPool() { + if (threadPool == null) { + // 获取处理器数量 + int cpuNum = Runtime.getRuntime().availableProcessors(); + // 根据cpu数量,计算出合理的线程并发数 + int maximumPoolSize = cpuNum * 2 + 1; + // 核心线程数、最大线程数、闲置线程存活时间、时间单位、线程队列、线程工厂、当前线程数已经超过最大线程数时的异常处理策略 + threadPool = new ThreadPoolExecutor(maximumPoolSize - 1, + maximumPoolSize, + KEEP_ALIVE_TIME, + TimeUnit.MILLISECONDS, + new ArrayBlockingQueue<>(BLOCKING_QUEUE_LENGTH), + new ThreadFactoryBuilder().setNameFormat(POOL_NAME + "-%d").build(), + new ThreadPoolExecutor.AbortPolicy() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { + LOGGER.warn("线程爆炸了,当前运行线程总数:{},活动线程数:{}。等待队列已满,等待运行任务数:{}", + e.getPoolSize(), + e.getActiveCount(), + e.getQueue().size()); + } + }); + + } + + return threadPool; + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UploadUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UploadUtil.java new file mode 100644 index 0000000..dd2a34c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/UploadUtil.java @@ -0,0 +1,358 @@ +package org.dromara.zhishu.util; + +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.encrypt.utils.EncryptUtils; +import org.dromara.common.oss.core.OssClient; +import org.dromara.common.oss.entity.UploadResult; +import org.dromara.common.oss.factory.OssFactory; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.zhishu.domain.LocalMultipartFile; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.List; +import java.io.File; +import java.io.*; +import java.util.UUID; + + +@Component +public final class UploadUtil { + + /** + * 上传文件 + * @param file 文件内容 + * @param name MD5加密前的名称 + * @param isbn ISBN + * @param num 顺序号 + * @return + */ + public static String upload(MultipartFile file, + String name, + String isbn, + String num, + String warehouseId, + String shelfId, + String locationId) { + // 获取文件后缀 + String originalfileName = file.getOriginalFilename(); + // 获取文件后缀 + String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); + + String path = "userShopGoodsImages/"+warehouseId+"/"+shelfId+"/"+locationId+"/"+isbn+num+suffix; +// System.out.println("上传图片地址:" + path); + try { + AliOssUtils.setIamge(path,file.getBytes()); + } catch (Exception e) { + System.out.println("上传失败"); + e.printStackTrace(); + return "上传失败"; + } + return path; + } + + /** + * 上传文件 + * @param file + * @return + */ + public static String upload(MultipartFile file,String folderName) { + + // 获取文件后缀 + String originalfileName = file.getOriginalFilename(); + String path = "other/"+ LoginHelper.getUserId()+"/"+folderName+"/"+originalfileName; +// System.out.println("上传图片地址:" + path); + try { + AliOssUtils.setIamge(path,file.getBytes()); + + return path; + } catch (Exception e) { + System.out.println("上传失败"); + e.printStackTrace(); + return "上传失败"; + } + } + + /** + * 获取文件路径 + * @param name 名称 + * @param fileName 文件名 + * @return + */ + public static String getFiles(String name, String fileName,String folderName,String objectName){ + + String path = ""; + if(folderName.equals("bookInfoImages")){ + String result = getMd5FirstChart(name); + path = folderName+"/"+result+"/"+fileName; + }else{ + path = objectName; + } + return AliOssUtils.getImagePath(path); + } + + /** + * 获取文件路径 + * @param bookName 书名 + * @param fileName 文件名 + * @return + */ + public static String getFiles(String imgVesselUrl,String bookName, String fileName){ + + if(StringUtils.isEmpty(imgVesselUrl)){ + imgVesselUrl = "https://img.buzhiyushu.cn/zhishu1"; + + String result = getMd5FirstChart(bookName); + + return imgVesselUrl + StringUtils.SLASH + result+StringUtils.SLASH+fileName; + + }else{ + return imgVesselUrl+fileName; + } + } + + + /** + * 根据MD5加密后获取大写首字母 + * @param bookName + * @return + */ + public static String getMd5FirstChart(String bookName){ + //书名进行md5加密 + String bookNameMd5 = EncryptUtils.encryptByMd5(bookName); + //获取加密后打首字母大写 + return StringUtils.getFirstCharToUpper(bookNameMd5); + } + + /** + * 校验图片文件宽高 + * @param file + * @return + * @throws IOException + */ + public static Boolean getImageDimensions(MultipartFile file) { + // 将 MultipartFile 转换为 BufferedImage + BufferedImage image = null; + try { + image = ImageIO.read(file.getInputStream()); + } catch (IOException e) { + return true; + } + + if (image == null) { + return true; + } + // 获取图片的长宽 + if(image.getWidth() == 800 && image.getHeight() == 800){ + return false; + }else{ + return true; + } + } + + public static MultipartFile getMultipartFileFromPath(String filePath){ + // 创建 File 对象 + File file = new File(filePath); + + MultipartFile multipartFile = new LocalMultipartFile(file); + + return multipartFile; + } + + 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; + } + + } + + + /** + * 将主图和水印图片合成一张,水印图片完美覆盖主图 + * + * @param mainImageUrl 主图的 URL + * @param watermarkImageUrl 水印图片的 URL + */ + public static String mergeImages(String mainImageUrl, String watermarkImageUrl) throws IOException { + // 从 URL 读取主图 + BufferedImage mainImage = ImageIO.read(new URL(mainImageUrl)); + // 从 URL 读取水印图片 + BufferedImage watermarkImage = ImageIO.read(new URL(watermarkImageUrl)); + + // 获取主图的宽高 + int mainWidth = mainImage.getWidth(); + int mainHeight = mainImage.getHeight(); + + // 将水印图片缩放到主图的尺寸 + Image scaledWatermark = watermarkImage.getScaledInstance(mainWidth, mainHeight, Image.SCALE_SMOOTH); + + // 创建一个新的 BufferedImage,类型为 ARGB(支持透明度) + BufferedImage combined = new BufferedImage( + mainWidth, mainHeight, BufferedImage.TYPE_INT_ARGB); + + // 获取 Graphics2D 对象 + Graphics2D g2d = combined.createGraphics(); + + // 绘制主图 + g2d.drawImage(mainImage, 0, 0, null); + // 绘制缩放后的水印图片 + g2d.drawImage(scaledWatermark, 0, 0, null); + + // 释放资源 + g2d.dispose(); + + + // 创建临时文件 + Path tempFile = Files.createTempFile("combined-image-", ".png"); + + // 保存合成后的图片到临时文件 + ImageIO.write(combined, "PNG", tempFile.toFile()); + + // 返回临时文件的路径 + return tempFile.toAbsolutePath().toString(); + } + + /** + * 校验文件是否存在 + * @param imageUrl + * @return + */ + public static Boolean isImageExists(String imageUrl,String fileName) { + File file = new File(imageUrl+fileName); + if (file.exists()) { + System.out.println("文件存在: " + imageUrl+fileName); + return true; + } else { + System.out.println("文件不存在: " + imageUrl+fileName); + try { + // 将字符串路径转换为Path对象 + Path path = Paths.get(imageUrl); + // 检查目录是否存在 + if (!Files.exists(path)) { + // 如果不存在,则创建目录 + Files.createDirectories(path); + System.out.println("目录已创建: " + imageUrl); + } else { + System.out.println("目录已存在: " + imageUrl); + } + }catch (Exception e) { + System.err.println("无法创建目录: " + e.getMessage()); + } + return false; + } + } + + /** + * 校验文件是否存在 + * @param fileUrl + * @return + */ + public static boolean isFileExists(String fileUrl) { + try { + URL url = new URL(fileUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); // 改用 GET 更可靠 + connection.setInstanceFollowRedirects(true); // 自动处理重定向 + + int responseCode = connection.getResponseCode(); + return (responseCode == HttpURLConnection.HTTP_OK); + } catch (IOException e) { + return false; // 简化异常处理,直接返回 false + } + } + + /** + * 校验图片是否存在 + */ + 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; + } + } + + /** + * 根据网络路径获取图片并下载到本地系统缓存目录 + * + * @param imageUrl 图片的网络路径(URL) + * @return 下载后的本地文件路径 + * @throws IOException 如果下载过程中发生错误 + */ + public static String downloadImageToCache(String imageUrl) throws IOException { + // 创建 URL 对象 + URL url = new URL(imageUrl); + + // 获取系统缓存目录(例如:Windows 是 C:\Users\用户名\AppData\Local\Temp\) + Path cacheDir = Files.createTempDirectory("image-cache-"); + + // 提取图片文件名(从 URL 中提取) + String fileName = extractFileNameFromUrl(url); + + // 定义目标文件路径 + Path targetFile = cacheDir.resolve(fileName); + + // 从网络下载图片并保存到本地缓存目录 + try (InputStream in = url.openStream()) { + Files.copy(in, targetFile, StandardCopyOption.REPLACE_EXISTING); + } + + // 返回下载后的文件路径 + return targetFile.toAbsolutePath().toString(); + } + + /** + * 从 URL 中提取文件名 + * + * @param url 图片的 URL + * @return 文件名 + */ + private static String extractFileNameFromUrl(URL url) { + String path = url.getPath(); + int lastSlashIndex = path.lastIndexOf('/'); + if (lastSlashIndex != -1) { + return path.substring(lastSlashIndex + 1); + } + return "downloaded_file"; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/WxPayUtil.java b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/WxPayUtil.java new file mode 100644 index 0000000..1386946 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/java/org/dromara/zhishu/util/WxPayUtil.java @@ -0,0 +1,411 @@ +package org.dromara.zhishu.util; + + +import com.alibaba.fastjson.JSONObject; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; +import com.wechat.pay.java.service.payments.jsapi.model.Payer; +import com.wechat.pay.java.service.payments.nativepay.NativePayService; +import com.wechat.pay.java.service.payments.nativepay.model.Amount; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest; +import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse; +import com.wechat.pay.java.service.payments.jsapi.JsapiService; +import jakarta.servlet.http.HttpServletRequest; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.*; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.stream.Collectors; + +public final class WxPayUtil { + + /** + * 商户号 + */ + private static String MERCHANT_ID = "1524946931"; + /** + * 商户API私钥路径 + */ +// private static String PRIVATE_KEY_PATH = "C:\\Users\\www\\erp1\\wxPay\\apiclient_key.pem"; + private static String PRIVATE_KEY_PATH = "/wxPay/apiclient_key.pem"; + /** + * 商户证书序列号 + */ + private static String MERCHANT_SERIAL_NUMBER = "1FD5B441796BE0250622018DF43EC4BAFB34FB78"; + /** + * 商户APIV3密钥 + */ + private static String APIV3KEY = "wjshUHNCGJKO1239874HSJKL8Q52F3G1"; + + // 使用自动更新平台证书的RSA配置 + // 建议将 config 作为单例或全局静态对象,避免重复的下载浪费系统资源 + private static Config config = + new RSAAutoCertificateConfig.Builder() + .merchantId(MERCHANT_ID) + .privateKeyFromPath(PRIVATE_KEY_PATH) + .merchantSerialNumber(MERCHANT_SERIAL_NUMBER) + .apiV3Key(APIV3KEY) + .build(); + + public static String getApiV3Key() { + return APIV3KEY; + } + + /** + * 调用微信支付接口 + * + * @param taskId 充值任务id + * @param total 计算后带手续费的金额 + * @param totalStr 充值金额 + * @return + */ + public static String wxPay(Long taskId, Integer total, String totalStr, String orderId, String userId) { + // 构建service + NativePayService service = new NativePayService.Builder().config(config).build(); + // JsapiService service = new JsapiService.Builder().config(config).build(); + PrepayRequest request = new PrepayRequest(); + Amount amount = new Amount(); + amount.setTotal(total); + request.setAmount(amount); + request.setAppid("wxec160b6872dc24cf"); + request.setMchid("1524946931"); + request.setDescription("充值金额:" + totalStr); + request.setNotifyUrl("https://api.buzhiyushu.cn/weChat/wxPayCallBack"); +// request.setNotifyUrl("https://test.api.buzhiyushu.cn/weChat/wxPayCallBack"); + request.setOutTradeNo(UUID.randomUUID().toString().replace("-", "")); + JSONObject attach = new JSONObject(); + attach.put("taskId", taskId); + attach.put("orderId", orderId); + attach.put("userId", userId); + request.setAttach(attach.toJSONString()); + // 调用下单方法,得到应答 + PrepayResponse response = service.prepay(request); + return response.getCodeUrl(); + } + + public static String wxPay(Long taskId, Integer total, String totalStr) { + // 构建service + NativePayService service = new NativePayService.Builder().config(config).build(); + // JsapiService service = new JsapiService.Builder().config(config).build(); + PrepayRequest request = new PrepayRequest(); + Amount amount = new Amount(); + amount.setTotal(total); + request.setAmount(amount); + request.setAppid("wxec160b6872dc24cf"); + request.setMchid("1524946931"); + request.setDescription("充值金额:" + totalStr); + request.setNotifyUrl("https://api.buzhiyushu.cn/weChat/wxPayCallBack2"); +// request.setNotifyUrl("https://test.api.buzhiyushu.cn/weChat/wxPayCallBack"); + request.setOutTradeNo(UUID.randomUUID().toString().replace("-", "")); + request.setAttach(taskId + ""); + // 调用下单方法,得到应答 + PrepayResponse response = service.prepay(request); + return response.getCodeUrl(); + } + + + /** + * 调用微信支付接口 + * + * @param taskId 充值任务id + * @param total 计算后带手续费的金额 + * @param totalStr 充值金额 + * @return + */ + public static String xcxPay(Long taskId, Integer total, String totalStr, String openid, String appid,String outTradeNo) { + // 构建service + JsapiService service = new JsapiService.Builder().config(config).build(); + // 使用jsapi包中的请求和金额模型 + com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest request = + new com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest(); + com.wechat.pay.java.service.payments.jsapi.model.Amount amount = + new com.wechat.pay.java.service.payments.jsapi.model.Amount(); + + amount.setTotal(total); + request.setAmount(amount); + request.setOutTradeNo(outTradeNo); + request.setAppid(appid); // 使用传入的appid + request.setMchid("1524946931"); + request.setDescription("充值金额:" + totalStr); + request.setNotifyUrl("https://api.buzhiyushu.cn/weChat/wxPayCallBack"); +// request.setOutTradeNo(UUID.randomUUID().toString().replace("-", "")); + request.setAttach(taskId + ""); +// System.out.println("微信支付使用的订单号: " + outTradeNo); + // 设置支付者信息 - JSAPI支付必须设置 + // 设置支付者(JSAPI必须) + Payer payer = new Payer(); + payer.setOpenid(openid); + request.setPayer(payer); + + // 调用下单方法,得到应答 + com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse response = service.prepay(request); + + // JSAPI支付返回的是prepay_id + return response.getPrepayId(); + } + + /** + * 生成微信支付API签名 + */ + public static String generateSignature(String body, String path) throws Exception { + String method = "POST"; + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonce = UUID.randomUUID().toString().replace("-", ""); + + // 构建签名字符串 + String signString = method + "\n" + path + "\n" + timestamp + "\n" + nonce + "\n" + body + "\n"; + + // 使用商户私钥签名 + PrivateKey privateKey = loadPrivateKeyFromPem(PRIVATE_KEY_PATH); + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(privateKey); + signature.update(signString.getBytes(StandardCharsets.UTF_8)); + + String sign = Base64.getEncoder().encodeToString(signature.sign()); + + // 构建Authorization头 + return "mchid=\"" + MERCHANT_ID + "\",nonce_str=\"" + nonce + "\",timestamp=\"" + timestamp + + "\",serial_no=\"" + MERCHANT_SERIAL_NUMBER + "\",signature=\"" + sign + "\""; + } + + /** + * xcx生成微信支付API签名 + */ + public static String xcxGenerateSignature(String body, String path, String httpMethod) throws Exception { + // 修复1:动态传入HTTP方法 + String method = httpMethod; + // 修复2:使用秒级时间戳 + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + String nonce = UUID.randomUUID().toString().replace("-", ""); + + // 修复3:处理URL参数排序 + URI uri = new URI("https://api.mch.weixin.qq.com" + path); + String query = uri.getQuery(); + if (query != null) { + // 对查询参数按字典序排序 + String sortedQuery = Arrays.stream(query.split("&")) + .sorted() + .collect(Collectors.joining("&")); + path = uri.getPath() + "?" + sortedQuery; + } else { + path = uri.getPath(); + } + + // 修复4:正确构建签名串(GET请求末尾需两个换行符) + String signString = method + "\n" + + path + "\n" + + timestamp + "\n" + + nonce + "\n" + + (body == null ? "" : body) + "\n"; // 关键:GET请求时body为空,但需保留末尾空行 + + // 使用商户私钥签名 + PrivateKey privateKey = loadPrivateKeyFromPem(PRIVATE_KEY_PATH); + Signature signer = Signature.getInstance("SHA256withRSA"); + signer.initSign(privateKey); + signer.update(signString.getBytes(StandardCharsets.UTF_8)); + + String signature = Base64.getEncoder().encodeToString(signer.sign()); + + // 构建Authorization头 + return "mchid=\"" + MERCHANT_ID + "\"," + + "nonce_str=\"" + nonce + "\"," + + "timestamp=\"" + timestamp + "\"," + + "serial_no=\"" + MERCHANT_SERIAL_NUMBER + "\"," + + "signature=\"" + signature + "\""; + } + + /** + * 生成小程序调起支付的签名 + */ + public static String generatePaySign(String signString) throws Exception { + // 使用商户私钥签名 + PrivateKey privateKey = loadPrivateKeyFromPem(PRIVATE_KEY_PATH); + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(privateKey); + signature.update(signString.getBytes(StandardCharsets.UTF_8)); + + return Base64.getEncoder().encodeToString(signature.sign()); + } + + /** + * 从PEM文件加载私钥 + */ + public static PrivateKey loadPrivateKeyFromPem(String pemFilePath) throws Exception { + // 读取PEM文件内容 + String pemContent = new String(Files.readAllBytes(Path.of(pemFilePath)), StandardCharsets.UTF_8); + + // 提取BASE64编码的私钥部分 + String privateKeyPEM = pemContent + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll("\\s", ""); + + byte[] encoded = Base64.getDecoder().decode(privateKeyPEM); + + // 创建PKCS8EncodedKeySpec + java.security.spec.PKCS8EncodedKeySpec keySpec = new java.security.spec.PKCS8EncodedKeySpec(encoded); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + + return keyFactory.generatePrivate(keySpec); + } + + // Java后端生成二维码示例 + public static String generateQRCode(String url) { + try { + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix matrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + MatrixToImageWriter.writeToStream(matrix, "PNG", out); + + // 将二维码图片转换为Base64字符串 + return Base64.getEncoder().encodeToString(out.toByteArray()); + } catch (Exception e) { + throw new RuntimeException("生成二维码失败", e); + } + } + + // 获取请求头 + public static Map getHeaders(HttpServletRequest request) { + Map headers = new HashMap<>(); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + headers.put(headerName.toLowerCase(), request.getHeader(headerName)); + } + return headers; + } + + // 获取请求体 + public static String getRequestBody(HttpServletRequest request) throws Exception { + StringBuilder sb = new StringBuilder(); + String line; + try (var reader = request.getReader()) { + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + System.out.println("请求体:" + sb); + return sb.toString(); + } + + // 获取请求体 返回Map + public static Map getRequestBodyAsMap(HttpServletRequest request) throws IOException { + // 读取请求体 + StringBuilder requestBody = new StringBuilder(); + try (BufferedReader reader = request.getReader()) { + String line; + while ((line = reader.readLine()) != null) { + requestBody.append(line); + } + } + // 将请求体解析为 JSON 对象 + JSONObject jsonObject = JSONObject.parseObject(requestBody.toString()); +// System.out.println("方法体转为map前的字符串" + JSONObject.parseObject(requestBody.toString())); + // 将 JSON 对象转换为 Map + return jsonObject.getInnerMap(); + } + + /** + * AES-GCM 解密 + * + * @param ciphertext Base64编码的密文 + * @param nonce 随机数(Base64编码) + * @param associatedData 关联数据 + * @param aesKey APIv3密钥 + * @return 解密后的明文 + */ + public static String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext, byte[] aesKey) + throws GeneralSecurityException, IOException { + try { + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + SecretKeySpec key = new SecretKeySpec(aesKey, "AES"); + GCMParameterSpec spec = new GCMParameterSpec(128, nonce); + cipher.init(Cipher.DECRYPT_MODE, key, spec); + cipher.updateAAD(associatedData); + return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8"); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new IllegalStateException(e); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * 从PEM文件加载公钥 + * + * @param pemFilePath PEM文件路径 + * @return 公钥对象 + */ + public static PublicKey loadPublicKeyFromPem(String pemFilePath) throws Exception { + // 读取PEM文件内容 + String pemContent = new String(Files.readAllBytes(Path.of(pemFilePath)), StandardCharsets.UTF_8); + + // 提取BASE64编码的公钥部分 + String publicKeyPEM = pemContent + .replace("-----BEGIN CERTIFICATE-----", "") + .replace("-----END CERTIFICATE-----", "") + .replaceAll("\\s", ""); + + byte[] encoded = Base64.getDecoder().decode(publicKeyPEM); + + // 创建X509证书工厂 + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + X509Certificate certificate = (X509Certificate) certFactory.generateCertificate( + new java.io.ByteArrayInputStream(encoded)); + + return certificate.getPublicKey(); + } + + + /** + * 验证微信支付回调签名 + * + * @param publicKey 微信支付平台公钥 + * @param body 回调请求体 + * @param signature 微信支付签名 + * @param timestamp 时间戳 + * @param nonce 随机串 + * @return 验证结果 + */ + public static boolean verifyWechatPaySignature( + PublicKey publicKey, + String body, + String signature, + String timestamp, + String nonce) throws Exception { + + // 构造签名字符串 + String message = buildSignMessage(timestamp, nonce, body); + + // 验证签名 + Signature sign = Signature.getInstance("SHA256withRSA"); + sign.initVerify(publicKey); + sign.update(message.getBytes("UTF-8")); + + return sign.verify(Base64.getDecoder().decode(signature)); + } + + /** + * 构造微信支付签名字符串 + */ + private static String buildSignMessage(String timestamp, String nonce, String body) { + return timestamp + "\n" + nonce + "\n" + body + "\n"; + } +} diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/BookParamsEnum.java b/ruoyi-modules/ruoyi-zhishu/src/main/resources/BookParamsEnum.java new file mode 100644 index 0000000..b576dfc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/BookParamsEnum.java @@ -0,0 +1,50 @@ +package org.dromara.zhishu; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@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/resources/lib/pop-sdk-1.19.52-all.jar b/ruoyi-modules/ruoyi-zhishu/src/main/resources/lib/pop-sdk-1.19.52-all.jar new file mode 100644 index 0000000..099571f Binary files /dev/null and b/ruoyi-modules/ruoyi-zhishu/src/main/resources/lib/pop-sdk-1.19.52-all.jar differ diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/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-zhishu/src/main/resources/mapper/zhishu/BookBaseInfoMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/BookBaseInfoMapper.xml new file mode 100644 index 0000000..5bcce64 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/BookBaseInfoMapper.xml @@ -0,0 +1,47 @@ + + + + + delete from book_base_info where isbn = #{isbn} + + + + + + + update book_base_info set cat_id = #{catId} where isbn=#{isbn} + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/CountMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/CountMapper.xml new file mode 100644 index 0000000..5daaffc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/CountMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/DepotOrderMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/DepotOrderMapper.xml new file mode 100644 index 0000000..c63a614 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/DepotOrderMapper.xml @@ -0,0 +1,219 @@ + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ExcelTaskMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ExcelTaskMapper.xml new file mode 100644 index 0000000..98799bd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ExcelTaskMapper.xml @@ -0,0 +1,18 @@ + + + + + delete from t_task_list where id in + + #{id} + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/FastMailMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/FastMailMapper.xml new file mode 100644 index 0000000..6e8ffa2 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/FastMailMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + delete from t_fast_mail where create_by = #{userId} AND fast_mail_type = #{fastMailType} + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/FilterSetMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/FilterSetMapper.xml new file mode 100644 index 0000000..9eba0da --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/FilterSetMapper.xml @@ -0,0 +1,31 @@ + + + + + + + + delete from t_filter_set where id = #{id} + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/GoodsAutoFailMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/GoodsAutoFailMapper.xml new file mode 100644 index 0000000..d9286b5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/GoodsAutoFailMapper.xml @@ -0,0 +1,84 @@ + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/NoticeMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/NoticeMapper.xml new file mode 100644 index 0000000..8e25355 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/NoticeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PriceTemplateMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PriceTemplateMapper.xml new file mode 100644 index 0000000..4f98fe1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PriceTemplateMapper.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PrinterMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PrinterMapper.xml new file mode 100644 index 0000000..106c450 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/PrinterMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningLogFileMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningLogFileMapper.xml new file mode 100644 index 0000000..8ebeda9 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningLogFileMapper.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningTaskMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningTaskMapper.xml new file mode 100644 index 0000000..5575eb3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/RunningTaskMapper.xml @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO t_running_task ( + task_id, + shop_id, + goods_id, + random_num, + task_name, + priority, + data, + status, + call_back_data, + task_type, + success_data, + create_time + ) VALUES ( + #{taskId}, + #{shopId}, + #{goodsId}, + #{randomNum}, + #{taskName}, + #{priority}, + #{data}, + #{status}, + #{callBackData}, + #{taskType}, + #{successData}, + now() + ) + ON DUPLICATE KEY UPDATE status = VALUES(status); + + + + INSERT INTO t_running_task ( + 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 t_running_task + + shop_id = #{shopId}, + goods_id = #{goodsId}, + random_num = #{randomNum}, + task_name = #{taskName}, + priority = #{priority}, + data = #{data}, + status = #{status}, + call_back_data = #{callBackData}, + task_type = #{taskType}, + + WHERE task_id = #{taskId} + + + + UPDATE `${tableName}` + set `status`='3', + `call_back_data`='暂停成功' + where task_id = #{taskId} + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopContextMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopContextMapper.xml new file mode 100644 index 0000000..d1170be --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopContextMapper.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopDetailMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopDetailMapper.xml new file mode 100644 index 0000000..a44cae5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopDetailMapper.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodIsbnMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodIsbnMapper.xml new file mode 100644 index 0000000..e1791c3 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodIsbnMapper.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsPublishedLogMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsPublishedLogMapper.xml new file mode 100644 index 0000000..02d8c39 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsPublishedLogMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsPublishedMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsPublishedMapper.xml new file mode 100644 index 0000000..31b1583 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsPublishedMapper.xml @@ -0,0 +1,191 @@ + + + + + + + + + + delete from t_shop_goods_published where shop_id = #{shopId} and platform_id = #{platformId} + + + + delete from t_shop_goods_published where id = #{id} + + + + delete from t_shop_goods_published where shop_id = #{shopId} + + + + + + + + + + + + + + + + + + + + + + + UPDATE t_shop_goods_published + SET platform_id = CASE + + WHEN platform_id = #{item.oldPlatformId} THEN #{item.newPlatformId} + + ELSE platform_id + END + WHERE platform_id IN + + #{item.oldPlatformId} + + + + + + + + + + delete from t_shop_goods_published + where id in + + #{id} + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsRejectionMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsRejectionMapper.xml new file mode 100644 index 0000000..c11fe57 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopGoodsRejectionMapper.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + id, shop_goods_id, shop_id, platform_id, create_time, rejection_reason, tenant_id, isbn, platform_type, shop_goods_img,goods_type + + + + + + + AND shop_id LIKE CONCAT('%', #{bo.shopId}, '%') + + + AND platform_id LIKE CONCAT('%', #{bo.platformId}, '%') + + + AND shop_goods_id LIKE CONCAT('%', #{bo.shopGoodsId}, '%') + + + AND isbn = #{bo.isbn} + + + AND platform_type = #{bo.platformType} + + + AND goods_type = #{bo.goodsType} + + + + AND rejection_reason LIKE CONCAT('%', #{bo.rejectionReason}, '%') + + + + AND create_time = #{bo.createTime} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopImgMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopImgMapper.xml new file mode 100644 index 0000000..7af2405 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopImgMapper.xml @@ -0,0 +1,15 @@ + + + + + + + + + delete from t_shop_img where pid = #{pid} and type = #{type} + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopWarehouseMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopWarehouseMapper.xml new file mode 100644 index 0000000..d5463fc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ShopWarehouseMapper.xml @@ -0,0 +1,57 @@ + + + + + + + select id, shop_id, user_id + from t_shop_warehouse + + + + + DELETE FROM t_shop_warehouse + WHERE shop_id = #{shopId} + + + + + DELETE FROM t_shop_warehouse + WHERE id = #{id} + + + + + INSERT INTO t_shop_warehouse + (shop_id, user_id) + VALUES + (#{shopId}, #{userId}) + + + + + + + + + + + + UPDATE t_shop_warehouse + + shop_id = #{shopId}, + user_id = #{userId}, + + WHERE id = #{id} + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TAuditMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TAuditMapper.xml new file mode 100644 index 0000000..7897fbc --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TAuditMapper.xml @@ -0,0 +1,102 @@ + + + + + insert into sys_user_role(user_id, role_id) + values(#{userId},#{l}) + + + insert into t_audit_log(log_information,audit_id,create_time,update_time) values (#{remark},#{id},now(),now()) + + + +-- //根据audit_id动态更改t_audit_info表中的company_name,company_type,contact_person,contact_phone,email,license,remark + update t_audit_info + + + company_name = #{companyName}, + + + company_type = #{companyType}, + + + contact_person = #{contactPerson}, + + + contact_phone = #{contactPhone}, + + + email = #{email}, + + + license = #{license}, + + + remark = #{remark}, + + + card_identity=#{cardIdentity}, + + + license_name=#{licenseName}, + + + license_number=#{licenseNumber}, + + + adress= #{adress}, + + + business_license_time=#{businessLicenseTime}, + + + business_license=#{businessLicense}, + + + license_time= #{licenseTime}, + + + where id = #{id} + + + + update t_audit set status = #{status} where id = #{id} + + + delete from t_audit_info where audit_id in + + #{id} + + + + delete from sys_user_role where user_id = #{userId} and role_id = #{l} + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TBookAuditMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TBookAuditMapper.xml new file mode 100644 index 0000000..61d93ea --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TBookAuditMapper.xml @@ -0,0 +1,21 @@ + + + + + insert into zhishu_shop_goods(id,user_id,product_id,goods_name,isbn,art_no,price,condition_code,item_number,fix_price,inventory) + values(#{id},#{userId},#{productId},#{goodsName},#{isbn},#{artNo},#{price},#{conditionCode},#{itemNumber},#{fixPrice},#{inventory}) + + + update t_book_audit set inventory = #{newInventory} + where user_id = #{userId} + and isbn = #{barcode} + and LEFT(art_no, 12) = LEFT(#{artNo}, 12) + and price = #{price} + and condition_code = #{barcode} + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TDistrictMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TDistrictMapper.xml new file mode 100644 index 0000000..6273717 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TDistrictMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TFreightMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TFreightMapper.xml new file mode 100644 index 0000000..6a31ff6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TFreightMapper.xml @@ -0,0 +1,175 @@ + + + + + insert into t_freight(id,shelves_id,code,name,unit,cap_max,art_no,status,tenant_id) + values(#{id},#{shelvesId},#{code},#{name},#{unit},#{capMax},#{artNo},0,#{tenantId}) + + + update t_freight + + + code=#{code}, + + + name=#{name}, + + + allow_distribution = #{allowDistribution}, + + + where id=#{id} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteCodeMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteCodeMapper.xml new file mode 100644 index 0000000..4787447 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteCodeMapper.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + INSERT INTO t_invite_codes (user_id, code, invite_url, expire_time, used, created_at) + VALUES (#{userId}, #{code}, #{inviteUrl}, #{expireTime}, #{used}, #{createdAt}) + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteRelationMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteRelationMapper.xml new file mode 100644 index 0000000..bbe89db --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteRelationMapper.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteRelationsMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteRelationsMapper.xml new file mode 100644 index 0000000..1b0e3d1 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TInviteRelationsMapper.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TLogisticsMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TLogisticsMapper.xml new file mode 100644 index 0000000..179e616 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TLogisticsMapper.xml @@ -0,0 +1,83 @@ + + + + + delete from t_logistics where id in + + #{id} + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopDepotAotuMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopDepotAotuMapper.xml new file mode 100644 index 0000000..a3a90dd --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopDepotAotuMapper.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopGoodsPublishedMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopGoodsPublishedMapper.xml new file mode 100644 index 0000000..4243639 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopGoodsPublishedMapper.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + id, erp_shop_id, shop_name, erp_shop_name, product_id, warehouse_id, shop_id,trilateral_id + + + + + + + + + INSERT INTO t_shop_goods_published ( + erp_shop_id, shop_name, erp_shop_name, product_id, warehouse_id, shop_id,trilateral_id + ) VALUES ( + #{erpShopId}, #{shopName}, #{erpShopName}, #{productId}, #{warehouseId}, #{shopId},#{trilateralId} + ) + + + + + INSERT INTO t_shop_goods_published ( + erp_shop_id, shop_name, erp_shop_name, product_id, warehouse_id, shop_id,trilateral_id + ) VALUES + + ( + #{item.erpShopId}, #{item.shopName}, #{item.erpShopName}, + #{item.productId}, #{item.warehouseId}, #{item.shopId},#{item.trilateralId} + ) + + + + + + DELETE FROM t_shop_goods_published WHERE id = #{id} + + + + + DELETE FROM t_shop_goods_published + + + AND erp_shop_id = #{erpShopId} + + + AND shop_id = #{shopId} + + + AND product_id = #{productId} + + + AND warehouse_id = #{warehouseId} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM t_shop_goods_published + WHERE id IN + + #{id} + + + + + + DELETE FROM t_shop_goods_published + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopMessageSubscribeMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopMessageSubscribeMapper.xml new file mode 100644 index 0000000..e22c6b7 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopMessageSubscribeMapper.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopOrderMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopOrderMapper.xml new file mode 100644 index 0000000..572b15b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TShopOrderMapper.xml @@ -0,0 +1,115 @@ + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TUserPlatformMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TUserPlatformMapper.xml new file mode 100644 index 0000000..5ec8530 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TUserPlatformMapper.xml @@ -0,0 +1,35 @@ + + + + + + insert into t_user_platform ( + type, user_id, platform_id, platform_name, + status, del_flag, create_by, create_time, + update_by, update_time, tenant_id, create_dept + ) + values ( + #{type,jdbcType=CHAR}, + #{userId,jdbcType=BIGINT}, + #{platformId,jdbcType=VARCHAR}, + #{platformName,jdbcType=VARCHAR}, + #{status,jdbcType=CHAR}, + #{delFlag,jdbcType=CHAR}, + #{createBy,jdbcType=BIGINT}, + #{createTime,jdbcType=TIMESTAMP}, + #{updateBy,jdbcType=BIGINT}, + #{updateTime,jdbcType=TIMESTAMP}, + #{tenantId,jdbcType=VARCHAR}, + #{createDept,jdbcType=BIGINT} + ) + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TaskMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TaskMapper.xml new file mode 100644 index 0000000..1ddeaac --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/TaskMapper.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + update t_task set data_num = #{dataNum} where del_flag = 0 and shop_ids = #{shopIds} and task_type = #{taskType} ORDER BY update_time desc limit 1 + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserAccountMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserAccountMapper.xml new file mode 100644 index 0000000..3907dc6 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserAccountMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserRechargeMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserRechargeMapper.xml new file mode 100644 index 0000000..49216a5 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/UserRechargeMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WaveDetailMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WaveDetailMapper.xml new file mode 100644 index 0000000..34f247b --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WaveDetailMapper.xml @@ -0,0 +1,180 @@ + + + + + + + INSERT INTO wave_detail (user_id, wave_id, isbn, book_condition, stock_id, stock_num, created_time, updated_time, is_del) + VALUES + + (#{item.userId},#{item.waveId}, #{item.isbn}, #{item.quality}, #{item.stockId}, #{item.stockNum}, #{item.createdTime}, #{item.updatedTime}, #{item.isDel}) + + + + + + INSERT INTO wave_detail + + wave_id, + isbn, + stock_id, + stock_num, + created_time, + updated_time, + is_del, + + VALUES + + + #{item.waveId}, + #{item.isbn}, + #{item.stockId}, + #{item.stockNum}, + #{item.createdTime}, + #{item.updatedTime}, + #{item.isDel}, + + + + + + + select id, wave_id, isbn, stock_id, stock_num, created_time, updated_time, is_del from wave_detail where is_del = 0 + + + + + + + + + + + + + + + + + + + + + + INSERT INTO employeeInfo (employee_id, name, user_id, wave, count, created_time, updated_time, del_flag) + VALUES (#{employeeInfo.employeeId}, #{employeeInfo.name}, #{employeeInfo.userId}, #{employeeInfo.wave}, #{employeeInfo.count}, #{employeeInfo.createdTime}, #{employeeInfo.updatedTime}, #{employeeInfo.delFlag}) + + + + + update wave_detail + + wave_id = #{waveId}, + isbn = #{isbn}, + stock_id = #{stockId}, + stock_num = #{stockNum}, + updated_time = #{updatedTime}, + is_del = #{isDel}, + + where id = #{id} + + + + + update wave_detail set is_del = 1 where id in + + #{id} + + + + + + + + + + + + + + + + + + UPDATE wave + SET count = #{count}, + updated_time = #{updatedTime} + WHERE staff_id = #{staffId} + AND belong_account_id = #{belongAccountId} + AND is_del = 0 + + + + + INSERT INTO wave (staff_id, staff_name, belong_account_id, count, is_pay, created_time, updated_time, is_del) + VALUES (#{staffId}, #{staffName}, #{belongAccountId}, #{count}, 0, #{createdTime}, #{updatedTime}, 0) + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WaveMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WaveMapper.xml new file mode 100644 index 0000000..d669008 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WaveMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WhiteListMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WhiteListMapper.xml new file mode 100644 index 0000000..242e96a --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/WhiteListMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + delete from t_white_list + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/XyCategoryMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/XyCategoryMapper.xml new file mode 100644 index 0000000..c0b029c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/XyCategoryMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + select industry, category, id from xy_category_id + + + + + \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/XyMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/XyMapper.xml new file mode 100644 index 0000000..015530c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/XyMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopGoodsDetailMapper.xml b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopGoodsDetailMapper.xml new file mode 100644 index 0000000..0c5f02c --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/mapper/zhishu/ZhishuShopGoodsDetailMapper.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/ruoyi-modules/ruoyi-zhishu/src/main/resources/preview/韵达快递单pdf_base64.txt b/ruoyi-modules/ruoyi-zhishu/src/main/resources/preview/韵达快递单pdf_base64.txt new file mode 100644 index 0000000..f8721a8 --- /dev/null +++ b/ruoyi-modules/ruoyi-zhishu/src/main/resources/preview/韵达快递单pdf_base64.txt @@ -0,0 +1 @@ +JVBERi0xLjcKJaGzxdcKMSAwIG9iag0KPDwvTmFtZXM8PC9EZXN0cyAzIDAgUiA+Pi9PdXRsaW5lcyA0IDAgUiAvUGFnZXMgMiAwIFIgL1R5cGUvQ2F0YWxvZy9QaWVjZUluZm8gNzQgMCBSID4+CmVuZG9iagoyIDAgb2JqDQo8PC9Db3VudCAxL0tpZHNbIDUgMCBSIF0vVHlwZS9QYWdlcz4+CmVuZG9iagozIDAgb2JqDTw8L05hbWVzIFtdPj4NZW5kb2JqDQo0IDAgb2JqDQo8PD4+CmVuZG9iago1IDAgb2JqDQo8PC9Db250ZW50cyA3OCAwIFIgL01lZGlhQm94WyAwIDAgMjE4LjI2OCA3MDIuOTkyXS9QYXJlbnQgMiAwIFIgL1Jlc291cmNlczw8L0V4dEdTdGF0ZTw8L0dTOCA4IDAgUiA+Pi9Gb250PDwvRlQzMiAzMiAwIFIgPj4vWE9iamVjdDw8L0lNMTYgMTYgMCBSIC9JTTE3IDE3IDAgUiAvSU0xOCAxOCAwIFIgL0lNMTkgMTkgMCBSIC9JTTIwIDIwIDAgUiAvSU0yMSAyMSAwIFIgL0lNMjIgMjIgMCBSIC9JTTIzIDIzIDAgUiAvSU0yNCAyNCAwIFIgL0lNMjUgMjUgMCBSIC9JTTI2IDI2IDAgUiAvSU0yNyAyNyAwIFIgL0lNMjggMjggMCBSIC9JTTI5IDI5IDAgUiAvSU0zMCAzMCAwIFIgL0lNMzEgMzEgMCBSIC9JTTU1IDU1IDAgUiAvSU01NiA1NiAwIFIgL0lNNTkgNTkgMCBSIC9JTTYwIDYwIDAgUiA+Pj4+L1R5cGUvUGFnZT4+CmVuZG9iago2IDAgb2JqDTw8L0ZpbHRlciAvRmxhdGVEZWNvZGUgL0xlbmd0aCAxNzI3MD4+DQpzdHJlYW0NCnic7b3djmY7ch14P0C9Q10L6NTmPwkMBuiW1IYvfKFxA36AhOWDQaYNaS78+t5krBWM2N9XmVWdLVhybxzgVC5+3EEyGIwIBv/++ds/fzu+z//+5b99+9v/8J/79//2/3/75+/xpcSV+rvycuTv7SV+r/14KWfq6/u3v/2P/6l9//v/8f0fv/3jT30ejpecLwTGLxFIL7V/qQb1ZVybEI5PKMQuFI6XVL+HsSi0/pKGUgi/UocYX65t+CUmxDr/f2lD/JU2xP7VNqTw0IZf6odUHtvwMRNmgfv7fLwc1wqE9CsE0kt6EISPCSzWLQqnFH7PdclyGy8hKIH8KzzI7aV/SRBKeAm/Nh59E0p+yf3XmuCZWOqUq19iYnxp1VIYT2S5bAqhrw/aEV/GKarn8C31++9CmRX/l//67b/8zff/jlL+3//wbbXuf2phYaQppKO8tPPT9xPnxfDznzJpnT/UE52ZmqDznwnrKRiv32ZCzyshITdgKA4ePntcpRlYLfX4kjV7XTgF+Xn2xAnDeICSO2b3e9jUTrj+HkHyopXSkAmzabMo0Fl6m7l/O/MfU6mPsRgsXApVE95WQj1V/3Eq7yYJqN54aUUSjqVPXEIRGrMObyhmfhNeRpFiwqQ6E/qqZpQmhZcWBMascLYqzs612fMmpzC+HI3ZV0LVRhxrvO+EPqSDbML6pL2kwnZ3n1CkDm3VYSbUF0dzSkN/liDNcAkRzVhicYh0kwnH4qM0A1wJiythDoYJ8xIqslR49NvuiC3yQdpQlpy9rYS88NHIlyrSMotUrkBs+1CWn7XpXYgJ04VlGDNHkvpkkbVUBJrKrPqdFKIwaMrF+07AICMMIq2Ewp5Zgya1PSBXmgA5IGRrGqUdY6MvB+asoOSuVgH0wnGDEX0mNPk9Cq+QH0MJtKroAxbVFulXzdyUV1W6UoWH5Psa06YtDwkDzFlwjsNUDAxUEie3ME4Lvl/s4wdvm9u7BPToThgi4n31v8jH0V07QOMhoS42GqKnrg4iUlEGWhSR4sgMYNRYjJI+UpEqFEDCormRsFTfhglfCy2yBIWJuGvr2P8OSvaY3e8h2q+1XDMYWO8u6qx6Qa6wJr99+8/eIh63oboN1W2obkN1G6rbUP2bMlT/9Dcy8xL1amZe55CZM6+zJp/NvOLZ16t+oh/ed4IM0QlTVbtgoAxATaAMxlM0+lZYE6LWq6um+rbGYiaUqiNavl+2Qpo54WJCWxI4i1v86+i8mQDDUVG/ky7lc8Iu8juQfUZ0tt2ZOEuGmJgQHbkhRidscrN0tr6IPupa+zon/hxfM6FR+kuRhPzyDFfYuUmy+IQqDKHNOEnqSLDfe5w1d3npDkskAAIpNQyiwcKFgsdBP5ColkuoouGLkszWRikfHxIOmLXfZjHKlvedYfMJCZsv2aDfbIbJCUNiNz0/ILLtN5s9+O93O/MDIpPm92l2PWXtfSWsgEiAYRRGUvgmGgInCUA6PK/fTELB70v2RLImbCJosTG7ldTMYXGkByi5U3W/x6zUDCyB2YOU1tfvaY7xPcpcy8VraEyabZ1eQ0f1OtTAYczQhlDgTOiiCee/24RM2LewvC7iTYahOK8dQyyFK5LMubufMUD5LWAbzA5eiJMuoUB0k2lnMk0PVVX8+0qo20FSCoSgrwaG9StwzAd8glZEHWYnJFCPQ0fF8YKBxK/r1sYTpu1hGEYXZUa3rn3njKQ31s3NWDpdu+Lh4bPTA0c30dfs1BLFszpo6c5/79+N40gu0lsH5GxGITtdE4rPXpuD2umukUE80hIcbMXVOoHFnQY/JpM9rzaTNPkLyciYgUByMhr54VT0tty35b4t9225b8t9W+7bcv+bs9yYm/9wxfOczc8velvD+H0nBA0NIeGQ6O+GwcA22AUnJaxyMzLTuIVD4hiAQQJrGyI2zYSmwUskdI1NLThQvsKmoaJpP2cAJLj6dxPVQZN3C2tWHqxgSK9orYRNZsSr2bDLmcAgTV3IxGhOdGjmiYt0jqIWdrDohGSchGzOhGwCOidMxVSkQE1cEhjQ2V9ruTugM+N06LPFoiqi7EVAgpl1DTs0+30ljGooALJlChHS3glSG4UR2Rf1rLFPTWgIXs5RfsKaNJZ5oqLE0054AmO+ZDcJDFZu6PJKoFRL/hHEwN0JEmat2igtRpos1TD9zUZVxN/Q4mrWLoJ0UoMzogkdaiFQzsUIrOD3HgZYJdjDAPH2PQyY0ODAzPDdkS8JbiRibeZMSLp80rbkmIS8FN9eaDAJssACHspCw9pWk5ahfts13wmysNCjW+eBxpglRIE0SNluksFqFLWPLGtAeb1ymeNUVkOrVxVzbeqEDUtZIapqe/2mVTlg+WXJ46yKuCiy0IOGrD5xzZJVojO3+AG6041jNNuiEHU9E7hS5fYzTWqr86Iup/ii10rYLhzBZSSostkwyK9bqdbsulHoW1ziln7CqsIJWY6N1VmV3yoY9WkkyBo1da+NwEa4RUiAUiIsYEHUCr7q0p+TTGcFPl5vvc3kbSZvM3mbydtM3mbyr9xMfjKjjBgcaUgIK2v7JJRY+7MEjhWJovWsWlKiaFKliG8SmOpxQWTwN00ReXtXHBCbEhQ19CQiUBvju3UPI4SDKX6InugoYnBa3QBWNi7tM4kVEZgwBILdDKIFqvAj8XNIWG2MxjhVweg4ms9w9gnTcJDhnUC1PvA7zCFbl6qa6VeNWJoOEvZccdPo9Ip2G4zea1qf3B0MVsK1eU2jT+DYQ0JHkDPSzZHek+I7LOrEa8SI+tbaDPBfOmeY1jYxDsUXJtZiNvbISn5CuEgFwXtNyM39TskCjMllb+iLREMiIVE55NF29NaxQeKvKJvBW21YZjspxRhXwww08E0YU8ScdKzRFLKNLQPBDjleoWGteKbSYVV1FO8VBzCOKwCVvmPRhGhVmyaIR2lgsLBoBVFkMasUSOACQX5A2RT2kFD2uNlrGmbcVZFU2gZNiGChwggIszVQYZQQsC5UqThkYMgyEPSIaR+zo78CZAXdL2ZM+gsJXIVCf0cMm7WGY9Dwn7sEZc9uS6iqMV+/mQSRe4UiW5U2RJcKnIqzyteqZVHZuqEO63rQvO8rQTgiqxmHdWhUkRww5arpxPCrYhAHZ1uI5PnHn/XAlMAG54hLhs04S1hPg0dCOYBvZOAWXEz8ihlLCtdCCF2pbY6QQP18Qq6tZmnVofoUXl0Y21yRBwdbRXdnUMi4tIpJpsSpB2WuaPYtwVxSgQRjkQTz1R3UPgvDisv37V3qMSZG+RsnywVeR7O9ySUVU9TYkiFlmXnUG9eKHIbZyyZaz0mhLMGYSSPrU3Rva7c+yds35U3F7kLlbeEORYpvwYj87Rsj+VDa77tae/bRqdYPdMi2blpm19WOQdMozUBvdjh2g0qZSy/DamkDpTsHDe/u7bwtuZbeVFaSteSs6/4ZniuXPEZ1dem0LwkrJLBu3Sx5gFGfbkC4Hc7b4bwdztvh/H47nLfDeTuct8N5O5y3w/lFh/Mxynl+vp3OLuqxHnA7uyhb4C67F8tY0jRt2gk69rZ1uUqjSNXm+tTMKksaRFzyIRZ3jl+KGJ5otrgcMMFd9olmGdhddGLui1IXYw505l3aiD+Kh5MliN5lhBeOlS77w4ooyi5KsMiQJIpQHsRpfbtRlryTQ4V+bxf9WURNd/HTilg/1oFh6S5eFX8Vzcovl0NWGIOfil5wKdq0E0153whNA5bq80uxFCyEFquLHixiD1khsEFRGra6YFlkP2WpbhUU2BOTSVn0a5d+WNVZHlCmXu5invljfclKZC4LSp+IJqT0oaptjXCKEBDddeLKX9eXMqZ6W1KL9ouAQ4r7su5F1EiXbaZAZ1bZ+8lfk8iPDK0uHukeDGBHZxdELbOLr1w44LtYmkIHrstUonIDbpeLQTbus46Vx0HRgRZLRcSdQ9GDgjLiHr9rsJxDG+wVsDi0+oiD3qmETyatt/649cetP2798aH++MQHmec5rA4ZHeVMOGRhGFUIx+F0yMRGiYQ5d9laRKHuPGGCCIF+jTX54/CaBGVDk4xuNcmoXpPMjQ77x2w1yUhek8y91ntYzGXsqkOIiJqEWIbqiFaTjOg1yYhWk4ykioIVoBqZu9i3Gpn7QLYamfsrjBqZh0S2GtloSsdGaFem4mjmV1EjLIRqhFWQsbnR4kHyaoQY/MpWjcyLL6wamVs4thoZsmEHymJUp0nm5GVjETrQGd1rkjGsJhnDahIiahLiyl+NJhnDaJLRrSaZMysdd0M2SKkmGdVqkrlpZWuSuUvFapK5o76qJkF3Splzp77VJKfAOE0yr3iwmmQOF6dK5gipVpnMrf7VY6tMUPqguGxfQIaL6pJRVZdIL3H0t1/wRW49cuuRW4/ceuSn9MgnPkk4JKBU5e6Q9zNBQl9ImDBIjUUDrOsZa9WzUDMwPBNwe9Qhl0uhAoSlqUJBAgJr+BoDlNRL0OxSesFuQNQN0sq6A87sg07z+j0ckNH1cQiWcsCUAyWH4OoVwqXeSGC78DVbPUlvlgSZ+SjLxovlp+P3imOzGZ3XXs3DtIonU6Jps1z8pIM9HGs3a5HQejiSaGhsFiTc/JeEsx0r7CYfVxyKO2RfaM0Mc0rRRhSmrqgV2h8tqabdoe7fg8TX+XVYDnfVU3FBFrdqxM+JE2r5WKDpACSgYfiazRbimyko2wiCMUUXhn92dds9Qu4Rco+Qz+xIXAaqcE9GiIeYZF0QCYM+Au7mOhOa9NNi9IZrfWBDLBcxAed1SI6iqxA74OOxGrfaHg/6pautqNoeFDEsFwkJbzZBlmZC0FjbQ0LXhCsepszQIaLSGV18PV3fOhOKNE5GS6eXVpBdEFblojiutfLAQlx+Q9W7/mKXvj+4Lz52pyUinbdVWuz0r1GbM6FVw75heDes2My8w7dbMRgV1cF8SOiaULNLsH1VWZ5URQ7FmKpWzhWkKQpzchDXBuyEJUSEOLRF6lxjPzVPTBzwlOu0ApdIeFuCvhR05RIdGqgJH1uXe9zc4+YeN8/HjbM57o75Nd/TW+5DXWerSpKdNrhjvn54S/2msCZ1SgKnBYXEx1ftP69ElvspQKH/NIVhSMBhEBIfPxjwAxLT0AeSiB8/f/EjEkXW4oXEx29H/IBERWRISHz8gMWPSBT7dMHP8sL1aR2GF39Wnza52uMXBctRkHttfpJCi55C/V7mosRm5ccvMPyAlXMBMf0ZHbopDITZ/nw+DMRSfjw6rHU89cMxsLtLDkQfvPZG4DnY5Bqu6v/WbL99kzN/SmapWf1ZlC4/lKwXaEgFufhZaYVifp5AP0XOK7a0ZAPTpiXbZTY5wZuC5L9iQ/Hs0U0uyj5V/RlYP5+ZHTCE/umDvdtrHXKX0pZHsEsRvAmv7BdoqzyWCVN6SaK3mgN4E5D8V2wo4tWZTVEs1aaIMDQpIP8VW4rDd3qSeOWmKHhTGL7r/feTYpZjo0oxy8XYmgNYKSD/Ff9cj2V5DmkXJlPUXZjgTVzyX7EprByexSW4ISVQv0fuK7b0kq3RSS97oQLeFJKvsf9+UayewaVZcs1+Wz1r/ZeTVj1sbd6/1eQFCngrn8PX1n//SWfVYuX/fWIn38CbePHjw3+/qt/dgK3D1wZ4E+gvj9CQa8EP2JZ9gcBKAPmv2FJsXppac0UK3N83L03+60kPuwSUXl+b5jWDQP0eua/453pLdgPskmRbxC5K8KadXx6hrXn3IxV7gTa94eUe+a/Ymj6Zjm3bJ4s/2/oJ3gYP07cLthSdFX6f2JUJvClczPS4WPHfdIlkG8J5BMRyhgnb9OGTh4Sf67Ywz1FkV2L1xpIJpoDox8mFxhuClNGRDYc30UwwVOSThwRLNjhLPslmR9N9Hy5m/vK1EKzW3LyvCIEnOV480ert0YWCeEbRK/GZ4EY6E4xLFL08X2h81osxe1Gcs1A3/phgCsheGi80pCH94pfFixvIBEOlX7rV01hkU/JDMaTsLQ0TNhV88pDgyK7ws6F68QqZYIhIrPyCLc0cnFoLOXuZZMKmkb3J9xR2P4ZcrHZY692/ExfPPzdw7Wp8Z6rkHUlgU4Hi1dCFgjSzX3okX5xJJhgq/dIjnsYie/o3Xgt8ThafPCT8uyX7Tz+aEy5fac0J1+wQo09WyzEt/ex9xZoNAXmr4kKhfEhhTkY3gSjH2jyBj+e1See1i0KSqJWn8HGMIen8XrggC36ewsdxowuFIoeRPIWPQyUrMLAp1PrIyPRx1OjCh1bFBP8CHy6d2TGZ/KXOdPI02pM6fCxQFwrhURp+7XtEqI9q3l1NH4daLp05rUd5kIfPetPXIo0nYv1ZQ6w8zGH/KNZmYIS2jEA55ARgWvtOfhfap8o8zoXhU+g7L0vWhMqHlIT0kwTumrnQkOAHkjqPdO8ExPJJ5UlCTo4sEzbZEfCKlSZk5CGVx4QdXXE0HNl2qe3oXIoglYeEdqmtJijZchy+tuylt2u3mYTD13YnfBwPYm4J2psSG5erWMBDAuP8FxquIQMX9TEhRK4WgMpDAj55u9KwZEO51DbwUnkl+5BQLrXVBENWw2JIiAdON5PKQ0LQyJmnYcmebvGRHNnI9SuSfZJwWCHZCT/Vm7HxTn4mdN6ExwIeEhpPyHsatiHpwA4aTYg8fgkqjwlcibvQcGQzLk7ThMIVMVJ5SNBj3Z6GI9vwMJxJcEPxaUJ1bNeETTZHr/dK1hUxUHlMiF7v7YSf6s2szyPsBF/vZwnFsV0TTEPkYv9NtgSvAR8T8MnblYYlO6N5ju1YhjJkHxISz7R7Go5sv9Z2XDTgY0K/1FYTNtmaLpqk5kvlHhPSRZNowk/1Zq0XlVjbZSg+JtSLStSE3ZAW+AbGTihOJp4lBNcQTTBkE695YUK7aMDHhMSbQjwNS7Yfl9r246I4niX42mqCIZvWtq53m+AVx7OE5PSeJvxUb85TXk7au94vzAIeEspFyWjCbsgIF5U4knd6niSEi0rUBENWb9xhgl50SSoPCXq/hqdhyNb5Hoplez2iLnIh9vCQcPDWDU/DkS3eC5rObCiOykNC8V7QTviZ3qxH40MwSAiHHzOPCQffrrzQsA0J0Q+imeB0ytMEN4h2giFbr7Xt3o14klAvtdWETTYeXiXWGLwv9STh8CpxJxiyYsMN2e5H+JMEmv0LjZ/szXT4QTQTfL2fJbhBtBN2Q1L0zlVN2WvAJwnRO1c74TdLxfPnJ8jmC3804d8bWfZmaeKVx/D9d3Edw33yjuk5VTYrbjPuMTeZiNMxZliE8I0wcTlMMifVCWXO1EuNMBv4PWKMa3Z4QXVWyOCyvAOcFFnXPW/aYa1oPGLWLBQx7YrxPa8bmZuBpSXl8r3H6isUqaziue15wkFyyA71fjzHneZxRpUNXDdMz404IxjqA5Wt3KYjsInZ58PKa0/ehKLi1u6Y6WuIGREmI/N6xngSmqNjreTPOsh26hVunjWeKi1JiXKrWZRe1JujZlhqQtEmSSJswth5JIdMQufzxpJCKn3/lm1GXo40t6SsOotDNYUO7hQOAUkDD5zQW0LTeFrgRdiI+6sPcecGThZIH+AFgXVUj7yYWyWXgDQ5QbRR2nnBxFf2ZsNT4KvQJs+Eu6rPtkDIO8YzRgw7HpBiUilkVIrVSt37zn7Yr4sfT4S/rd07pQZ69tJv3CebROToxaDHA7p/yJdz8GVhIi8x6tJbgafKZ0RrbmSbkiuSWcU6idQW3ts09/HOKcK0COvI3QTrqbVVr9J4pxyhCPvcgTrRdMhFUM7PZpXnsa75t2zAn6fdWFYXKceBPvAAR//WR0OOsoHAOiS2/q56ClTmM4wcEUt9iQYOoHj2hOOlG/aEIOziPtLVRfw0vURlyesc9EFqtB7ZEpWAlou+UB6FdXn+xGu76Qota/XWhhWSef22MXyVdWBm4rU9et3cz6nbWaOu1ZvbWtfYLtxrPFc1Z1Nk87B0vLZbitkNFw1HXU/9qbu0lW0eR3rzGJ5RB0o1M0FBcnKDf+e2O7u3T48t3YbtNmy3YbsN223YbsP278+wPZ42dLM2mduxve+KRahiIKPWzagB4iKCFAODu3Kn6GLNRpBT5D3YsXIB4moZCiHaj+YQy72boqMPXBNsZWnRNR2CGm1UbVZpCwlpu9ddn44Lk21zB9XiNpYYIrpy5QYlXKwawP3AYqBU5P5eGYiKpIN5SbE0LeKmTHa33EApKOk7RMRyvahIXsIFvtaUbKbg2urA6DlQtVkjHY5FiI1eZVgOfHYR+S1FtxT9nBR9oo/yOqJTO5ztuR0tK35TTB8W2QnXiYAqK0GyQJqzcIdBeuIAz5H5g0b+s5iDTaGRS6DQqPVBIbNzlILSlGDzLlPMD3DhhgTkV/yboQkKWiYoNA6EMUwdLAXxyHixUVbHD40I9JhnD8oxiImmvcz7z9Ml7nQ1Jb6f1y7IvUCVGwml3QNNhENuGEAX0VdW2F2HPmJ0OGwqPTpiuSR/o9ksIp7jR10r74SRAxiTCbLmu4WrWGFSGDhVQPZAcrMlGa6A3PC7kYwIYpk98EtZsPEMepXOWt5Lw2XFFAgu/G8BsSdNHjGdtdzpOOHkCTA8T0E4UUiUMAnI3Qxt7e+ad1FBcLBV2xiCpvnFFxTqAKK5AHikWCA0KYDofc+dya+kE7zccDSpmtnRPHkqc5NZh6RzxSCoSKeKG5mW14zJSOqcD85KpC7iNKC7UpemynRpo7HztgPndlPjdMlWQQaNr/1qTydTZZpC2vLQRBqqfeQEFJ3A13kiqqqHmIZMQyNZCJ0sXBOFsDsiWqKjqmpXohJ2WIVLZ5IfOEY6a2kmxalT4pPQxAK60uyCxTVeZLnKlDoCCTgGlrkaD4xZOqeESWfVoMXPAYX1sAmynY6DDayvvI4MzFwZi7ROzHHSGZ94HimL2IRLHcTPThrVWXLTuBlBpuBJp4RT5IAwN0H1TtlWGXMjGZLB3DrTnCPXS80nHtptV2+7etvV267edvW2q7dd/UW7+smctURyRixbiTJWK4xCiVxoWXH/KJyT7i6BQiJx9RIkCI1lgUC5XLFf/JYwxkp42XwuQSQBiNNukWfWQL4s8WXP1ll5SmlJIhXSeiLRsL6hkzNFNzCKX1GyVFhGL5Hs3Z2XvlohKVlZLjWCXioHtbT0XZHoR6kwZWDZ+XvadeK3SeJHvBxITrxTvkp5iTrsBKhBLoULGnQ3ShU50G4tbL1s+SyV43YsmeWojWkj7dZKzXPIr3CmVuOrjHBaitJ2TzVudF2rVc0uLs6ML9tkKJijtTRKERaeGtdFUtkFiq33zVyd2jmUZEflXFOIxgsq40VC4qvdC1Q54wDAgDggn3wr64as7fOgnMa9X6XThizhAaoOMUBGLPcmAbFKrv6vcvVAElqyj/HEwXZlPXhDzhSb2ZjdlXLtADn7+o1YlHw9uP472zjlzPRk1W3J+LHswTz92q5kVt6unTkjfVHL1J+kM/mldCaKFCH07VwtTy+bpWfDs3Ffz3ZH73USy42NQFWeXCfis2HAGGpEwnMiDuG6TmZt9Ussg1bqiLApKnz8TNj5Vry34r0V7614b8X7r6F4P/F65QKafdylSegDM8DZUplMTNGtg5tp0ITODTRzilMb57arCfXFjrWKqUWCLNdONZmEcDASgxlXhfZtB/bizKyoL2ZHLVp9eWaVdf62Dz802SSATTbrgp5mZ8NNNyzNip5oh0Ra5UxLVFzD5F5kpXUupU3WtMHGI++gBOKZqG0TejDCuECB+PAjYUPrMlBkUDVEGsj7s3JdTQMaWeUKf2mE7vH5bV5qhC1k0sd1cJ4nc0L2MqMSJxfRNMVhm8MW7PYbygtvxmy6pwRdidDKGgI6nZNJd8Vkj2cmIF/zBuewZM8sDLNU3svaot3mcyKswi4GJGOnFquya47sOYGabdUu/oKTqP7rFA+MtCaczV13nLTCNW/RbKdodfNrZhRqIb9DRqHokZ13sgkiig0zpEpdwBqJ+W5u/0zT/TOokYQf50MPYYkQwqSrFIQDM+bw7RLKapXCKNvvyLWip8Q+cOlurXJrlVur3Frlz9Aqn/gr8sQMXaz3iWPW0DIflKHTPLAXGE/kIEzZsbNncJPvrNvQOOokPAoXS4S167kZaqyB8KYsu20kAeuN8YKQKL71/FKxavAV981RTcjDRFQzvqFzwPXK6KecJ1xvILIL13V3KaoL2Yd1N4c63TLOR8AWpvW0Ehxi6UF5Imp7kOPgtq/JiT5Q5qQjbyfukUfMmWbHxEcqLGVymyo2xw4yLWE72WJ+5pJGFaZBcPWFJoju6mEJLqNGo3JuK5qbuENzyztIWonChaM0+A7SnvawFp0vTI3tZUPqNpOwd1yWayhnMtmiKCnvC4cE6pQ5JGQIjEzFInpULh102AyZEewKIbuyQm+Oyj3tYiBZNq9hoEAy1LK/VzzEUvfGt8VUmKNf1BnJTP+HnoCXRQxikWaIH+gcrKP0mTxjuevQB5eSZPIzDmtb8cylOUTQOabWe7KdQ3692tm5pIk3Pbs9KiDvybJgCLOaRlIqMCu7mmDtwfzE37n01HV6jadLzTB+1WspKRHvRgIgIckuXUExVH3vre4AwnqSy6zgj0BJbML2w7oTS6UYh+ldcdvMBIOAGw8ByCLwmR/yNIiP/Ih1wtwlcqMhi15w4kCkpDOmtDRYgZCsd2wFcO26IyCn5SSrvBeurh383EGu4jK3PpLb1ejLC7lEfK127/bmp7Jo27Nd6UIpDCIKhNVkHahWC3fazvqfZOAe4KBCtg5CT9YhQMtVa20Mju/VNJIRtcpC6AGwCqJmT2QODsjbu/xy5YUTtR4grixyPQmrSCwnRYIbRChShe/OdgRgeNbjo4ceb+N/G//b+N/G/zb+t/G/jf//gcb/k9n/vPpc6MmVMcCwJG+KO067BlqPdbrwiJYH8rThsa3JfNrwyAbqwUUcrD14dpEvS9rMa2OgyYuDS/g5HNZu4TFIU5MQWZNVU7mlXE9QBl2kxbHd/XvD72kHteRpw21eZ2ljLzURYu14wr4jb5K9Gikn5pNigadhM77GQVDRqpqAc5ghMFa3DnuFw8qvvABZbY/pabD1eJs8u0gor3sW+3tlwwUWFha1g7v5OXGgJYiDG2kzIW0nYMJguErIY8BMwIB/o3w84MCj9UfjGS8c5d8J65gXYYK4Nrt5YDceC89vvJZ/W0uWqE+IHZEX3jEhcEswbxsIXIWXt0LDyw5q+tG2njELEnPuOCE4nzHlhtC39StcXDGDszthc0dhharDaXUgD6tLf8EGcDzCYLzykYFtMthjerpd9yQHQBgGSPaBkLSsW4/BVf114rYzcgmPptuDdG/zWW5zYwTeYCAjqVpgG2X8F2ssNSFDFge3UA7IfbRj8BR8HFxvZY8DGPYJEabmMX4sG/D3ZjfdqyBt6prAZ7mFGsccnirj67N79EvDFg/5vu54sZmx1sCH7/CMqtZk3jDQde6hkDtyKF4ZLzkKkq2qXvTkFdzIBZ5R+G7Fxns4JB0vuuTA60I/fOf4tjW3rbltzW1rbltz25q/gK15nNucImFuX1gvDPC51PeJp/rKctVrOiZrsrwYnyQKlDO2aSaJ3OSCg35Joionlv15+DgvyungrdpTi0YJFZ6EhYusRZQLk1Z4BVWKEsnge64z6+zZrNcej8X/LJsg4goWZhk+LIW3CSUJ42S52wnVA1jhoXlCLCHnHDhZdlqQJxIljRJiTNyngbonUQmoXhpsyZC8yeXlmJGXEydeh4WkfkmCVEmiO2kgCAn2g3IKpLyOncjWPa1TkhBNPngBvdYZR1i0fcF0rOwHTnJfVY6b1mp9Ai15KmhiiWygJicGrSo9ueoFylE3BkaJlaXGy4bBkcr3FFYHJtFf0kVJDhmltBglexlQqcRjhGSWBM9JVD70Ra6zXXFJScJpSHBvt0judoLYr8NPtT/ixHuk0OaNJSCWuFE1RbZxjSnh70Z9/6aHjRLNF87GJXOS6nBlFTbV4V3Xxt5RLGNYBBCHr8CKT3zTW1fcuuLWFbeuUF3xiW+RxcXDOH7nkWd9WSM3kTzeMZ1lE5qWn8v6cR1Mlp1j+JSoQFT4YeFZa7kKLvPa+Cx70qBe8rod8vx/ElCz9udJSmZQ5z/Cw/OPnFViF0b/6r0B+B75s9WJWaZrWZ7HyYVP04vmYF5RR5OvcY2zyV459565FJtlJpe5qpHXNCLLNIJ08KVsqss8yowT9fxVHGN+2Tj20XrxslGsHDvfoGdboyGMAqHl3V+BTGp2Tpx0H3VXByjA52UpommJolyOqUhCCrgGAfgNp+TB3dzJ6ySFpqpaa30KHFYx+0+ZgO6MjRZkSaHsSQRrc3V2gFnFLpGzkINGqcDB+ka9WDgSji1lLEYalmUbJ5iwhF3gOjQu9wJC4e4BxAX8LNPHNHCGBnKkyh3injifxTUYG4tQQlcytyirLBPEVDkKgfXaCJn5JlxtmkWVycInhk3i9aFnzbsrF5iqiliWOnNlPdawEnahHBXipPeRdH676rGEEzYkD1ZRNCpEFRjCiUpsFCl+Y2vbjYxYJ70cVkQ18XQ9seYG2qPOFiNMHkHleNcPDUXt1z5qNQdZYifMXNnUETainSNW/nfKDbAqCr3sBHLCu4qzbHHOfO6DWJQ7EYYDUEDcBzefUEMc1l3BTROpM69syoZE4p4EtCrJFu1U4P/hxoMtkQd5sKRISsXrUHlFgtSDwmUhKDZLlAkuBQcVoy6iq9l9kZ05+8+jlRVyjV8hNGtMJJprNUVRS+GPWoOerXxJDcQ1zNG6htouCUDgWhl0JBHUmyJoNGO6It/AWpyTWBB6U1tFLSStgsMurVDvnZ8mxF43BvPC9idZn7j7pEQ142/so7zfgEMH4/slhMfWu/OKC+pSXIjRdnvToMXADECEBxYEogUzwd8ObA7AHSAQYFJS1Kw5xLUbmC+wRjCHqG9ArFnuBKERO+h6D4NoUj6+wen2xG5P7PbEbk/s9sRuT+z2xG5P7PbE/jU9sU/iYuVgVE/eEMVdKYlr2EV2FEAz4jqZjdr+bV1sAc0jZkRu74Acr9s56rYT64KUZF29d16Ioq5fkW2YMJ5vvCfH4rzN6cJd7eVJ3MR7fVHrkhIlJpcqynUugG+EVG3Mve+xxH0v+/tOqQpsLhycRIK1ewpKU2LKWiRuN1lQQ8XIrfg3QxHfa4l6Pcphg83IbykkjhXcUJMkoiwuc0nsDtzdY6LJr7xFB8yHnEAMy8HVGVy2AnzwAhjNPTUV5IjfRoowbrOJNEquJ/Qh5c0XCI222mPNv1Zp9KVmQOEJRVSMDJAu4RQs2fCBcVwTo3pknruoVjxVQhQbc0dhh7TKfT/qpOGKHWhEXOMD6ZWbelSUcRlQ5uOHexSh2xNnScD6qPRid36pqi1x2xHQZ7dW3arjVh236rhVxw9UxyeeR5WDglh2fzdYWFTloM8Vq4pA/icYL63pCqXDusz/8Vt5/9sr9xn31A+Vx8iq81obPcTptM5TZzbMgQtA4Ho2nWVNVxxIZ+DEnWQxXmJSuomHRKVQTGLqeNmT5Cp3/ybefl37y57G18ZBibtMzLrxussEQ3AWUitn0FN+NxLffOPmfh1CFyENXCi21pMxscMFKhtlO+ljlfRXjHOgC9Vui+zKOgUtuIxlmN+mRiN97rzbOKbNHjBAmTVcTcGsxuX9Kn2AeS0Y27kAv24K6ozDrM7T/pLpWR2c2qJrTWACtwrptBdSoCKSojabiLNOYOz2gMweliqmQ69GvHH9jQnj1aF/rma1HToUQdsAliVSCs2OHOkEFAhGalhTpAXwjRfszJDxGq1NoxqK7WwWHWFx2bO7NwjDrmXYm3+0AY2dVveoRzcROY3w2Vugt/q41cetPm718YH6+MQDwd1gOokhhtZINmbVErtK7+kyDGpctloqJNPfF+FpmTHm9SuWzg7eFJZsNzdd5Fr3zBW7arSReOTEspzCLxNLQfhRYq64kQxuc9NVxyWjXDeEdkzsy/Uj2pkdF9LmAlYVV6HRToo8d2d3NFm+TLyJFbSBSQuDwS0MrlvdTCQS99CRTRrE1RvgYrb1wFIS7oNDSBcMT9iVtwhhEVT26ClfRLmy4/BjwTRkMamSDeB2tYurTZe9cC9btYOQGM2WL5Pe1wcNrnfO5a2ycBscrEjLVG9HMgLKX5NdF2kakYeERqvQGsP+4LRVsI0B+bAzQtNFLgWJHmoulH9BGvTPphP2j8khMCRR4oAhj1g0GcMi7VuzpLJR3XKt1sDjjdK4opW3dvurR46zFjZddISaOLLNmq0FamVXtXCRRqa8Ino0KbrACCXQt0bf6uSwlxRiTFEl8PbvpqvtEKcS99h0I/cTz+xWq7davdXqrVZvtfrravUTj7UHDkEJ6hHLiOiBpydwtbAJor5+64ddBOgH46RLytapzK2rBt17/GgUV+ciOCS3Uz8uVnScWlq9TYCOIAw7owSPm254aqRpNbCiUizCFEpxCvbXqbI23eDqKmditAoAWPk/WFkwGr+G+ASR7C5f90OtO7IVycYuYqj1bs+6oDYMazfdYrgUqPbH0pGDlkQ06O7YiSkE8mUPNFi4dylQTy8RCXZHQ3drGiuviejzS+FB11ULmZf18LInnT3QqIwht1qrfe+Hlfg2aKmSoGPHCygw1IOdM/AhPRu3Clpk21aub+vybAAMEWgv8EMHvdQbZaBRCEqgwbAZ68qqY8c23shK6P43XpP8BMvSS+u2+iHapmUbGoEQI6bSht3BhIF6wBp1XVoqMqbr3r3B8c/9kt0tUm1Nsq7McnrlE//uVkK3ErqV0K2E/vWV0GfeULML6e/fum4JwN1+jXNCXKXX6KgtRdXoxK078Bp3r6FRje3HXZJAuDbVIJu3FPtrTlqKnkPua/ka8Apy9zmT+9WjuMt4ZUu1zP2nrKTrcsbJorLne2+8CHDLk+J17+UPEIabwxstuXXI5l1js9hllBPt+P4rexGjAxXeyExTVl6DT4QpDlD0ZM1G041Qn6P72hq8Edp5dM8FozB+hEYx1d3cz+y2ArylKLHjVjcmnjJHfyduM1/ScEXFSVx6cT/G/gQp2VBtoUCoEBCEPlkl+oCi0xCKQ9EKInCDhmpEAp24B3GyGkQv7EQ0ibQUYYGjBVNH4I36bp0a243DsL8aPqm991gYvEGJPmt1v3rUqs9rDLfxKCAnauy3HOH21MLdV+2Cx5ZY7GL2SOWX3tsHyOZdPacoDQ433cLDbky8CtajvO2/jvj96xNQrMrZRY5oqwOklTV4oyNd0c6rDHuK2vAqVK/IRa8FWJndb439BlMQrdfoMRT8Rrn7vO7HFp8gtRtWdJp1RjeC0Dcb+9yopyvSy8E5mJrdVe4t8Wfzh9ts32b7Ntu32b7N9m22b7P9b8psfzLjxnME2PT7Pu9+XxaBm4A3xlMPgedOHdZNx8j/BMsmYpT3czue//dX7hPuzetKsRFRPB9eMKlaU3PQ95kJI6oOnlechqoqekKnsZkAhW6g3DrqoMvOC42NYWFhapIuCbxvVWHyV67hdlbzs0fV2jC2XMtO3INIaAJQ62pXY5B5r6v6QyZBrqn9EeRNuS7BwDIeoMu+riXdMIK6OVS7L/6Fg7Oq/uTv13W5bu/mR7me1sDq6cq5US1XodRKIWvtEgxs4QG67N1Tv8BRbN1Nnxzs0KIJeXtKvFxXe/h4iU4eiEVcDu5eXS8RYcslJW0M+u741aNmCY/xssVMwXqJiAAPsRCOYH4bm6SOuo1D0crBT2Iz1VFir5oxr+dfsyYcW0mTniIX85aKASro2ja1GQrDML8ZDqnRAv+AH5AJx7/uukbtxQuMl9wpup/ztnmUGPWXjEzxRmw9Od2uCcMIMRyEC9wyDefiY+iyS1cq5O3R5ooU07MJ1ygHrrTgenDjO6nm1x+5hnaB/qpxLVqhVEwhK+4SDDzSAzTZycUfQVqN6PoksU+DJrheTexVavJqXSTYBfOzR8MLULaXkag5fIDbYMVuqqIwDAdliGiC+FUG9vQAtznE4NPKBuhXZ+w/iYncrsHtGtyuwe0a3K7B7RrcrsFfn2vwaeRgcNzTPdCLq6gq9DY6ugeD0Ubp6GE3RF+gvNNhvQMicQ4ssnnNkx6qrAet934AxOyveQJzvmRP0f3+DGWt9GHL7lT+hCY0vx/EMYao0YwOTeh7IeDHcL+wYxIMlG520GUXM6ylx/QAX7WP1cg32lVCu6bi8USxOxiutI/sygZkzQB3zU2CgfYhIscXc2r2x3AUU3XTLYX9WJ4lTNitB1i8HZ8JVsSKXaG7QMmdfPaYn8FNPFjnpNh6uVFSzHjSjyw0o8/tGmcd1VHQ/eZJuyN2N/rd5ZhvZIEqnMJ7IQlxzqMF2yZVV8WotuLUYDE60l0CamD2bYraS6k6mPsle+7ud5+7XYl3T9xcgGZgGF7C/NNaxlvQhGEkWs2ig1vA1Yp+BF126U+FaezBaUy6JvA9ptgdtMswagr2z60+g8XpLFO42Q9q4K66STDwSA/QZN98fA7buGhkdozbPCsJrmeH9yLHxYu0mLbEQHOj0jZN5vfan8FtmrqriXUYiDhQhnlJZaNuCW9vQROasYk6Wp3t/zSQcHsKt6dwewq3p3B7CrencHsKf+WewmdxhZBf3KpDSFxE4GO++cUtOpwYIUx5aZi3Nq4+duisbSi00KtPN5RHix102cumTe2pCCwOxYZ9Wa/n8HXV20R+JzT7O9HKrbkdnih3B80d4q+LaYezSiHRpI5rgryonF7yEwQV6/BGq4cdsnnlfVQtJoKwN+U7IYD0YRyB4O6SfF2vRnf3c30KSTxyy6cUHu0JcwNZc5dgYAsP0FHvoP4cwk8IersouySwD4smmF40UPo4XGw53qVWgQnm74N7PilrLmHCVh2snvRhnwg0kC+BFz9KNGEE9/sw1M0YPLimIAM2bGcBjdzOAvrUjP5A8581IZhAZtDjXYRtRz1f9bVuqivUldqNUFXhTuALvsW4DSQWDePMRkytzFP4Km9P64/BuiDaTpPXuSAbovfpgIRhRsq2TZDH7TTshBG2vNI2ergHB03ph9Bll35Vcmk4WILrZtj9EF88Gm45gtqNv7ubhalyDHFNSFthac2IQjHqS9tFdKQr2nnJQd3Le4FtXBTAUMOVtqMnCdkYaRi6qDrerWXBXpifrU/p4eu2klFtl3VFAi9b3qbMinmxiyYGcpAUe12+gd3QVodBcTNmUcertf6fBRZuV+F2FW5X4XYVblfhdhVuV+Gv3lX4LLIQD+csdG5ehLpYP6urEN2r6BPW7SrEw++pYgL12IbLV/DQZS/F/Z6TlrU1ssMT2Ygw6uly2xDwIzQB4FdptSrvYY8KGkhXoftThzPBewrE0pvPEbWrxRtJ11pk84o1JoqgezHl3R70fALdwc+ZkKL73aPDE2/2oj4DpWYKWXGXYKA02kGXvXvqFziKrbrpj+acBHdkd0Jz9PMCX1d2c/hzwhIddEtdodrzn09guBI/sivc3GluIBWgJozgfh+GunETqj0Wirqqo1DpQySVpuj8hErDnzWhWD+hvmSH3NFQVk61lMJuWmo0oCaE4X63jDPKuNoTok9gvuQu0f1c84/g6275/r1bo9Kcl6DCRpukz6u0a8Iw0q0W0cEt7Go/P4Iuu/SqwjT2QDWWvL+YHYus/Ibu3Kgag/278zH6y5V2d0WbNQhFofi8odhfj3RFOy/59xy1cdHF7I7BvgyaYHtzmbeoFsYvd8FKmN8vMNVLdrvcBeO4kTtGekkwMAwHMUCYABdhw54eoFpHjj5WFYPVmPzPggm3d3B7B7d3cHsHt3dwewe3d/DX6B18Gj8oHPhwEmLmtkU6CcU++SwJ3aieWO3WqQucta00x+IoKBRHwUGXvRT3ezbUje23foL9u1xCwGdC879b1b8h+7u4EPAJs0Pm0ObMnbgGA7N0chEmdlwTpE9/BKFhfYKB0scOuuzLKG8YQX2jV+1iWnxU3sDu3AWfMGGLDroVjRNn46tsKDVTyJq7BANbeIAue/fUL3AUW3XTL9GG8iXBSlt0x29P6G36mWDP215huBy/PRO6+7k+hSQe3PnbDaVqCjlQNGEE9/sw1M0w1IRQdl3pMaDh22NALxs1EOkEZE04jJNAghuaHVS7uqq1FHbTWKMSNSEM97vlnVHPLgGMN2jES26ToC2JrtdN9ug8EBEZrQpRGBeRg5WCUG6nYScMI+O0kB5ukac9/RC67NKxCtPQ0brtOrsZZv8Rduc00Djw92w9DkXF6TAtWqFUTCEr7hIMPNIDNNnJxR/BNi4aeqgVMycRJcF2a3FuJeyDkQmXQOtioF/pivbH6la6NlSTZq9rNjAMBzlSKlcEhzGYOrAqlwfpPFS3s5g15bB17sCn4YXbebidh9t5uJ2H23m4nYfbebidh6vz8Fn0IQWqAToQ48WtUCR9NRr+w5mQtyJKwe6tusDXlbsZvbbhch88dNlLcb9nQ31r6BRcvFiq9hRJZhsuPqG9yCkFGyx+/XZJCOmgdSD0LsTg8TSaqkE7OzQBdlh69keQCtclGCgd7aDLLoZaS4/pAb6yl9UJGPadlgnT/lVymxfknsBwIW5K7u5854ast0swEK32LLH8evh7aE8k78w19lx5ljChdRra1a7ro+Aynps9nXuBkj1F97tHx5W4Pa0bqzvUueH2rof1EvRrC43TwMesQ9lVVZ+h0aNIKkLB+wyNTkDWhGIDnY3brAi3ZtptU1VVuc+qm6Y6RTisy9C4P8xyzqjkZo+1sSpPoeTO2f1uT7mxoTZ7dz/7mowdSt6jw9im4fyFYezaMCZx/w3ZVtvZ3flCD/eYUVM8jJUevFKpBNepNPLD3bHEsbI9hPFS3c8tPoObeIuucPgbqBdhKFZHabsUHukBmuzKuyts3kXQcY9uEBW9PQRocPYjDVtU22Kg6H97rxKsh4HX3NbheIR1+wTbzpm6mHUUAzE2mAAnYcNuqauTsBPaNoQcpt7ifxZguP2D2z+4/YPbP7j9g9s/uP2Dv07/4NMYQr1c6ZyK8xDq5T7nM2EYvZMaPQhxEdploxUS1EVo7j5nDyW7vc95f53TLsxYfZfAuhnoliEcnqh6aCLAktte4PwI0zYzM7u+oA7LlPTl9nFNkI79EYSG9QkGSkc76LIvW7xhBHVvxndCEOrm72wvcZam2WucT2ivcUrZXuIs2U3ChLZeRKy2xRu1cEU2b3d0PRrF1tl0h97HXTTB9OCE1gO06HVltodzU3SHc0/YvVy6hAnt4dwTekmL7jjuhlIxhRwjmjCC+31s4mYARnu3M2tGP0Haud0E9K0Z/+llxyTfvrHlqm8i3/EhbM5NQG2oqyLf9emmoUYTakIY7nfDNqOVozvC9gj9ETbWPGoP2yNsaGc0HR7dr8laF70gOIyLtNE85cs9zzthbNGmdXRIBZ2m9ANk80p/ZnfD84YluP6F0We9NzQXPr/CFvDH4pwNKBhDWhPScL9LxRSy3i7BwCM9QJOd/PsRbOOijYearbQdO5dA9W99SJq9aKyBXeQSU/IUvW4bGZ3ZMtBf8uwTaAN1FCjkKGnukmd+zUHl4LaROgarWyv05v/TgMLtLNzOwu0s3M7C7SzczsLtLNzOwqfRhW5fvn7XhFMBSX0797/l1fG4LLmtnpj1we3KbQlOmHTygktOTrjRmTvjnhr+jDtv+DFuzGlLy8/swcbJZ5vjtieEarORQN0oH59oCXgOjE/1xtxBOLfsWtZ7ZZZhy3pvTCqsOTpCDN8g38UqDvKdRnbYd4wnRGx4NdQzfXaTKbBLP2S9CKen3Vp29BQXV+AUt2iaG91d3ICGV9FdfnTC6BjdpVugOHbHoNvW30eyPcyRjdu48TMazi9neSI+6IXpVmQjXt3deQQItkn2EM3o6PbdGGXrVmLohay9NAQKD3GZT6b3QpHIyuNlsLLUjT2Q6RmxD9IaC5OH2P7VioNkoiYkn51DwR+O8wnsE2pUCLcqVNZ1/5z8x+lK3KrzDdNwEHzcCRxLz2G7Um/F/d7bA3TZhy09qzCiUyjpYfcoR+2GNbsuwqjdAlD7Jp3G5cwghymtmLsa2IzaS/ag5NLWGUYn5MbsY7tTRqP05DROTz8xz7vV9q22b7V9q+1bbf9bU9ufedy5vOy2vy+cs2FGYWOE7ZmLvNTFeolcxe/JVifb7ReSHZeJMLs9EwLqO9qD0qFDWLcTioStqgPN3Lgigj/jugl+XBl5IvHGKJUU3nh6SarWuJDPqjevShu3gkv2apfhpTLVyiuuVdhs7UbEfvu2G3NoP0SjIOU+VrYs0+LBfs5BUo0iTu4GTUDTlEQpGfi9GQUI6mbgyi15u+pWvbEhRfsgm1+b+a5RfZBsY0xlTbNzozGSSjV7TEuyj+r6x9lxoW5Y0pwkZMNLy+nPPJt7eNzD4698eHxmQUrgcx1wOoueNluiUKK77OaE8JEhaCXRP1uG/oQYFMurANxOJxMgl/iaCwIn9Vat91+imTzMug4jNyeMpq2hHJAj+fWgHIn/M0iaPTRAuuFne7f0hux6TWj43VyRrXAwEAfimECdCCJLiK2wQYnjCO36vRwPf4NsOciuVeyGPTmIEPtOkL5TuJzZRbrr5GZYDWIg+YFJ2/BVBvsWLeiizfgSfL8k1KL7Po12elgCJ5OXLl+zpoJzojp5gIBs+Slm3BQ9g4roK4UZS5Ibkrh5l+rVDoUIeatmfnhC4+tJO4eZHxa9ioYw+5FzUOcuFqN3OF0Eg/e8B0KEhLeVAE8XCzDnYIrXBMTlsWQzu2kjyOGOhLMKu8b2spxib9Jxze17NBpk1MpndvpWQrcSupXQrYT+1ZXQp95QsW89vtsEqU2hF77iFAV3V2xVUSiRImaVUihyVBn6opw1I3cTVftxo9SReKfcSeGdw1+qphCre0zgIO7uTsXCoxIjsCr2SMFZVQQ6RCorJwyUSr2aRIabu7pkQhvbnDgY95ZMRYjPM31NGIoeHpk65t0miNronP44Vmi0cvOOnE1WZ2s/sH647IS/a7dGVBd8J/XMjpLSs3srZMOu2e05E36NjU4nNLumNrOU9cVOcAzjoQSLHiSPaVcWISfyVofALG4vGbMuXH/eEIvlTECQEB8n7XS8lbCrAmUgjKgulgqu7+kUekV/b5htWXE2xLvbn3BC7E+IzcBdc03IaQuMtrv7SJsWR7Y1F9vfg2MMK1/aKd1e6qHUt/x3d1aOwkyBcMJO+Q+7Oe87AWFJDGbMN8k6DacWHIpBkFPUDOequx+iSn80URFKGD8udq4vvWyLViHgWDEPW0juaGIoxd39UIo9DLEHIuOjJ6yuU3afGJVFS9HwTGUZrgd3Dx9eAoKXj2Dl5xN/9TYTt5m4zcRtJm4z8dduJjCj+MOfzKSCNuNv//in86Px/U//tE3H+i18nwdRz2LmNU9nMX96//Z/xz/+4Y//z5/+v//rH/70ZxFM9UrwlIDff4FgLg81/PsUDMFNBF/+8/c5OZuJv8Ocds3N5v1PUyTev/3tf/xPqX3/+//x/R//rBoVWYb4y/GslivBkI9/+ALBlh8JpvgrPFss/0sxrJcl3KY6R05fkYmRrwTjH+tXGBaOdKWYc/jjxxyb0ZbFsaUF5uNpS2sesmlWuNY3155QWPE/SwILLIcEw4TE+PMZP++9uzD+97F9hU9n1TzB9Ifj779EUDYu2Cq2Nr5AERptPhbHnmx//LuPe3LFinY/JLH0J/N2N+Tjz++GLMfETZW+2A15XAmGP/7+kzaucNZq4/hej7N1URx1aV34RE4df6rE/jx/4q9IehVL6imkX6IgZ/c9hfwhhRVMXRSWsW1lMSFsJpRfYUJry7Z8gQldNkp5CvVX6tDXKqsn0H6pCuOxH6zC+ZyLQy6I9IzsPzVW1vc/HMF5lCWgawTXfyif6eLT4K1arXsgk8xNj2O5cajVx+26UMhyp8FXKKxjL18h0FbnfIFCkf1rX6GwtiV8hYDsKPgVCkk+n653lcj5EYwnUo6fLH8RkPmlJ/CJsjNfy0TIf/3xGF9rMkqgyYkuTyD9JUZHr2uCs0ZH+YefNME/opmWOrY0Q/hD+BrNOQNzJH/JbZ+dFqShTWZbwrv8Jd6VNCeHrlLxD/1r7RRj6Prj72r6Is15Z47rjl9x30/etSYd+hfkXVt7SG2ljt//4e++1s6zfrlfGvr7L/JuzHHnqjnqV+Yaq5w8d5qxir8/jq94vPVKsITjJ2XwucNbrgSP8cev+OTzZKKjd86EvlJB0QSWgy19Zbo8t11c61e/Mv0OF3pH/LuvtLcdD/UbX6lfW1vFPQOP8gWCvT8QrOEPX5mPtyvBXHP80ny8Ximm+PuvVHE+4T31119OrOeV4xeK5fi7n5zWheMH6iucHsupE9PoJnYTf5KXP6ba5u5MS7QcP6u8f0y0r4impZr+6Ebi8b2elmj+GMOKWP5uhZr/5b9++y9/8/2/2+0PdvfD/Cou9f3+LYZ1Iz0T3nQ5rOa+ote/SHiGiYcljARD+MCmk6kW+s8SLkOk4F2j2UjYhEvrElT+NcIt89oTEG7c0qKE56pJ+mXCc+9RsoSRYAgfstnqFwkfGZ1HwkjYhHOXhYFf67zcuL6GzmPCm1skffgS1dh9j4Tr52aOu9wncafm6abEXdHH9uJNsMB8WGbO9aH8ub7MY8giknxZn385Q3Xry7k48X29y5CbcA4ftp/+sM5TdPvD8ezDgkhCqNLDsV8+q8fT8uScnBS4JskB3x6yGUq+Dc++lfxLe8gxhFDXTQG5D1vux4Ggvr5c5depKlcgY3JqKIvrx5Gcvs43LQqyzrac5VpNJ9WP4zBz95sjcA6PPFeq1Nuun8Rh1n65RWE5mHWFUSaJtOvwSfD40FiOacVpjXb4ubqJdj3lvRtdnOZ5imfDbvxYG6/V262NkZDm1silRQ/zt+xd+Mdv/wtWyOiXDQplbmRzdHJlYW0NZW5kb2JqDQo4IDAgb2JqDQo8PC9BSVMgZmFsc2UvQk0vTm9ybWFsL0NBIDEvVHlwZS9FeHRHU3RhdGUvY2EgMT4+CmVuZG9iagoxMCAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA0Mi9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTMzL1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDIxPj5zdHJlYW0KAAAAADAAAQAAABMAAAAVAAAAKgAAAAAAAAAAAQAAAAAAASYAAQAAAFwAAAAVAAAAKgAAAAAAAAAAAAAD//3/Av7+/v9jloDVBBFTxeJcWEHYu/lywhIl8EbfEjf2p9IkE/lN9OMcQRqN8yVVpnkXMnRNm/aC7NjoIwFL01u4E+HgXHf/rAplbmRzdHJlYW0KZW5kb2JqCjEyIDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDQyL0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxMzQvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMjE+PnN0cmVhbQoAAAAAMAABAAAAEwAAABUAAAAqAAAAAAAAAAABAAAAAAABJgABAAAAXQAAABUAAAAqAAAAAAAAAAAAAAP//f8C/v7+/2OWetr80wslVp5h49doX5xgJ5D6PGepHC/+e/UBr7HcKRfzlddSE8Z/hfqw63zu0f17l5IasDCB/Hr0Vlp+Yb//rAplbmRzdHJlYW0KZW5kb2JqCjE1IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDQyL0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxMTQvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMjM+PnN0cmVhbQoAAAAAMAABAAAAEwAAABcAAAAqAAAAAAAAAAABAAAAAAABJgABAAAASQAAABcAAAAqAAAAAAAAAAAAAAP//f8C/v7+/0NBhKIZQmaaykAHM0m/0vF9lgKiKLj5p+niqZmVHhN/7JLzKACio59c0xZf/6wKZW5kc3RyZWFtCmVuZG9iagoxNiAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCAzMC9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTU3L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDU3Pj5zdHJlYW0KAAAAADAAAQAAABMAAAA5AAAAHgAAAAAAAAAAAQAAAAAAASYAAQAAAHQAAAA5AAAAHgAAAAAAAAAAAAAD//3/Av7+/v9kETx9jGu9tURtGptxGJ5tXLTNwymX3NMB/2scjCkISoocWvTcFITe5ez5lTb+lx3p2b2rNdhb1zZw/fdWQ3mfbERfr9I/Fvv5Ziz/ZrAv5JDHGOP57Z//rAplbmRzdHJlYW0KZW5kb2JqCjE3IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDI0L0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxMDEvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggNTc+PnN0cmVhbQoAAAAAMAABAAAAEwAAADkAAAAYAAAAAAAAAAABAAAAAAABJgABAAAAPAAAADkAAAAYAAAAAAAAAAAAAAP//f8C/v7+/2QSySqAxfkRxBWxE9wovpAfgIWo87sOF3vEt7NZA1//rAplbmRzdHJlYW0KZW5kb2JqCjE4IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDMwL0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxNDEvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggNTc+PnN0cmVhbQoAAAAAMAABAAAAEwAAADkAAAAeAAAAAAAAAAABAAAAAAABJgABAAAAZAAAADkAAAAeAAAAAAAAAAAAAAP//f8C/v7+/2H8xz8Hh6ZWvYBqlldqDbaZYj8oOomU1kV0B/a6kYBdIwI2OGj3JkP/WK+omWjEI/z5ao34j+3eU0ZrB6k9AmswwhqDZclL/6wKZW5kc3RyZWFtCmVuZG9iagoxOSAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCAzMy9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTYzL1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDU3Pj5zdHJlYW0KAAAAADAAAQAAABMAAAA5AAAAIQAAAAAAAAAAAQAAAAAAASYAAQAAAHoAAAA5AAAAIQAAAAAAAAAAAAAD//3/Av7+/v9j7UUykqGzvE0tdO+MTWm+g8sxNFHbND/CspDSYM9BiOeD/GHOIhWFK8G7PzrGU7mYeSkF5+2rELarA32uPs0IG0bZSBeksjHRebsTR2gZg37cdkgR8tkFySd/oH//rAplbmRzdHJlYW0KZW5kb2JqCjIwIDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDMzL0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxNjAvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggNTc+PnN0cmVhbQoAAAAAMAABAAAAEwAAADkAAAAhAAAAAAAAAAABAAAAAAABJgABAAAAdwAAADkAAAAhAAAAAAAAAAAAAAP//f8C/v7+/2QS0I6YsdbJPhAvtw7fGtKDn3Ke1+WIxa8d9QiXkA/LwoAaWitRgA8OKW2Fx3/e4Q7QhQKrCbPNaIottDnzBm4YjQn6m+aAcSxVpHY0ZaOG3v56g/XeWBKf9/+sCmVuZHN0cmVhbQplbmRvYmoKMjEgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgMzMvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDE3MS9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCA1Nz4+c3RyZWFtCgAAAAAwAAEAAAATAAAAOQAAACEAAAAAAAAAAAEAAAAAAAEmAAEAAACCAAAAOQAAACEAAAAAAAAAAAAAA//9/wL+/v7/ZBLRMpFqN1M2R/XCZeeYnXET90wCV6ff5cK2wNJSETkuM4C5AcqSZHrJ6WVCDjiAOiFcSepwoEHI2hQFjdqPv3LtxYmXjTT/Rl8vzglij4m+OPOp1S4mWSFm0GBFOlR2anRFDKv/rAplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDMzL0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxMTYvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggNTc+PnN0cmVhbQoAAAAAMAABAAAAEwAAADkAAAAhAAAAAAAAAAABAAAAAAABJgABAAAASwAAADkAAAAhAAAAAAAAAAAAAAP//f8C/v7+/1RzfFbjwXQu3p5uDDBYpkLQzTImSpx7nB9mHEZOKw+t338QvlB4ilGVYzSS9j//rAplbmRzdHJlYW0KZW5kb2JqCjIzIDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDMwL0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxMTgvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggNTY+PnN0cmVhbQoAAAAAMAABAAAAEwAAADgAAAAeAAAAAAAAAAABAAAAAAABJgABAAAATQAAADgAAAAeAAAAAAAAAAAAAAP//f8C/v7+/2OjPFehuRcZPf8y7dJtqcWMhbdd2S75N0532jJMlYpuKIHLyOZujVUh+nMBOMFqU/+sCmVuZHN0cmVhbQplbmRvYmoKMjQgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNTcvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDE2My9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAyOT4+c3RyZWFtCgAAAAAwAAEAAAATAAAAHQAAADkAAAAAAAAAAAEAAAAAAAEmAAEAAAB6AAAAHQAAADkAAAAAAAAAAAAAA//9/wL+/v7+yc5xXLiMTc16G7nS2Pm4HGQ5ERTRTPrLwOXv3yCdTFCZ9Hjt0r9+JeJLzsZJ+cyGWm7m2HGpT+5Ypb1JLZlJ/w52RAzBLE+lEI2YP7kMmOTGLh2+ifg+mot/AvaV/6wKZW5kc3RyZWFtCmVuZG9iagoyNSAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA1Ny9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTAwL1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDIyPj5zdHJlYW0KAAAAADAAAQAAABMAAAAWAAAAOQAAAAAAAAAAAQAAAAAAASYAAQAAADsAAAAWAAAAOQAAAAAAAAAAAAAD//3/Av7+/pzRFbtKLjlgz9KpULob2XpH/3//f5t7n/zGNVXLHVX/rAplbmRzdHJlYW0KZW5kb2JqCjI2IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDU3L0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxNDIvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMzA+PnN0cmVhbQoAAAAAMAABAAAAEwAAAB4AAAA5AAAAAAAAAAABAAAAAAABJgABAAAAZQAAAB4AAAA5AAAAAAAAAAAAAAP//f8C/v7+lJta2ouUv5QYEf8Yr6GBgiDdUEu9Bikc/IsqqL0/X9gnp6SLJ2FO4Kk/1hU26+qnegw1szaTkymWEnsk4ayXhAgJ0te02Lnivf+sCmVuZHN0cmVhbQplbmRvYmoKMjcgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNTcvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDE2Ni9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAzMj4+c3RyZWFtCgAAAAAwAAEAAAATAAAAIAAAADkAAAAAAAAAAAEAAAAAAAEmAAEAAAB9AAAAIAAAADkAAAAAAAAAAAAAA//9/wL+/v7+yb+crL6sdgq+L0fuft+86P4UW3mxF/kV0o6UCduljKarUWCFA7PrbdMdyOSqnARD5AvZB4hP3Iei8yXD/2z14C5o6g59QHn6/xQuMZGMfKPgbP35hRdiDI6AvJVmW8Wr/6wKZW5kc3RyZWFtCmVuZG9iagoyOCAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA1Ny9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTY1L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDMxPj5zdHJlYW0KAAAAADAAAQAAABMAAAAfAAAAOQAAAAAAAAAAAQAAAAAAASYAAQAAAHwAAAAfAAAAOQAAAAAAAAAAAAAD//3/Av7+/v8LppetMyJf1DP0Udh8iLAsFc+kmIv8ZS9PXBger4LArCrrBjpZMF+BfoDv0bmM17nSJLE8BkVB79k6pkQoNaaNTAMlX2II3kOG6UVkvPJEC1AoyjrFfE3uPHQlR31mr/+sCmVuZHN0cmVhbQplbmRvYmoKMjkgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNTcvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDE3NS9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAzMT4+c3RyZWFtCgAAAAAwAAEAAAATAAAAHwAAADkAAAAAAAAAAAEAAAAAAAEmAAEAAACGAAAAHwAAADkAAAAAAAAAAAAAA//9/wL+/v7/BkcQs/uxPyVFZIaAiPV4kFXZotCtD+smUpbo4roN5FJfxH5ulORWfMfeb1H/T4ky48xT8Uqmp0kdALWAu/wpwSz8qouILi2FDVKeS/1NfmmElFeLYJMsD40rwTXq97K+ig72YLimqI1v/6wKZW5kc3RyZWFtCmVuZG9iagozMCAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA1Ny9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTI1L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDMzPj5zdHJlYW0KAAAAADAAAQAAABMAAAAhAAAAOQAAAAAAAAAAAQAAAAAAASYAAQAAAFQAAAAhAAAAOQAAAAAAAAAAAAAD//3/Av7+/v8LqdPyZqOpvOg7uwmIEjc3E0W3VAJQbBt6nivJdLRLJdHUKxE50KftSbeBJGOP4M5AZkSanVe//6wKZW5kc3RyZWFtCmVuZG9iagozMSAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA1Ny9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTIxL1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDI5Pj5zdHJlYW0KAAAAADAAAQAAABMAAAAdAAAAOQAAAAAAAAAAAQAAAAAAASYAAQAAAFAAAAAdAAAAOQAAAAAAAAAAAAAD//3/Av7+/v9KnEqhgacsktAIYf9s3zDgL11gyIhjyzUZfS0YbcdZqfutf65g9ZtOR+MvSjHEtc1VTH//rAplbmRzdHJlYW0KZW5kb2JqCjMyIDAgb2JqDQo8PC9CYXNlRm9udC9MTlVITkYrU2ltU3VuL0Rlc2NlbmRhbnRGb250c1sgMzQgMCBSIF0vRW5jb2RpbmcvSWRlbnRpdHktSC9TdWJ0eXBlL1R5cGUwL1RvVW5pY29kZSAzMyAwIFIgL1R5cGUvRm9udD4+CmVuZG9iagozMyAwIG9iag0KPDwvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aCA0Njc+PnN0cmVhbQp4nF3Ty6rbMBAA0H2+QsvbxcV6PyAELMmCLPqguf0Ax1ZSQ2Mbx1nk76sZh1uowYHDWJrRaFKFYzyOw0qqH8vUnfJKLsPYL/k+PZYuk3O+DuOOcdIP3foS/na3dt5VZfHpeV/z7TheJrLfVz9L7L4uT/JW99M5fyHV96XPyzBeyduvcCo+Peb5T77lcSX0cCB9vpRtvrbzt/aWSYWr3o99CQ/r870s+ffFx3POhKPZVko39fk+t11e2vGad3tangPZp/Icdnns/4sLsy07X7rf7VI+58Hi5zQciqSoi2RDa5Axrkgx6UBOQ0wJgTGXIipEUM0NKhmUDyBpYU/GPAN5y0CSNqAYGxTnqMRRAtXQTbVAGQFSHLM3CbIzzTwoNR5kqCrSNCqUSCBGE6jGdmgRKSjVUJl2Birj3MPZdbAWFAXUaQyFOnnSUKdxokH5hLKwp+A1ZDfBQHbhKXTCygidEClpkAu6SDKH8nrTFvOvWLKbILssBMUGMkjV4J7Jw55SS+iLo4yjGoXycFppEpzIsQAnkkFDz5wW0DNF8R5cjfegaDAoB3ekGLWoaHFMXvMAA1OmmnxOY/dYljKIOPo4gTB7w5g//x3zNJOyCt6/uOTYtgplbmRzdHJlYW0KZW5kb2JqCjM0IDAgb2JqDQo8PC9CYXNlRm9udC9MTlVITkYrU2ltU3VuL0NJRFN5c3RlbUluZm8gNzAgMCBSIC9DSURUb0dJRE1hcC9JZGVudGl0eS9EVyAxMDAwL0ZvbnREZXNjcmlwdG9yIDM1IDAgUiAvU3VidHlwZS9DSURGb250VHlwZTIvVHlwZS9Gb250L1dbXT4+CmVuZG9iagozNSAwIG9iag0KPDwvQXNjZW50IDg1OS9BdmdXaWR0aCA1MDAvQ2FwSGVpZ2h0IDY4My9EZXNjZW50IC0xNDAvRmxhZ3MgMzIvRm9udEJCb3hbIC03IC0xNDAgMTAwMCA4NTldL0ZvbnRGYW1pbHkoU2ltU3VuKS9Gb250RmlsZTIgMzYgMCBSIC9Gb250TmFtZS9MTlVITkYrU2ltU3VuL0ZvbnRTdHJldGNoL05vcm1hbC9Gb250V2VpZ2h0IDQwMC9JdGFsaWNBbmdsZSAwL01heFdpZHRoIDEwMDAvTWlzc2luZ1dpZHRoIDEwMDAvU3RlbVYgNTYvVHlwZS9Gb250RGVzY3JpcHRvci9YSGVpZ2h0IDQ1Mz4+CmVuZG9iagozNiAwIG9iag0KPDwvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aCAzMDcxNy9MZW5ndGgxIDIzMjA4MD4+c3RyZWFtCnic7L17kJ3HdSf29Z2Ze7/nfT/mAWDu4AIDkAMQJEEAJEWJI77EhyjxKWFIyQIIUhLXkkVZsl6R1rTXWilw2XFSSVWyu9l441on/8QZyKk1JadcdjZOUrVrb2XL/6TKW3FVKnHiXTvZqvUjVVtGuvvr3/1+90x/A8jWxvK6cXHmfl8/Tp8+ffqc06f7+26koihKorejpaj71g+/8dbzz3d+N1L/qU5sLH/66pfe+vwbnZ/VN3+iYfqpz1y7mn71//2DSP1nvxqp/+5ff/LTn//SD//cE78fRWo1Uj/1R5/85BtXG+rDPV32tzSc0Lev//E/vPN39fXf0XDxE5/68sdfuPHle6Kl1/7bKDr1Wx9/6xOf/vXX/5s/itS/142i4g+ufeHz0+XvqN/Q+Jd1+e9EhraVC//wX7x2x//wsc5DfxhlJiGKfuk/fuRt8/07yed+7+af3vxtnfrb+jaPGlFZwPz97Zu/HZ1Qkc7/YxW59Pm/D73bpLz1K+rHontsQiPqRueib+qLf1b8AVDYf2/P4R4NfQ2GWz3LsRLaGi5pyFxe5tJiV86k5RqOaig0dFxax6V3XR0Dd2s479JQ39RJNTQ0LLv0FQ0tDU33bdJXHd6mK9NwwGmxawd1ll0Z4DJl79UwcG0fc30fuXpNR3fH0dh2YOpvaBi6NtYcb2LXx5brR+xwdak9RXwzbV7U8JCjIdXjsKrhgxpe0LCl4bSG1zTcRXzrEvQdmPZyXe6E4xcgE2XBl5zy+3QvwY6zxvu8o+mMhoc07Gp4t4YL7vouDQ9q+KiGe931CXf9iLs3fblfw0V3b/DcoeFODdsO36MaHnY4n9PwquPHkxpe1vCDGp7W8D4NT2l4xtH1nCtj6j6u4SWX9h5XztS55Nq/x6U/6No55/qx4coaenZcedPfk+7+AUfvRdfOA65/Oy59x0HuwKQdceUMbRPXPmh7xvXN9OVF157Je8LB+1xf3u3o/YBLf78r/wGXd8n14zFXZ9vR/B7Xr2cdjy46fGYsYw3XNPyChpmGL2k4rmFdQ9+Np+HLVMNRDT03tgaHkYehhlMaMgcmbeD4NdZgZHmk4Yr7/piGux0/Tjk+H3G4py5t5q4fcPCso/UuB59y36h3lK6PuPp8f8LxPHH9vRWk32O44vhuxvRp15eXXL8MvOx4fjtg9ELk4Asa3rqN+y/QNedzue8mX4Is//0GJxwYuTQyveFgStB2cI8bE1MPsmTG6r0a/r5L+0k3Dn/X4f3b7vuvu/JmTvwXqpz3X3Z1zLw0OsHMRTMnzZx/l7s3smzmr5H9TUfP/a7+M+7a4Dfzycxjo5egkwwOo7+Ou3ZNW11Xd+LaOu7KGrz3ue81l2faM/r3nLs3OuOowzWl65G7n7i6ptwxV3/NwYZLX3fwblf/hOPLu1xfDY4HXD+ecH0xeU+663U3DhddmycdnHNtvNf157zr2+Ou7LtcuXtcuR3XLmzLeUfvKdef+921Kdtx12dUJSumbt/RBF3aduXajm93uz6aNCMTb6pSPx5XlW4y+E6rSu6OOVp3XZ/PunZ6jq6xgzsJIDPnHA8NvgtuvE0/jI/wlBtfY4uedm097Oh/r0ufufYvOFxH3Dg96Pq+4/CfcHlj4sl9NP6PuPY23Xjd5753Hf/7jsa7XHvHXP/WCNeWww3ebbrvTzm+mTq3pWPhIzocEo6ral4dI9hyeWYcP+b6/oijB3Pm33e8v+Dqb1I92KWX3fXTjs/Q6+9zY/YBVemZo24Mtty34ckdbowuum/AGZf3quPX3W6sIVMod7/7fo/7vsPBUYfjrKP/p1Q572aOZqPjfsHRB3/AzEfji3zY9cfw43XHIzPeV1Wlz552aab8Rwgg16btxxxO4+d8Q5X60PTDyMc5R7uhw8jFD6jSx/20o2XL9elNh2vgxuak6/9Jx28zN7/o8MJfOevwfkbDV9z3Z9SiXfhu028HviyuFcHt+B51MHLf/4sqZfCI6yPD3W6cjWz/hCrn4+dVab/udXwyfDQ+qZnHhSr1mLnO3JgYH6nr8kbu2pSfujKGBjM/f8Rdrwg6D/OxUH/HXcNPhu0A39Zdmrn+nOvrW248PqtKGTPfn1Sl72rk08jNq64c1glGhl9w37g388LI4vOOX4+5+g+oymc87+iBfjE68D2Or19xPIRfN3Bt/D1VybzBa+aTmTORWwNjbdty60WdfvMmrWvTqFpzL7l14rFybXjzT/X3xK0TlwlPy1133XqyDrAWZpgISF3ZuAaWBKy49MTVZUCbHdfXkbtv0doV63H0fdl9Iy8l3kREA2IMhePH1LVj0iNV+XEdJ4u4L5ws99zY5U7eO1Qe+bn7zlxZ+Q3cmRt/4OoSLswtrIvarq7RU+9313c5GTnu6mIemraN7jPzb9XhN7I7U9U6piA6IadPuLYH7jtzOAqXlhFtW6pan4I/Y+oHcGaiTOroeNSVz135joMN16aZv0PX7pT43HVtJ64ufC/omaHga8f1se14gT4gD+UKwtOm/maO31sOT5/qpzReGKuc2kO/U4efgXkCPnbU4rggjXk6VJUMZS69S+3l1F7P5WUEOX33iYZ1Vckn+JG4+1hV8pxRekr1C5eHejmVA16uBxpS8c30Y46cUpWccP3MgyultlGfr2FHGD/Xw1zLPSD7n6nFfhpouTY6apGfXFfSxPexKCd91Vwt8pNxyP7X0c7piUhjOeH7mK65DPqeEPCYQ38yTdw/X198/JJyBfoKqpOK9mU73CduM1cH6ZEyWwic4HVHLfaJcfL4t9UiXQXlMcg08B6yIenm8Wb8rHclPpbdXNRhGeG2JV5fW3JucP95fDg9ETjrdIKk3Sf3cr7JuSPHTtbjdn31ecwz0T7jZh0r+SP9gUQt2hNZz9dfqbuY54UnTYLUmVlNWV/f69ITcS3HxafPfHpL8qtuXmeiLR/NkGPWXTHhkjRJnkpauB/Mu7imnuT3YXIg+8T2rE7H3kpW62gAzb5xkPT5+lLUlJXzgPvMds+nZ+t4xnT6aJOy4ZPTpKadOn75dJjUvdKO+8aKv+t4dSveSbmr45eUjbq+8VyQvgt88IGq/NCxqmzfqlr0nbHe4XUP4pDwn+Gbdl0ebFKmDvq/TJeUf7MeOO3ued3Vp/IDKj9Qi2upjPqHeqAhU5WPDf6aNRXi+mbNf5Ku0YdNGlvE9ji2ZGg4oqpYCOgw/BmqyicAPaB5qKr1DMqmqlp/9Gm8sHYqCB942Sf+8jeuU1XFatqUzz69XFvIMYMsdKgvSGsTcLugF32AbHfU4hjJNTQDywzsMfrfpTzDO8SHjPxuuTGZunZXVRVXxxrDjNXfVJWsD9VBm8u8RL/go0l9B32OvnZcu6xPOnSNNTn6I/UY8Bb0DV72RNtsc6Tekr64wTMRZTAeiN+tufR1VekOjFXh8lEXaT77Zr4H1K5ci7AdZN5jDZjRfezGqCPqQVdAbmNKB78hK4w3oTzIlVzzsRz4/HHpgwDYnrXV4vi3Bc4etXuYvwu5gzwz/ewPsjxx/1AO3+BNQW1M3HhhTkLufWsD0DwS9ftqkY8s89LGsf/nW7OxresSn6VsoR63xTLRJ/ywK9w/8A95iBexjYL8YmzZthl4kNLWXJmjbqzW3PfY8WhMaUYnrRPvEdeW3wNXz/B7SMB7gUMag4lrf0xl+q4MYmQ8H1juMebQ8ygLXnNMif1E8InjSCbtU4TH6OX7qK6x98bebrt77PF9XZVxd1Nvpio5NfQfo3aPqkonSlsFu5+6diFHkEtp/zjGJdd/mVrUc3LNyjpOxhm5HY6Dsj+GeGSX7rsCV0r5XQEmD/E9tr3ACzp43MGrXC3qAfRL+tTwZyAb3GfuN/TPGvWbcbEfcY9a1FFd1w+cGcDZAsyR3I3/GtGOvq+7+vAH4JuturrYS+2qag7A9524NMiuqWvksq8q+YM+MWWN/zdyYMqccfVBA3y6QlV+KOLnR1Q1j8c03n1HN+YyfATQv05jP3FlwPuRK492J64stwFfc+K+d1QVn+f5wL4/9AX61HZ1Muo/dBuuh45nSJu47w7hBR1c18CGqmQB+q1H910qyzwEz1ZVtT6BDwZ7CR24pipdCL2K+Dj4BsBeA8YQuhT86rv7VUHrhNJAe1/gZh6iLdmnlNK7VBZjApuCscE6AmsIc7/lynVVZTM3VSVjwA164R8ORBuQK/BgSHmgYUJ1wFfuD+jnMYA8gBe8L8RrE4wf1nwdqg//lNdLmA+wh31qC2PYd20O1OI+3ZDwtKkN+L7gGfjWo3vI70BVcxR5aA86CtfoD+gEjV1V6bKUyk+oDOqDf+DTgNLaNLaYJx3Ch/1A8AiywfbGtH+MeMe8QbvgJdcdq2qNCPsyprqQO8wl1MN8wrqfed4RgHyfzsDcQx8hi5Bl6EXYSsxd1luyLyNK4/nHOrevFnUm5BCyxPeQf4578HqS8YM3bSoPeeU52iac4AP7N0z/hNrFOMBnGKqD84x1MGR2RGVY10v9BRtlvtfVon6BLcN4jlUl+6xfeBxZL/K8lfI8oDIjtah7mF7EcXhceP8ZuoVtIssl0tqUBtmSPILfz3EIzodOH9F9W9RjP4PzC8pDOs/djshjH4DLrFJ7cnyBk+MqrNOwJ88xItAMmYOMYhxYR7AvJHUK+8GZWtSjoBP0pCKddRfs1Ugt9o3tNa+1WJ9A/rGuY7t4hNpnW4j6sAe8RoMvMRZ1oaNgH+GDZWrRxrIeBo/X6FrqaJx3ho5FPq83sMaHP4rxkG2assYvxllKnKvEOUrjE+JM8HGXZuY/zlzizCKuj6vqbD7Os+GMJPBsODxTd43ztHyWc9O1jWcGjlJZnNPkNkAv7uXzAxvuWgLW8hsi7agbgyPER8gZ/A3cc4wE62mMMccJc5HHMV6OB3E5XsvJPYO6PBl74XSpO3j/G/PMtw/H9HGsQNLii4ExncDNa3W5J3MY+OKmvLbF2MhyvJaGLZX7Gb79DclDXmfLGKOMMXB/fHFWridp4LmLNayMuXGb+O6INOYdjzX3UcZDUd8na1xH4pdjnKmD/ZTxQsaZedqE7wIZhC3i2E6fyku55/nIcWjmH9PBMW5JH+OU8iDnAssmx2mkvpDzmGOUck7I9mUey7ZPX3REfZYzH++ZHh7TtqrnF3iC8oi9wkcFL3xxeY4NZR5cUsakroLeY31WiDSOkfl0D++dsEzW6Sjc87lA1OczYwA+kyDx+eZZW5SRsdCeBxfvXfAc4DGUZaVsMT6sZ+RcYUBbOGOHdRLns/8NGcWaG/HOvqr2jcBT1D+iqnUF6wCO4aIvaK9OruHHdaiOSZfr3rFalBfQNCTecfwNYw+6OJ7NMVxO5zW2T2+yPHJMn2UaY9MReFnXsR6CTLC+l3ticm5K2eA9Gim7PlsFeth/4HZ984v3KNAnOXdl21JOfeXq5JnX76xH5Pz36Sa5/yXPNHEZuYfom1M+vrN8oA3IhNyzi6mMrMt7RVI3yfGQvJb+Ya78PGY/QvJA6jnfeMnx9PkVrHNkHtIlnRKfnAtcP1UHZRzjx3m5uAdOyK30lWRfDrMzfK5E8svnc/hknsfFJy++suiXXIukoryvH4wD8x36DzqT++Lzj3xj7qOxbu6w7NfZAt+YgB65L+/D77PloH9IaTzP6vQUYKAW6feVYzkGjyV+LherRZ3j6xPaYrrr+uSDuCaN60D+pL7MRJpvjrIv6Wsf45yK9lkP8z30HNfPBR4+lyfHW9oSed6U5RyxMKn7pPzkarGvTK+0/dKmMC2+MypGj5hnNk6rynfisYXM8/kAvuaxwZkd+Oxt5edDrBZ1SKIW1+JyTY4yiNvGqvLhEbOHfwl/jeN+4BFiY+xb4R59wR4y/Lk+tduhdhFjRFmOiw4oH7HWCbXJMX2OVZqya1QGPEK8HLQhD7F68MaUQ2wqE+3w/gbK8p4/9m6wb4I4MPME5REDZR8bOMEn2CWst7CnDNw4x4F9vTVqm/kCeYXvzmfe+HwL62XMDcg7aGqrxXnH59/AI+DkWNAptThnpZ5E/yGbLMP8nhHgZf1U5wvBxuMclrRPrEcY2O8CTW3RDuYC5jbz0xf/YF3AOkDiQVs+W8i+lon5Isa/pSqZh8xgDqH/kAvs/SAmPlXV+2d4PxbzAOXxfGVB+IC7Szj5PPS2qmyuqWdiyScFHUzDwIMb+xWow3sFA9E+bHyP8CGtQ21C95i5dFQt7mEwv3K12H/GeyfRX1A6P4/J5yo4Lj1Ti7oTtIF3fF4BsZ0+4R+rRV6xjzykMnzGgenDGSJzf0K0O6D7tmgXfJPjhPNq2LNEf/FekFQtygXqSbowdnKvO6M8pE/VIq24TgkH8zCndnBeBPMHuHmsoBdAH2QO6eAx8GJPA3FVlOV9OlOW7UdG7fG+Ms+Nvlo8x8M84jmCvvTV4nzCniT2s+QcYB4C34Twm/xNVc1v6ATwaEY4ee7wXIBN4Pm6SffyvB/XL9TifMBcZP7gLB72AdFvlrec2sGYQZb4vBDrE3keBvab7co60bVB4yf1b+rG8Yyq1kygB/rd3J9Wi+frjrt8nNcH3RyTM/Ns29U9qRbtBstZ4sbLXN9FdG+ryiZDR6Ed0AidAdw458Bn88Av7Mli7xQyfprGGbKxSfhhJzBH+Bxfm+pAptqEn31H2GG0Bd8WMiz9wjbhxDzEXIJfyXvjkFNTH74J8uFLgh4+EwGe4ho0QMbwnh2ORQMvZJnT+JrXEEiDPk5UtTaBjWA/xMc7+C7IY5+sILwoxzFQ9nMKKueL/QNnm67lmo3XTuyvsq8k9zfkGpv72Ka0nNIYmC+JwMFnT3zrUu4L65yM0n00yXbRdk71umqRdt6/BK84hg8Z4bi53OdLRV7uuUZ9yC/no/9Gt8Gngu8A3cznddG3Lt2zDwxbxHsxkH32HWCTgYvxsw1HPq+FOR9tsD+OdQ3uOe7O8reuqjm1TjigK6BHeO0A+nG/SbRwumyT5ZvjByi/qhZpTak+y19CZRJP27k62Ge5PuJvjjX40uRaE+tLLsPztqA6Upfweq0g4LUR2z/gKuia+cPlOebANpj9N4wr8MHmsWxBjiGb8DE4VspnytqEE7SxnMr5x2lYC6MtrNfZpqEu9ADkEX4J85LxdghnR+DgM4TcFmIGsap8H/AQtLNv0ad2wec+tQP9ybqNz+ph7qEPrLvYl8/VIu9Yf2dUB/X53CKnm7ItDy0ttRjHWVOVbcJ5V+TzOgJpiFchDb4IZE7OBZwV5PrwXyGPrCtYFoEfvgzbICl/iLf0KI/jkLBRsj8cE2LeoQ7rCPBxrCpdz/gQj0Q640J8Bus3lAf/EZ9nuvi5SPSJZYGB/c5U4IqpDPgAuUAdqUtZ7jDmmIfgC/O+qSp/kc+RtVQlD9KHQ6yMdV9bVe/qkfo7U4u+NfiKb/AMcoZ1EOY56EkdvWxXYlWtO+EbcyyObYyMy4HPLPcs8+y3QE9Iu8P+G+u7FrWL9TPbOdA2ENe8twEesF1mHBhPPicDO8N0SNuLumgb9EMu2qK8tOOs8zkuwv5yQdfs3/aoXcwnuS6DfWD7BDlgPw50QB+Bzr5ok/1nxoG+SPwst/geqUXZ4Tgwyxefp5F7RkPCx3Fm1vnIw1xCPZ8PgzoYZ+ybYczBB+Tz2icl/OxX4R5rTu4f94n39FrqoLwxrp7I69C3yd+isUYdbpvtSSHK4nkG9n3ZpvKZEN5P5DEEz9GnFvEZ8xsgzx3xXIEd4fUG5oWUO+lzgv+nVSVj4B1sO/B2RB2fzPJY81ixr846xOcXp4RDrsf5HaJJTb1U5Mt7TuO2GB/bGva5JW95/0a2zfeMk9vmNK4j9519Z4MkwC4wDtYF/M3jKPUPnwmWe0mMg69l2US0Lec520fOY9oLT5pvHvn4wePFtgQ2thDt8zj75i/zimWuoxZl1CeLUsbADzm+vvMQXVHPJ2cS6t4zJ+nwyT/r26QGD8uunGeJKCvnr48OOaaSXtYnTI+Ua9l2He8lbSaNz8Own4X6vnGQtPL4Z6IdX3/rvutiI4fpubr+M298sQEfXdy+Ty9mNfk+nvh0m/SJffyskx3J2zrZrsNdN3Y+vc10yDZ9cu/Dz/q9bsx9MTLJPzmWcrxupRNuZ9wPmy91fWBZkHLh6wuu5VlT1JfxudsZ79hTLr/FteRV5gHOk3NH+sRSNnzzVtLi06tc39f3Oh2aevDW2Qu2ex1Rtk6fSDqkT+/TFcxrxHvkfPDxxifnsajLtgD0+PhQNxdkXt28lWly/HnO+niFvnO9WOTLecE+E/vXWKujPO9Fy37gfQXmGusxjhnIM+ocd2A5kXOF5Zlj1KYM3uVSx1ep46T9Zh+S+44yiH2yjMpyPLZom/c00S8ZY+d2U7XoR8v1U5fuEc9lPvtA7pX55iev01m34LpP7fCYSFlFP3lu+3wHXuvKeSfrHKaH5VqAY1zYMzc0X3Q0mTNzZ1UVJ8R5Ex7PVcKDcxt4LwVii5laPA+EfTPsdZu0maMTz7bfoaoYM8erT7k65lzCjqpi/AY2XDmcV0GcH/3GXiDLA85M8vsqIGM4i8JnBu6gNOwZ5Kp6XhzPkINHvE+BZ45wLoGf/+azpvxuFt53zIhOPreF35KStOIaZ0f4PSKI1fK5nx5d4+wD5LlLwHs8fEaC9xzx/kJuE3F2lEM9jB+fuUAf+tTmOvGOzzGkqoqLA89QLdLG59JG6iDdHbVID2QW+bJMTteMJ1WLfMLchg3YEP3siTbMNd6RNBB5XZc3EHm8X9JVB+lCWyxbkCd+hoPPc0CeICtIl2cDzdmfO1UZl8I85XMq2MfC2ShzfU6Ve/U4z8lnAvhZu0Qt7j1JWwUbzHqV7QTeF8vnGFlHsj/IdpZtHHgDvYF6iLWxzWdd7vM3OH7BcUvpg0kfkPMSke6zz3wt/Reff+CLmQAkXT4bI9dFbKOYx9I+Az/7EWxHJXCdvOaaxyMT9+A3jy3LjtyPQL9ZpqRvznQV4h7jLH0nfBc1ZXPCJ9cIPh4z/ZkoI/0XKfsyT/ZXylAhcMq9JV//5RhlanGcJR/ltW8++XzT76Yu0qBD5PNFkn8M3KdClOOYl5wbUh4T8e2bYzJeK9vjcff5hjLOK/e1UypX5+9KfcjjWBerkvsbfI8+yDWBnHdSTjuE57AxhZ2Ruky2zf1iPSX5LGnyrTkZ5BzkcfbJZ1sd5L2UZalffLIg9bXsI2hnHVaoxTmNMlIfF+LeJxOy/9J+wZZm6uC41NkyOY9zgV/KCLeViPZ8erhH99yWvOcxkTpZ0sTyFQucXM+nZ6RdYzq4v1JXSBvFus2k8Ts6pAyyDDA/+Vr6Pz4eSZnmvrGulLaP6WCdIvkkbQinSV5malG+pS2VbbPsyOe7pN6UOKT+lD6Tz69iG+jz0TLRvtxnZpzSTks5rZubdXE3luHD4msS5Hj59omknr1V/9CexMX99OliX5zRR2+LrnHvi3nLvrO8+/CCZuaVz3bwPcdK5Rj68EPWQDPHXvk+EeV948h126Id3stvUj+4jxIStXhOgsfCJz8sG3xWxccbtlMsP2ib5VbSk4i0QuCW8Wrmg+SVb9/f18+6schUPe8kTskTyVPfOMq2Y9Gm7LNvbGTdW/XX11eZJvHErn8tTz2fnPrm0ndDw4jS2fcH4N3tA2oXvqepw+97ZP6bOMOaWuRfKtqKqa4v7ovzST7bEXvahPy2RVkpf3JMWe+hjnw2gc9IybVqSvk+Hcx+GJ8H5nzp10AHSN9G3ktfWuZL/xCQizJyjOpsCeM7zJ7wcx7cN/ZreJwwbhzzknsdLB91sRHmyTaNy9Dd45y7b03h88V9/hyPjaRNyjtg4MmXcog64IFPLuQ4Ae5Q5fOGM2pL+sDSp2L7V9cPyQ/ZP8zFtjrYb5xT5XFBnzhGLJ8VylUVz+5Q23zmtiOA/Vt+XkKuXfm5ELn+As+5Pssh9jk4dgmcci+yLdrrKD/9pg6eUcW5005NG755xHj4nulmnZaLb5Y3xHL5GTWfTpTrHLTBMQnQyDFd5ovcA4FMtKmcPIMJ/Dj37OOB3Ifl9QWv33msWbY4JiflCuXk8xOyzwDuC/QdtyOf8ehQGveH7Q3zmPsq+8mANVxBdXgcZT2MJfeZ+cxrVsxrPmfL3xJYznh8mSZO47W2Lw4jr3ne4Jr7wrZDzn3UZ/3Lfcc84Lkl+cnzROpv1g+Sdp8ek/zpCJwyVsZ0cLxLjgnrtg6V4f6malG+ZWwb+EAD671cLfY1FjyR8sw4WKfL/jPtcmx9cs48lbxN1CL/fPhY9lGG9S+vDVGX7S77ilIXc3ssM1xO6qmOKOfzFWUeyyH7imzf+VyADxdfyzhXRy3yk9vFPGE83DfmNcftuWyLyqAu81ae82c9JGniPoN2H7BfxLiZBqmb5VwuPNd1ujkV+HiuJuqg3DJeng/gC8sR5rhcI0g+Yz3XpmuMo5TZVJRl/ZxSmx1VxUWk3uW5J+mUtpRtIevmluibnLPSv5N+ghxP5g33J1WLa0Qp31irF8Q31qscs5M+N9tb6atzf5tqcW5Bp3L/O2rxWUTQCD6xXpN2g/1+OQ8x3swDnlcralE2+LlDXHNcruXqNAkfeNCi9hEHkWsSlOE5zXl193Xrr1S06Vv/8NjKuj58/Awm+MD+klw7+vqSqoM0svxJWWF5q1svsl2WfgK+5d45+xYxtcP2j4HryzWktEeSF+zb+nxaxin3erm/rHNyT7lM4GceYU6zXZZtMF1yLcR6RLbJ+kv6CNIvZN8AaT7++Hjns3mFuOf5LvmXetKk3EleyLTDeCfplP3riPakjWU+pQIP+5rsz/vakvIi5V7yiOca4pNrhA+2bENVPjbPKdZxGFf41ohTMT+hO9n283Os0kfFN+LBLEuYmzjzBhslx411IOOKRbuYg9A5HMNhGWI/g98vCv7nalFemdfcJscH8bw7cK1Tu2wfeM0tdW6qqrNuyG8TDpZ7nl9NooPnJupBf6RqkZ5YVWcNOR9+Ukz4TPqY2gQf+Z1D4M1IVXF67jf7cRwvN+lTcY86iB3y2W+WBakLIM88bxOiTdotToM8xwIv7tk+sCywHYmpDPssqMvvqeV9Ll6/yedP5Ts7+L2FrGNNWby/UOoPqRtZxkGr3DeS/eSxSdTi+yzBZ8jWhHBKXcz4+T1k7JNB7uBzMa2S3zG1C93FPijPbfQHtPTVIl0+X0XqAC7HcygTuHneStuMfvHaCX0w1/JZStb77Lvx3hzKsGyBRrm/irLsM8EvxJyTe1PcTo/wMg0tTzqvSXw+Je//pWpRDlhPyL1CyLzp7wmHT+414F1hHXe9par4kfnm3x7B2XE+Ey1lH+PY9eTzHPPpqFSkow7OY/t8GoxRIepLn4BBxkQSdbAPrBOZTpY72Eh+JwnqcPwtF3X4GR6fTukTbsg70lCWdS3TyvYSZ96hL3JV7YlkoqwcE3nNbcsxTDxtc/rYg4P1AO+lST3E6Ty2Uo/4xtk3l3x2Ubbrq5OJbwk8jgN1sF8+fqHMuKbtw+i+FfjGkvkuz05w36Qt8smE5IWcf5I3rL84hiZ9R26vK3CwjqsbHx+P63gnbYCc77490sPGgn/Pm2PzrAOgV3m9w3EttMkxRfaP2KdJCA/7Laxz5dgxv3Nxz+slXutBZ3B9uRbBN/w0qWNYZ/n8rkLg4XUIaOI5inJy7Sh9VqnzE9G2lENe6/DY8D4Ijx/vVbVFOdRjO5CKNqUsSLngssDLvJW8Z7pkH30yzGOAvvcJX0fg7qrFvvhkwGeHeX7W6RKpl+VYc3vyjK6MkQEPP0c7EPjkPGA+chnuP8udnE+y79Km+XSUT4/FhJ/ndh1PffpZxlCkfef54Jsjcq4zb+Q8lPZN8qJO7mSelHmZh3psVxO1OK+wJmY9Y8rwO+og4z655GdsU1ePbeaIyrL9YL3Oz06iDX4WkeVyINrvqMWze1Iu0RdeK8u5n6rF9S+e7d0h+kwM7A4HOw7MeaTTqnovPc584H3lPYfrtKrOfqyqar29qar3mI2oXfxeNJ7NBQ/xDCUAv2cxIpxHHc14RzB4aOg6par4FNaE/HvsbKdywsO/S4C91Jzq4flbPBOO/uC57AnV5ff98btX+WwM2ud3z6MOr9F8uoNtuc+e5546vnmUeXDW6Vo5tzEvOB7t8zGkLpK2heeRnD+o3/Hg8/loHNeQax8fSHzS3+O9q0wdXLMDh9xvkj5kQuWZt8x75h3HSWIPzsRTxldWrjVikcZjxjRknvoSv89P9pXlNg6jt24cJV9lXaYzF3h8Mstp3B7LjMyHrLfpGvrGzPVzqvpdD6Mz4StB/xndsO3ow/sZ8Ez8qquzrqrn0PHeA+jIjqp0GN4Zit/H4PcqQL9uOLyr7h6/Y4V3lyKWw79dJNc1PEcTqiN1h8+3ZN9C+rvwVeXa3edHJyKN91j4TBDHCfGNGCbvmfB55rao9y43BrBnGL/c8W/i+Jm6awDi9vAL8K5+vNuBxxLjA1ucUjmUxXv9gR+/VzNxdKSqekcJ3gOM300pqK0O1UOfgAPyh3zkgT6822FM5eBfoD7TOyQc4A9s/IRwQh7HapGHwLkmcMG/YDrbxFM8n4AY1ogA82ZAbQJg04EX/duk9pDG76UYUh7aAw7wx4CZf4jh8JzGnh1kBengz0DwAGV6gk5+F8qawI82C6KNf79uLHAP6Bt8Rb8wxmO6Bi5+/wjixfzuD+bVmHCMqE3wJqN2+F0c7EthPoNPeG819BHe8cW2APTwmUvfGpLPF6Av8EtkbIVt+WH22Wd/5RpN2hu2UT475kvz+TTSj5LrIZ8N7Yi2D/MBpY2Q/pT0Wet8L/b7JK3MV17fyX7CHtTZe+nvmm8Zr2dgPvhozURZ5pNc83N9GVe7FX/YV8zVQXpkOd/aXdLDe9w+fFIupDzk4jpR9f3lfidq8WwTy06dfybnkc/vKDxtSn/TN9dlW/xcp5RruU/Dc9En60j3nWvxxci4TeknJeJalpexF/7NDOY915XPJfO6gGmtm/M85nw2Jqf22uLeh5dlgfsj/UcpX5mnLkD6gBIfz5O69uryJA0+2YCdkngSDy45tj4dchigbN+TLu0Nz31fvD0VZevigAbMXrCJCR1343yC8tjO8m80IR3rJ+wH+GRAyp3P3kiZ4fnD/WI7xnqIcfG5EdkWQ0+0VSc3pn5X4JSy7Bsrnz2qu6+zvxxHYl4Uok1J/63mhNyvkPMIfU4EfjlGvnZSTztcVtoLXx2fDEs++erI+cB94/5i/YRY3xG6ho9q+s++PP+GJr+PcEMtrq/497CxPgculENMEOsrfuch4rZYV+CcxapapANtMKA9rIvl746yD82/F4rYB95dmNM9++sTKtMl3Py7n6gr7Uin5p73u5DO+6sDtTimcoxRDvyTzycmlMYyIWVWngvNKR10Qjdz3KigOkxbrg7+/hTKjUU5396jfG8i8mWsW9ru1FMPdRCvLjxtp+K+pw7ymc/3mvShwMP2QPLE91yKlAPGk4t6XXVQpnzA/eB1oGyHy/BzSzL25HtWKPWk5aJ+VlO/K+pwWeyPcB7qdEQan6HlcQDw73BxO9DtjIfvmRZZPxX12uogrT6+8Dj4eAj/Qo4H0yzTB8pPq68fdc97SbluU1me31KWUI/XLW3xzdd81pn1G3/7IKtJh0wkoizrB9kPtI1v1pUSP/tQvjK5p05HVXLKc5j9aNiNNl2DHtkG/44W86lbk34YfSxzPH5ST7CfIeWJ86UvmKhqvtX5XNJXlDhYf4AGn643wGdtc1GGy7E9QDrP3bo+3cpvvVV6XZlcpB0WL5BnmH34fH6mD/C8HdsS823WE/CXeJ5KWWJdweMEWUY91oksN+yHApf041O1OI7sd0j/CbqS97W5X9Dx/HuP0vdmuWObznEeH79lmYzKQR9iX9XXLut0Xu8gZoGzrHKNwHxnXjJve5Qm3yfoW+Pwb4wzfTm1Kf0vHmfpSyVUh+eatNvSdiBd8lrGdLBWQJ84jsZ0+2I+MubH4wI8OZWV/nJKY9qiMrheV4s0s77jZ0p5PgKadM3PefB6n8txG5Abbtv3zjyWI6T59p8lv+r2tRGbw1hzLBnXPbVIB3jJtINP8n1XvnMTLcIhf6cwEemmPuSsEG0Y6AvcLGdoB/QVVGaiFvsIvseqip/LeK1s26dXZHxI4uT5gn7KdsDvrkjnGADLuOQtruWzR9A98owI0820DKlN5o/ULdKPlPMNZ5Bga7riHrqE36Xvsx0yrst+Lt/znjrns44rRDusB9uethi6hEOuldp0jTIoz3qW25XrtkwdtL9cNlV+XkhfUKaxDxmLujyeqCvtuaSH60u/gd/7gbbbNQCfIKWybFN4zYzykEOWXT4zK/1JfIMHfUrjfPlbEZxvfm/FnPkzMeaT1Ce0g1gTZKRHZU4S3xC/OKWqdyRyLAbnDyeunz1KM2VwpmLicJjY94ZaXIvAb5ip6tyFjB8AL5+R6BMO9I15xX1lfwF+PvbCpY8mec5jhLGTa1PQyza4EN/sA+L9kuwjcF0858Z6rq2qmCnjYn0NmnB2AvkcJ4J9gm6Fns1UdWYAvhF82kJVOha4mK5YVecfWJ+iH2y3mKc8N1j/s/5g/iCd177sY8i4guS79PGYFpmWijTGc9jah+lhXxcyKtet7MdyWkE4uAwD23KZh7FnfEyXjGFtqIMx4zpg/9env1jP+vJZH0Me+RlKXusw7yErM0pj30/WYb14luqcpTb4mUrW0VnNvZQDlgeuMxRlJMRqcc9nStfAd4+Gu0QbEp9vHePTNZKP/C39f14T8vzztTEQeXIeZZQufWDU4d9P4xh23Rxjv8Q3VkxzIdrjdbA8CyTHmGngtZ9vTSFlQvrXbE8kHh9PZJ6v/9z2RPD6sG+pC31tHAay/GHrDN8161yJA+U6lOfjsU+ehp52fPT6eHwY7+XYSTvhszN1euFWPEU5PhslbSfKSd8FtPL+G/PLt8aN1aKcwx806UdVdX4SNEDP3qcqH8PUW1OL6xlpB6X+Bw3mXDf73ScoH34f1pkc4+NnwdlvAu84nX0M2IW2qMf7NzwuhYBUlAE/4Xf41vA+PcS4pP/ia499N3zHomzmqcv9ZzmSvo3P1hWeMnVwt4bzqvIReZ3NazXobKw1eU3IPgXo4H1R9ufbanHM5FqP19q+dSHLZNdTJ6N8uR7PPO3IfST4elL+mc5VqtsVbfrmDJ5p9/lSmVpcN2Msed3K/OB1tvQ9wVc5j7g9n/8n4y2SV6xLpbzy+HDMpc7flDIv2wSfcZ6E/Wleuw/VQflhecTY8L4cxys4lsN0yt9ilPESljO00xH4ee5zWSnLPOaQZynn8lrGXFgfIK4P+hEf4GcwuS8y5u6ba2hDxoswbng2xFdf1mO5qYs/Mb9lDIfLADeve+viP21P2z6QY81yZb4HVJZ9WR+9kGEZ80PZjsA1FHWhA3zvFUe+1K9yTzlTB/uQCzxcxuBEXAe2uhDtgYerVBc+LM9P/H4u5JHHW/Kb58lh41d3L/sEXwbPNEj9clg7aU07Ptplu/yMVS7w5aKu7zoX7UpZ9Y0pl89r8rgtA3yWjduAfEt9L/WEuR8qfx96nnYTdXAO+OZO3bh0PLgTT/m6uc2y6+NP6smTZdin4vGuG8uRB49vjvK8hKzwGPepvmwf84x/n5fpgJ5kn0LKEsY0FXmHyY8cq8N0ah1knnakXZbrM7at0p4XavFslE8uuE5HlJX+g7T1oFfOGQP8XjDWxzyPpY/fE+0hhsu+hKSJ2+jU4GVbK2W8bkx99z79xmPh4zlDnd71le3X5NX5S8xnXx2pr5iP7Duzf9WraQv68la0dT1tymvfmoLTWc9IWQRw/Jd1F4879+9WIH1bpsOHP/d890W+XIPW+bISfOtOSWsdDbwGk+tgyK5ck8q1jW8dB9noi3S267KO5F0d7zkWkdE957EOlM/hyXW/jIH5YuOIzzB/4Atgf4/5IuNWTCue6eYzljIGKOOKvj0c6ddwHJjveb9E8i4X7cn5xr6tj5ZM4JOQUxnGwTFOLiPrMC7IUkfU9cUEW+rgGa1CLfbZR78vRtlRi+9b5Lps53z1oROYxoLKcPxEzmN+Loj1s+Sl3IvlfXukQf9B5qQ8cFkZm/bxmv2QguoxrlQt7nUARyzw8x5vImhk/4XpYT3pmytyH8cXs4eOSZRf7nn++OQC0KZ0tgupaNPHb+hvjr37dBTT3BXlpQ6Tc8mUH6uD/WNZknyU/JT6HrIr52qf8tA+4rYsryy3PJ+xF8d1WUdyXN83RpLvoB904XydlMvbgTodwenQE0y3lA98o084a8J04/1W8r2ndTSv0XXHU4Zjszzn4IcAvym3RLzMqD72m6Re4rEF/iGVwTsYUK5NONn2sw1mnsm55ZuLcrxlupRt3/PY5nvqqefjO/tdtyM7ucB3GJ1yLvr0T+JJl/m3Q4/UkTyfuc/SHsu2eA763lMh+yr7K3WN5HuuDva7rw7SWYh2pV8g26sbh7ox8423j0c+XrNvI32kW8mPr93ikHyfLZbjK3U785fp6wicbXVQRqTMJergeEk/hccVeOX5isNkum6O18mZ5Kdvjvjk1IfDl1c3n3158kwXPw+SijTeZ2M/QrbBsSvwk+0+yyPLPvux0pbJNtt0j3YRpwZ+vIspUQftF+xHog7aA5Y3k493lfn2C4HL4MAZOim/Ph3Dv3Ut7Y205XLsfGPJ+k6eC2ecnRoceDckfHSej3Ku+EDqk4G4B47Nmvo+fZiKvEwtrqGlLuR5LNPr+oAx53eeZqIN6AyJU9IGGWDauF4sygN878JgvVZXz8eT2x2nw/D5+sm69Vb1ij9jHvflVn1MRZ7Plvv6iXvwQf52DcrIOAPWABIn6x9JK5eXz+DwuKZUhuekb/2B7wHhSqg9iTsRafK3OTJP2ygndYTkv+/5E8aJb7SdifbqbBj3hduVc/tW8xHzj2MjPZF3K1k+bF7UyWrd3Plu22HapS4o6B7A8TfUwbMQTAPezeiT2Vv1A7FUlgPoUINjRYyb7HsicOIZLI4BSD+Px591NMeQYeeAg+NBbBtyTzl5Fo/nPMd+WHfwHhzrNblukT4P6MzUouxzbIL353g9inZ5fHkPIqOyrGflPPKNR1u0w34F7nnfT/qrPhniMeO67DNJv0gCx4SYJp9PJeWFx5Hrs25hfSfTGLfcK0DfeKz4bB3iGUNqc0T4pU2ATue+s95Gm7zWzKk+j7d8Hhq6hOcBeMsyyHPEN1+lHPt8f5Z33z4Ig9FB5vkH89zUEVXFw4Zq8flOUw5nYxF3HKrqbFRLVbZoVS0+r5Oo6qwLeL4mxoHfYYxnalgG8H4gtlkj4r20YeCr/H0sPOcJHzx1tLAfcEQtPh8FOrCXgH5LmQItWO+06JvfwY802Av4rDgDxM8i9AVv5bMTwIW8wvGSdTr7LcwT9BV8P64qGcb7ljDvsOZi+WL/iOcdbB7rf/BtVS3Gg3GmwODi5zUwvrny+6tIL6gsj4HUU6xvec8OfPbNDd5TZ/0lfwuabUcu8qU/Jn8HWfqksg/JLdJlvbo26/xQ1h8+fFJXSr+2rhzGlXUZxw2kXyN1Huf7zhqwb8D1pN8i94bgd8g1mJSZlNqTthF45P60LwaHdwuz3Pn0P9MYq8W+p6K8XO/I9Ti+ZZyH+4a6bYGH/QVfbIh5IfuSqINjKOec3COVNBZqUU6YXmljWYYhtyw7Q7VIP3jTVIuyKuVd2lfWl+x7yDhD4gHW1dIvlftTcoxyTxnYXrTH8sHjwvhYFth+Mq+gQ9mPZFmS+gL7Nb4+M0/qdBSn1/1WJtdpesYHdqZu/rJtlL8HUQfA01EH198+OfHpv+8WfOv8urzvps06HqeeMrI9TmNfidcoqadenTzU9YP1WB2vffaoqQ72T/7GCvtfnMe6o1CL7zdhXqFNXmPw+pL9Id/ZNPYPOK6NfKmvZNyA03ivn3U9y3ws6gzVQZ6jHD/nwDaA+VGnW3n8uiIfsQ65fpWym1N93/hzP+vefyLrpKJNOQbAmRMOWY7TD5NXXhNLnkha5ZotUX47Im2wzwfkOeyz54nAUycjTK9Pj9fpvjq9wXOH57ts9zD9k9bg9ukz9p/lfOU+yPc4Id1ng+R7g5qEs+XBKdttCWD/W0JM+OWaQOo/jotIvdYU9e5Q1Xw2azi8W4T9Afjn7K9ybJ19DtaXyOO5ZNo96srjncbQExyTxO+NIN5n6uPZErYrPCfQHuYa6401SsN+FvQsfh8dPIX94nMn3Pd1tSg38n3UvPbg3/TKVPXcrZx74I0vdpaoxTPqHOtg3V6oKobCfeeYE889ttPse4G//J48tjltgYf3jXneHCVejAh3T5SL1WK8g3Wg1L1Sl/rOM3McA89DsW+MsrDRWHf69LWMd8qySGM7zbaR4xFMG8eoZRvyTJS0K+w7QIYzdZAv7AukIp9tDmhh2860svxKHcv5ch+d12csIzKGKW2OL12mAWSbsjzzj/cWUrX4rk3IPNtTxMTQPzzHwH4brzm5PvdH2k+fLT7s/lZQZ9+ZH4f5HIfxz2eD66CuDPsN8qzercb3z1O2br15u21IXkE38TXz3rfu4LK36rsv/7A93T9L38AX2I66Msjj92OiHz6+HobrsLKsMzuiTFqTHntwMU555gn0345u8Y25pPdWvJe8PUx/Mm2H6QfmE/sUqbiWton5KPsk63IdyRt5Ldc+Pp/FxwsZ1xkp/3xJlV/2mZdyvvnWAUyn7BvTXhcP4jq+uAffy/1IHivpH/v65OM3rzWZDt5POUyu62xCnc8mfS3Or6OR8flkxyf7dXgkn6FXfXOHeSrlivHI8T1s7sqxkvT4ZNUHUta+WxzSpvjmle/6dvRMHR9888ena33zW7ZZR/et+uxLlzT9Wex6JuqyPPAasq7dunjKYfT6eFcXq/hu+VQ3xj6b59tTk/XkeQv5LfWl1OmATB2Uff72zcU6XcX2y6cvpI6sk+86/SLluM4O+fou02V7sh8+2hmfT8/X9VHyRrbJZXkNl4g6coxyT35dP1kGpV3IBe46PtTpsz8LMH3SBtT5Bb7yPnnhd7T7xlDi9slDXRsyDXQhPiH3+DjOMBUw8qQxbNE34DilHxfluGwdjlu1d6sydZDcIn+zpm8Sjt0GbNZc3y7U1TnlvrcobebSDa+PeuryPfg3c305Qn066nCY8utUR/Z5SninhH/DwabDz+WPinZAf+buj7j7sWvbxFZX3fcRB+vifo3aPOryV933uks7pqrfgkYdrrfp0rkMfqt6oqozaRPCj/shtTGhvFUC0LEu0pGHd2qPqcymow39X3P5a4Qf7eF3x4GDf2sdNDNf1iiff/97TPV93+tUZkz4QOOqSEMb/Nvz6+56g/o0EWXkb7lzGv/Wuy+NeYLfnOPfKJS+CZ/ZRDrHEX3P7rKulDFgn73j+D+vpznmPSJ8oIPfu8K+Ic508rvCM7X4Hqcu3eeq2g/Bc0vAi2ehcM4Q8tAhvuFMJPqNM4D4DUbwBO9Qwngmqnp/aEL4cYayo6qzHviNRYxfTrjwm/F8ZgrPc+GMJ3Dh/fWrDh/2VPh337HXg99xRP/ByyGV66vFPQa8ixU0436gqnmB/RLIC8fM5Vl0jiHI842Z4Du/c4p9bi7P/l4ugP1xjnXwHjlf+3wa6atBHtAPfg8AxzEP86v4HAOfLysIZ+YB+XtZPr+a6eX5V4jyTLPPx5T+PXgMWWIdwGtC1hXSD+cxqusD874r8PC6h/eqjBzxu/8k3+r8VeiTVFXnMo6JcpBTyTcuw+9OMGmwDexz+p7XZT5BxkET5tWqWuRPQvgk/+R6ou4eMFYHxx7zzidbcu0uecvvA+d5h3khY20S5NoZ7fGesrQx4JnsJ+bKMcF/+e4C396cPDfiWxezPPLvdTHPec5NPGmgR8oq5Fqe5ZHrQ8w55olPHg6790FdTMSnJ315+Jb6Wtbh5znq9JOk1ZfPY+Sjty5Ge7vAdnioDtLgsyE+ft2KBh/OunIo8+dd798ubXXg22tjWb7VvrKEc+qgvpf99sl0HR/r5P2w9MNk6bD2Zbv8nH7uyb/dsZDyhfMwfAaQoakWZcO31yrfkeOLq9TFbX1jLt8NxOd8mLa6Nvh9Nj7+NAV+3z5RUy2eV77V/JPt+PacEpHfpLZiKuejW/JA4opFG/IMWksd3PfC9UAtjl2d78kxO/lsl5Qxnyx0VD3tSG+Ke/7G2SfIRNNTDrQxDnmmGONvcPBzQ9AR/HwCz2HWlZyOdyxzv0YCL+thfh8a6zjpP8lxMvkTtUgHP48o5c+3J+Kzs3V0QtakLy5p9Pn27Ktxm7Eocyv9KOXF+EdYt/J7YDEm/M5OrCskIDbAa0I+y8frffk+Wn5fdEF1+L0ukImc8hNKwzqB4w2QO7x3n8/B8Xtw5T3qyPfxImZj6D8sJot4pomZnaR21x2NiB3w7+yBRnlGTuoDAxPPuNbZKZ8u8dlf/L4dy1NB91Kn1+1tcX3oQc6Xul/qT6lv2a7wmeXUjQfrZGlbDrMvPh0n79mecPpEHXxWimmU9l6OA9sVHmups/nZnDpbz3UmVKfpyff5ohzL8+HlvrUELonbp5uk3vT5Q9yulHnZ5zpbJ2WDv31ycRhfpGxLGn02oe6eccBWs+/J5Zge5oP0BX004xl03zl5X5xF0lknW2ybOF36dnz2HvVk29IuStz8+5OSL76YCds6aY/xbLm0+ayb6sa0TmdIvQzgdbK03Sjv8z9ike9r0zfXfD669GvluEo9ZYDPnh9Gj09O2J6be2O7tt21fHaBzyia9KOq8n16njYzqs/xINDJv+kt4zUJleX3mcNPAP6M8mVckn0y/q0Feb4EtCFOZ/i05uiDT8mx9Q2iAXiYf+xz8hlsfu8c/KNMLfqU8LkxV9g3y9TiO+5QF3sivPblmHGf2mZ/UNp1not85pZjqjLmjD6iTeg4ntP8rreE2i5UtRYAf3x+NMcK+beKC0+bWP+sqso3A23yXVIsG+gn4tOgCb+DIuPdCZVjXcfvdGA+8O98wxfl/jF/fO9G5/EEbuzFwefEO0nk+4ZyVelQnjvwhVmP43cqWLbRLmQFe1LwX3lNyHFt7JNy+8w/+Mksrx21KMu5Wny3Cu/dsO5EPcgAn8HmtQfKgHZ+JwfvEfnmB+QP6eh3m/BLvwf8QDnoMI5vslzz+KSq2t/g8WB9znzy6VXWvR2BG7qVn49KqR54x3Ig7dtpVb3zGO/twroQz3ZBZ2VqMf4k9yx5HCDn6Jd8Zqor0uS93Mv02VHWbdImSBsi5z/fs61qq0V96bPzbC/Y9sNHZNnhsYK88t48dAnv0aEvbbVIk3w/E+qzXvLxjMcGNoH3DEErr7GBx5wp2aY0XqOzLsPeey7wSRnwzdVM4JN2EzjuUKWtxPuAsGYfqup3LSDD0KewBwNKZ/sD/nJ9+ewp9xt1WJdLO+CTYZ7DLJNsY6TMsY/sA5SHDc09ZaReYD+WdQlkg2MPLD9Ms9QjrMMSgRf1EPcZq2qO8Lt4+Rlgtjnw5dhGMcAPY/+M7RLrIXxDJuALgg6jq3H+DP02dN2ryt++XXU0me8zqrK9hsZ1dTA2jHNpkDdD58zhx3gNKA++yoaqzqRABxxTlZ/Auo/3P/ndBuAPx8ZNGXOGb9v155Sq5jzWkqYOx07GanHOs98Df3vN0TVy/VqP3rZ1N93nuIZpdMx+tuzdVtTVMInujc5Eo2gW5VFHp2zolGNRrL+3ol+Kfj762eg7+rMffSMaRuPoU/r+5/XdL0W/YtO/EX0l+qRNn9Bn1X1MjZH+HNPYVqMvRm390RTqEuPoX0Vfjj6t797Udf/d6Iei16OPRi9EV6MfjV7VaZ+Nfjh6JfpI9JaGy9FX9f1b0WvRj+j8PCqiNOppTN3oqG4hiQaabpM60deZvsr1d1vf9zUUOiWzKYm+TmzdWJePbbq5M7lte5fq/Nhiylx6ErX0XWxLt2zNxH5MSmpTU3vd0lcmL7cpLVuiZVMy+8G1wZjOy6WuxZaF1hx7+TElcsqJbelknoJ68byt5hxHPC9nvpuEJ45WXKmqduzuS8pLroxsybKneXTE9TSxHC1cr/qWopKP5tN2OYXtYVtzObPcG1ieth0HRq7Fjr3LLP6B46Npt2vTSu5kll8t13LL8q9p20hc2yWPyhFPiKeJTTe86Lqxii0tBufQykZqpcCkdiz1qU5r6byRpmagr8f6b9tC4jAf159cz6HYYS7m41tKgKHK9KpjW4m1xCduzErZMlT0nGzFGv/Yyq5pz1z3ddsDjX1kr0f2zoCZK4Wl2PAmtxSZEhM7t0w/upZ/Pdt+X5cY2vSO/pvZ2WdG4Kj+zu1df55rPj193dP55rtrZ+bUzoY1W67naChLjCwVhs6ubtvUGNj8QpfuWZ4NbemBw2XaSezfvk3r2VY7lqqS4rL+qq1VaDC8K1NHtvzQtWKuJ1Y7jd2nb3P6jvKyJz2Lx+SklpK+xZ473mZaB8lPpRnKccrtWCXub+Y0Ru7GNpuPZzKXzthdlX8hmYaa1rxEz+mZUlp6Tj4TK7uQ79S2FVvet+d6oXCtNe38hCSBtlSX7NkRN/0o50Pb9qLU5LmdhbmTyLb7dByd+fyTWkoy1/vUzuOyhy03o1JbLptfpbYXudNlybxUamW8mNfJbH7LlmjbfuGTLdThT05/MzcyyMFVt7Z2auc131VjVnI2c/fVSCZO4yROi1d5ibUziRuPeK7lK470LM5SJ7Ydz8u7jtWQhbMvLdeT3MpT4UYmn/Oo7STN/C0lOrU6zVi2VdunZOGTijvfpy3ui6jikNEZXatr+3bmHbFasK+9gr72HPr2s+a++7Zsx824jpVn09eexdCbX5u8tsWdWa27bvWnmfVGc5uybZ3atVJlJDe3lqlrZ0vXauqupa3EUVg+d+0nt1JetjWw+R1XNrMlu1bzti2VseW/4dcxm9uy/O46XnYsPZmVxsyOUtuOUOEs9BnbruH40OpN9L9j9YmhaMNS3nX6rOd6bnjTtGW7Vqv37Lzv2/zq03XQs2V7TuvGFmNufZnv7pPPNcTtfyovY+QkL7ecS5x8tJ02WXVaCXqtbWcjNEfqdF1uRzSzWrbkZcvOmtTxvGu5nlr8mfOtsrnGyufaAF5E6nJSNxuMjKTaN21bbBi3fK7Nqk8+7wvw5/PZ1nT3mZ1dmIGV/uvZmomdC5353Oy73FyU79N1bseu9H9yW7dqfbBASe5GLHfyk9m/qZXu9pyrXdvzzvze0FR5WOW8KuatVB9QUNYpvTHQVfLV/B2R5qx0R3Ou09pWgoE7cdYFmjF29qzsR9luKuiAlcucpUqdVcnnlkLKIyxp7vJLC5o7eUsdptTZZVAOKcmjyvrCZqQRfMOK0nQhLxH2Bxo0nuPknMzJADxItlPJgfrlGiKnvkm9XHGh9Eyr9UQSVbaIOTVweGLbS6wlcjvPMldj4DgdO0rwnThspt7I6kWsQJADnyJxsy6eS0DHUdF2M8vkD63th3UpHMZKok5Z2zWI4DH0tSbpOx+t9CbbNq1lPdPcemiG7qHTMaXXWnrGBtPI4h65+vhbrgGH1k8e2hqF85m5JH969m9CKblty+BoO3/YYCz1FbQkrsqVQ19o0JJr7D0mc0mXdjpesOHgV2WTwUOZcvCTiJKZ8w0rmcO453PK4TXGzjOBpwr5qeQYK+HUeqBlbzvzUplb/WTW0sInRm48x5u4dVOTuNByq+nWXEKrTzbneuwwVzOi5XgaL4xKy0l4261eE2tjkvl6tvKKWq7G0JVgTmZuLqCv5Zo/m+uAcnVdzrNiPr+r0W86P781n1fwqEFNJSuVpkxdNAFaEhyH9sznqRXX+w5Hy1qggS3TdtoltnOyFfEKBXLYiko/oR2VK43cjkM651E5drmTAeiLDuFpR+XKsvRxO27NnNm/HTdr29ZHKj0seFodl9K132XpUnI6rlRpa2PbWj6vl8/5yLYTNq+Y2+TEcSN32hl+CVLaCzVzKyHQ5EgtFlIweoXT+eBS5alXsgr9Dy5WFghc7cwtB7z8ypZhBVFGTcqoFEslz3dYssLddahMPpcXtnCyLu7iOX7EZzB6JYXtCCvfdgSbUH4QBUncCrOYzzeeqWWfKj2XuZUka8QiqjRVez6PsjmPEls/n+dgFlUYTHp3fm3obNJIlH7Q0PW47fpXyTpmiOHZIKqigpUnlbn1Wz6fncU8N3E8w1wG51sRfNoswiq9HcEXAu9zAowLjzuPVZnSilKhL5OFq9StSs2n6ax+4uZ0toC5shXsq5RS25lHQDPLW3hhaQS/Dzq11JBs78FX5lPiIolYi0N2K2+vokyu1hOirtT+nTm/oIE7C3yLI1ihdB4FLOOeiaWg73Sl+TuOSq8ld7g6ulTT1UDE0HyvWH27HJVx0hVbO56Xih1nUoetNae5cFFX09ZkHjuLbXyrsCvrrl03lmvGbL4y7LjVeBk3SuZ9R2y3NZ8H9ZGTujhAuiB1OaUs+sV1OFpz7ZNQqdhZcviZuGrNOdp0dVccT47bmOWq5uVMfw/tirGM3yH21HTa19Re0Z/UynQrgm3M3ewsdUcx1wKZm6smUrpq46JllHDiYn8bLqI6slGNib1uz73HvosUVrHfMvbatxjKWEyJJ7be60iP49Dl9SytZdkyNtp3dcvroYshdHVp08eh84URnxzYegNXum8945FLGbhIZs9FNxGH7bnYQ9/NtNSub0sdAP8KXkhrPmrGVratn7Bix6gVIapVzu22pY5908Rhh+bHbIujRTnB2oHtAPyIymfLotjZucoj7s7vK83Gmq6iL3Z2J3EeQOmVVj52FrFXxpqpsiCJ8x0gw/Fcb7GGZz0ITVrxpLK8uG7PuREvtHXrj1wLw9erKw8LyH2v9AH4lDqp6tjRLmMGuYtDdq2f1nVSOZzvMyRW7sxeQ8/uAYzsLl65surYUgM7Y9pWS5XeWjKfj/CVqk/XcWVsr8pI0NjGQwaW8o7Td50IEb4yMt2bRxyN9u3aedOx0Rnk9Jw3aexV3/atbSlE/sDWSl3ZnsVi8lrW4+lH5Yo0t95sbr3SbK5N2s6fzWzdtptjhfPSBq5n5n48j+Nl88hTyWG2qqO5D1xSndnvMipTaq6OjUc1HT/bll8dK6dt6+FjtiPOwrayE1WR7lKaFi1pOpfVxXhGGTfFLEbEoFp1wcZjdHkFG1t6y7mI9ULH+QeLK7rSSlc+SuzsZvnpunlV7UCi9nBOQ5nXXijVmpeEhil3SZoudeAsTWKpzOzd+rxWmWckq+U+6fyq1HPlVTa/yil21l6IppUcKJwGyNz4J9G2Ha9SQrft3DLScWd02nLASNSqrT2wUjiJeFcDdrny7VnHsh9VencT137JC6wuqhhQYaOF5d506VcPomyhRW6ZtRdSUiel8XxlhFU31yotThFtzTVSQtxl/6zSoJWXB323SBG8VPjrXZfLMr7IN3h+LYGNbVfJxe5C/mL7lX4/FnEsjT/5XAaRx3aq69bGI6e1RhEi3m07euhJJcuJiz3guhUlrv9ZVPnBGJnKplZtQ+OUcYDCrawLp8Pa7rtwsepSe3ajjos9504q+k5yO24N1bVXprcdK8flar1ndWxhy2PnPLdpbat7cztG5XzJnR41lJVeXrkDg2h2uc8TW8yIyxduL6KMLPYovl7utqQuDpFabVruGnctfRMXWW/PdfvY1SscXkQuzdU4ypwlyp2O7jlrU5Ys3F5X1+W03S5BuQs1tj0s94/6Njefcxu2o9wbzK2n2bMY4fG3neVpu/Vp19Uod6cG8yhLuR+eOer6tr8ljtRe8Z5qbjUCbEE2l5jE9Tq1/Rk4ScmsBsIuw3AepehFiFhg7wNxZchwVvvpzUtlzn+qvCn4NWMXFZF7k4mzrwdXN5156XLu9+bfw4h12dDNa+n9lZqQtWk+1wjVrC+iSifkC1i+F58y/oBYyEHtxV5pqUFLXld77NWOQLmGHRO15eiU66dyvKtzDAe9TP9naOtmzr4cjEEvprRIT7KmNZ+uHRtQUPoAgwgatqJpUa99t5+U/pb2pe1yFndEEVOSn2KeU5384pVJO6p2QsuZ0Y/KvflqJQyrNFgYy8pqVXEOOQ7VtTlpU40V9hOwP1PupJZnmMxd3618yphMOQuqE2iIgcR2fVd5c9VJMfg6SZQ6K4NzYTgdxpZscWRKmzWae3st8lSSeSSAZxSij4jewF9KHPX4LkevipNVnKh2KBgzxriSO5zCkZIkZQwxIZ9ElVa08ngrncX9Z1y3I7ntiFtIo6qtIsK6tvJwW+TVlmOEvZ2qVaxX+XQM/L7swMzFqZ36qFGlC3mOIjZuPiO7VoRWKjlUWMoKt2pbc3UHc6noO2613AiX861aUWONjfg1fJDFq3yu//L5jEgi6LvDP1jDVDKVzrnIa5HFuGoyX9sczFuMTsRR7saubK/vdgfTKHFXSYTzk7wLVs7q0QFK04U06IHqlBnWMNXuVjVPzOwz59nW7WfNwpq+P+I+5nrN5ZSlcEJ33cbDVm3Kmr0eu28DR3XqxvwE8aZO29Rp5gOca55TdYufkoKy3SMW46prY83SU0Ya1ly8YehOTaZOs+IkQrUSKM9AQLci6l64dVcZF2g73zJ1q/7yqmPPGmW2XDfqzveJS5/LcL88vVieJho4f2tgvSzjUa47L7Lygap9utv9LOolvxQf9ArwqWSvGfEZ4OrEsfyUdgHWoGPnYO5yKm8Ea8jWXLOiBMqXu5+ZtezD+cyq4nRZhDVN045G7M4s9uY6DrshZT+KeawEu5wtJ8lVHCyb07N4XhkrJOzZcm+rNRTWVdUKvyxRRNirRqygmuMH9TuuW3R9cM2H1quTnYs6JRFjU9GJWuvuvFUVAyw9J5+tqtaBlRTB62CbVPkdscg5WGIxBf1MosUoaxUjqHYWUb5Fd3XtVbmV3BQRTnwbnws7wN25dSjXoPABctd2Tj3mXdpKnsuWjI7pupViNyoWRq2KCcXuhFgVCarOzVQSgFHl2VbuUMh4QIvyF0/Z4yRvZekhH2Wp5gKnWvP2mlG1E4Q5UPlsTbpjWY5FSmve5+Y8tYo+9ObXsNyVlJc8KOZ1Sr7053KMk87l+c5qv1bKfeXt9KiPZak2aTXe+QIPOQrI84/TW44Xi3ldt7IuFnAv1oZnir5CCioLj/t0zid41zxi0CEcWWS5whg3CWPmOFjZhMriI57GGgUnK8pd/MoHhs9acpdpQF8h7+l8nCGLZT4ietWcNrOiEy1HZs2ZRyei8sRt381GnAKDv9yaR0jNzCiiFSfxDY1hWf81s7xh219xNm3ZfgxXlvT3En2arpbBYHYDyzMeK7acmnNc2XbLqMpSVO70tu3OBT4rUbT7xDf+5td/4m/8+I+9/aN//Wtf/Xe+8uUvffELP/L5z/3wZ9/6zA99+lM/+Nfe/OQnPv7G69deu3rlYz/w0Y+8+sre5Q9/6OWXXnz+uQ9+4Nn3P/P0U0++74nTm900OaNuZOmjs0ffSM+eiW6kmb7Mzp5R+81H91s2cf+DO9P93ecvbz3zwuXHH9vY2trbmG3t7+4vn3zcwNXXr19Dxp5GoWvpuhrFMy/Onnn+lcvTx69fsZk65aWFuzL//nmeu9pvPPrS5f0ndvQd3b/P3s9vnxTZTyF7Nt2Pnrt+/fUb0dJJnb67cUPZi5VHf3JP92Rvtv/azmxrdvkNXfaGZv7WS1ce1Vc5rtT0fRrj9J1u9JqGax+evaPc1SuX96dXPr73pC4dNU7u2/8vvhNdmH2pvL6yP702ne43T85ee+7y9a19dWW24e5fuKw5pq5uXN+abU339t65+WtHTOnZlsbViB65MVPffP7Grvrmi69c/nY3iqbffOnytxqq8eiVR/ZunNB5l7891QNuUxsm1SSam6m5iZ5RemS+1Yht+Y1v70bR2zZ32SbY+2u6FzYtRpqKrr3TKNO6ZUPbtqFdLaHX3lkuc3ZRelmnxWXa2zbN/tN80LzfTVd2491kN28UDc1tk/QtnfKd8sHAX8xVoTZu6Fov2OR31Ns3kt2NssTbusRuSeE3X66afvmVy7+o12pqw/7VDT1i/p098/iNxgd2ZpU8Pn9Zs/3xG+oDO1esTC6dfHyqpXF/98XLpuSVDS2Rj509YyRienn2xsZs78ZweP2txzWG2Y2rze0rO9dLwTDiMOs+qIVp6eRT12ZPXDEltHDr/0/ppGsfml7Zf+3Kjr6cdp+4/oQZu6umdDS+0Vg6eUMtn1Tvid6j+97M99PZG4/sZ7NH5jkPRw+XOU2T05o9sq/GJecenz0+XX3z+rXZa1pOdp+7/ImNj+9d1bj3d2dX95dnj2zcWI4e0VK9qnQnHr8RfWBH9+YZLSkf3HnuVT2VTM+n168/Nr2xu7x99dpVc//YlubEdZc1e+yxParx+PT6/u7Va1d0icf3bGE9X3Ti47Or09c1S3V3Na9enOnLV14xdV565fL1/PXZ6zPN0N3d61d1tzem1/Y2ru9dswzW9TVp0dkzK5UOcSqkYWbmyWsf13/emUavXZm9ViaYOSTTPiETPq5LcdrsadOc/Vb2+/rTs8df1yUMXH19f0kL19b09b1SPqLn7OyuLaSo0FSPqUV+vfsu3Cl3p2/0/+v7n1i8/eT89gkDVzTX7iplZX9528ja5a39v7ax/6m9nXmRq/tvvza9Pu3OHpyZP7by+wxc2V/RF29fu2pUSNPInk54WidML7+mpVcjfOLKdUicrra8PW9p/4d2FlBqxade0k03Tpru7L/93PTK3vTKFZ2qp8rWxnR/RX9PP37VCJdRjs+V/XlOa2j9dfX6i7putKcb3dhvaT398atvzLa0TtVpe3sl9w2Ny5q66MXL+9HG9euz6/tKk3jyCV1Yo9/eb24/Zb70/7d2Zlff0INo2ptefcPWfUKTa7ljsG08Ptva00UaJy0vNeO0NnrN/Ll2XUvj/kf1bFs52bvevz594Prl70Qf1Wpxefvah65o5T3tTp+Y2qG+qiXZMOEpc7enEZUFk5OmoK5v/2/vf3rnxkdbJ6sU+/8zO2Xh2GLVlL1wef85FGnZ//riszv7jcn9OtN0Xr2gbcCyHSjDvJWTT2n27mqp2jC1p/uNly674bH1nzJVNzBgZTWdYlWnMV5boDcr6S0bbdr/uf2fnNyPT+qB3l/WNJTZLdOdSgj0tSa6rLNkyS07oK91U1OXYztyxd0sn3zD9qk0WlOjLbU5vzozsPHOzV99TlvNKzMDe3um+dg2ZGpY1NdLxIZdTZPpY4Vrqfyfmf9P2S5wcmr/tyzNJq/s0soi4x33vn3zV6OSc1vun5EZ08tvuFnp5t0bG/uf3Nt5vazVdBp8qjWq1tzXnrc+wat6Nsy2WlqP6e7rWTXdf3FH2wzbt2+UXH261A5GKtUTs+gJLUPuQjuM+9HsSWX+RHpqzZ7cb+jb+dXsW41IxbP7zVcyu/9GQ7W0tjfKqFvkWtFfv3bl9dKcai5H9288ZByYph3oxI7tF4xqeunyysbynhWZ7f0v7jgpLv9+YWee/0UzJ1vgZGzyrs8zVyy6L5ayse3+fmEn9ta6Ht9eY7Ebzf3E5hlttB0f3tRSOUBPl8P1dKPE/HSpJ3Tq9rXr141qu/HRtpmh+XZPp/c1aQ9oIh9wVGrefFWT8pxpOrYp9lZPt5Yhpxy2k5nO6Oqyv1aKdqYzu5qaX9soS+n/3755M/rCDkqXTNB0pydLOXfZrnYpnV/c2dNXTxi4oos8YcDNpMzN0lxofYe+HNNkMXM2R2YM/WyO0dzdULn2VJc3VnSL29OuZteDlp/bmlR9f/3BG6q17QqsmAKNkw9ev55B/xv1/23tJkbWBYz2rsuE/a/p8dBjXfhzYpla2GQ3ysX82yS66ZA+up89avwXY5sSIwB36fH92q87nWPdCWKMTTJTkVNXDe9bUAmf2UFd8O3jdkq7uiL1pctf06mGU79uLMm+0t8r21sGNgzrbGtGxj+z45zVr5nR/XGL7sd3ptM3tZ/1qNLeljaUbxpTNTWl422r5K5rh+fNq1etHrKLjVXtS71gPFztp8+6U/VQ9FC5ZJm51YC2AcsnLz+08cCe9v7fufl/HdkrVVVDG3kNL12fTrs9nXV92tfLgf2vW/a6vJlN01a8ue1KmR58XU9OU04Py82PnF/ffPX87uYr529u7t17c/PyPW9vfvie3c0P3X1z8+W7dzZfOndz88Wz080X7trdfP6um5vPnbm5+cEzO5sfuHNn89k7b26+/46bm8+c7m4+fXpn86nTNzefPLW7+b5TNzef2L65+fjJm5uPnXh781ENj8zWN987e3tzV8PDx3c333P85ua79fdDWzc33zW9ufng5s3NB47d3Lz/6Hjz0tGdzYtHb25eOLq7ed+Rm5t3nX178+zO25tndqabJ9dubp6IN9Y+MovX1z5yXN9tjW9uTvPV8Uc2J8XmscnNzaM64ci42NzYWIteXV0dR6+um6uJuRqt3T++/5XOSN0cqcGz/Zd3n+zd7L7c3+vuFc/mL688u/xyvre813m7/XL2bPpy69nmy6obvdzeS/eae9Fe8mz88tKzjZfjvcbetPGcXrbsN36nsbK0u7uivq1+Jnpp55l3WjdfeGY/fu7VffXN/ZMvmr/a8d1vfnM/evmVVy/fUOqn977+Uz8VHX3kmf2fefHyt5Yifal9ocajz1++sbz003ufi3ainZ2dyH123DX+qs99Xu3gYxLNl9LfJbh/tp7CxYHL6m5nZzX6pZt/Ev3Xeplk4PMaogpu/q9ae92IIndv9gPMqeW2/du0d10bN2rbiImJXZuT2WsuIm32A8zbRka6dmLrde2ZS9Qqn6htRuXeT+zqD2x8pWOxlE9dFvaE4cRem/qNqDxPFv6Ff+Ff+Bf+hX/hX/gX/oV/4d/Bf68FCBAgQIC/1PBOgAABAgQIECBAgAABAvzbD+p6gAABAgQIEOAvIzQeDBDgewS/85cDln42QIDvLSx/JUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAN/PsHI6QIAAAQIECBAgwL9paK5+j+Hv/Pmg9f4Af9khbgQI4IfkbwUIEOAvM6TfChAgwPc75I2/GlD83QABAgQIECBAgAAB/mpBpxEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL8xUP3HwQIECBAgAABAgQIECCAH3r/OkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIMD3GwyiAAECBAgQIECAvwLwBwH+vDD6oQABAgQIECBAgAABAny/wvg/DxAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECPC9gNU8QIAAAQIECBAgQIAAAQIECBAgQIAAf5Gwdm+AAAECBAjw/z9sfCrAXyQcuVzC0YcCBAgQIECAAAG+f+DYzwQIECBAgAABbhc23wrwvYbpnwYI8P0Bx5sBAgQI8G8AfjtAgAABAgQIECBAgAABAgQIECDAXxTMfj5AgAABAgQIECBAgAABAgQIECDAnxdOjm8ftt8JcOq3AgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECDAv8Wgos2bfxS9L3oo6kWz3YFK2svdQu3m0bNqdzCM3q+a0bnf2Nn5x/eqc//9P/uNu++5eOn49vbFi+PxaNhuXLjv0sXzy0m81Mj7y81RsdQsimaaJMvZSnMwaSjVWIl0C/nNP4n+MPonUT9a203jTidfarXyKI/Ones9cO58T3/uvufSpDU6f2kys3+Ot06dv3Dfpzeyd3VGH3uhO/6fiix57Z/k8aOd0We746Xkv+xHDY31/4j+VfSbURo9EO3sDlpHVHvzzjvbvQdW77q4euTIPe17dAN93cB53cB5aumSIb45O35qe3LhvlOm3Yu69WbLNj88f/7ei5fOD8eTZmt2/MKFWbPZOnXx4iVD032NraTVWF5qnlOrSW9YjJJx7+724IXO6dZyY2U5bfXvXTu1dOKCuvuoulOT/ItLk/5KMy36Ow92V9Pkg1unOiubo/Zwrzc4sT5odtTqD9x/YbA8vv+upSTSPTp68/ej34v+UXQ0Ohtt7bYnp1aOz06dmh47fvz09LTrDPVjPNF0TTR98/5sn3LUbp86NWdm69Ql3c3nN7aKwcokWW+faK6opZW4l4+2O43+tLtx5Oh/1B78g/+k3X+n2WmqvzXc7G/l3cZscLy/spKl7Ul7Mk2WOluT6cZ2e/jL7WGSN/9+sqbpzW7+n9EfR78RbUc70WQ32Zicyre2TjRPgO/33qvlRXPYkLmtGWzI0V/jyajZ0qS2LhhCZ2NDsunMpYuqc/pDabe4995TX0176dHRyfPd1pljOw8/dnTaXVPrR5dGj66tbfQefmM1Xuo2h2plpXFP2m1dHB9Llpby4cZmd3l9Y3b3/e9ZW5r8yPnxsZ0oWoq6msr/R8tJW8vf3UZSzk6nxZnT29tFd2WlyDqdSTFh5hrKzR/N4eGkdWE2apk+nLcCemHSbmjSL42NkMxKwWhZVhvp+VXVeb2jVOda0v7K68Ok3e42jqqNYqUTfyTJW8nyA0n8a0X/6+29rPPLZ81EWRmeHcZpvnz+/Dfu67aWO/ly3LwUt5f77UZcDE5kHUN/dvP3on8e/ePojuh+PUtP7fYePHdu0tkoNjY3JxceeGBpskTUG9mY037xAoTXzCfDbyMvbp7NhcbTy1dUV+XTQWNyrHU8ie9vnzx+ptve6K5m3fPbzWW1tNz8jOqcN129J20/df7aR0bxsVcnpzpLaxcmjfhsY2l5pUj7S8vnst447yyvtFrpi5892hxNWmeuHU/TduNrXzM9m+iR+RfR/6xn8NHoXHR0Nz9+7GyrOKs/6qSynXpAqwgzexdn7SUtM9tG9+iJakhutsq5O27dd+rC+N5LF/RkfbMxLNLGUmP5qf7PNfL2UjNuLKu/l/a7q//VL3TH19TG8fW+em+R/eaS1nia2u6jx0ZZY2lpKe528myojmTd8Q+sJZ1kZSn9yFIUNfU4/O/R/6alvYjG0TS6M7oY7UZ37Pbfde9g5+GtwcmHjw0mDzcH0cMDTbmdotXHzlZNvSbf0n1Js3loh2Zie7V9alvPklIZDSdlT21XT10a2XHUOWdUo91oNFvp8vo4PnmscTbfGDTjlmokdyo1jlVntLTUVEuNpeR+pUdm8hNFnnSaS2o5KdYezVpfeLK/dOc3x/328nLRKIrJj01XPztKW3+9P/7qSE+eZDnvDC/9bH+1eWL1bxe50drbWmv/39H/GB2PNnaz/GiSNKLpdNwYk7Tp+X3JiEwpQc1L58dGdU6ap2bNS6VmNUOx/R/EvUR1flT1v9RfViudZP0nR5rA+Ec/V2S/nLdbD2lV+OGuUseOnG/0G2r9E92kFT+6ZDRiT+v4f6klJInuMRqxvXb32unTanXY651RZ6BmnNzPZaR5arsU5gvWkDg9qDlbiscpTaplqv7WUpKt6O4/pkX50hNaZX+nO/7B+1v9ZHKkN1IP6mlw6TeX0mK5kS3l2a9sPzVJZktJdzxL89blQdyOlxv5C2/0+631ycfeMhKd3Pzn2ib9o2gt2tI68Z7d8R1rx4vNtfUiHbVGa2v9YbcolvpLgnJ8MGtLuheon12aHG8ZiTmFLp76huqpD2iSP3O//vNz7eFHn+qMPn1pFLc7vaX1t4+mS9nKSv/YeNzaXHtwKXlJy/nwpc7ouW6/r5X7+kjLRhL3e2vRclToefiHmst3RNeiT0Q/GL25e+9yklx+74WHtX65/MTdj919332Xt9fXLz/z5lNvnjt3+bk37vzAG5/85OWXX33x1ddfv7y1udm53DmohObfPVKsQks1W8cal7Q5aBrbZeyAUa4Tq7EuOdVqJ7dTUnN2WD5Zteb5U4qe8yhOaSE0gng5zttndi91lo4+ea7XmTbWet14OW2nzc24yI7Pkvi+pJ2eONZqf061tzey7sW78t4zeiadS+LdaRLfY+BcHD+8Gcfn1CQ5kbTjpaz3wvb29sfuXi3ajeZyM1Gq2x30l3prkyON1f74bFKsvKcRJ+2VdyfFiUnaSo5kvfW83x00J/1GvN6IjzTitUa82ohHnUxLXdEcZr1jq6vH1tYiOy6/q+3rP42Geg4+FX0gurC7+tClk8nGPaOnH33/7vvvuSd56vT7Tj/99HKyPJeoRZkyFtipkFK7jMelDj21qI4WODYbOws9syNixdAyezJsnb/wsJ4U2v3pd1tqaWllp7Gcaq3UTJY+pRPP6IneKAYv93fGg+Xz7VbxaOPBdEOL57sbm0n8nsbd/+Hb/WFrOvrp0SCNT7XyTpwWrV6z2VtebizH2WiwtpbGU5323mJw9uSSnnbHH3tqc+nUe5aSI3c04ub25uNGE3c0X35fy+tQ6+Fz0cvRXvTR6IHd9ccfPPLB0SuPPHX+gx+MX93ejj/8yivxmQ99aCleEuZ9LpwlfxbY4/Ruy/LHcUcYyNJVbGnbelELq1Z5pY94aVb9vXgJYvewVcZJr6NWjN3MNxqNVKucxjuq86wxoO9v9p6M4+ZLrV6ykh5Ra6o9zJv9/vnT6tGNwdq71F2T4WjcGE7S5Nlnn530x/HW6PpolLeON7NOM82zZi9dyVrabjWz1RMXus201Zzc30/S/EONuJW1W2fPNYtkeanR2925O1068sTZ8dLaqUG61DnSf+LIkeNHj0ax1rL/Umv6fxqdiM5Hl6J3RY9Hz0WvRp+J9nbvvPzpF849++n3nXvk/+vTymLkOM5zV1V3V1VXV9/H3MfO7MzsyeXuzrHkcndIieRySS6Xl0iRJmndWh0r0XJiWYpkINbxEDiBEgMKrFhJnAQBAhiJ/RAlQAwbSGwZeZIc5CFAHvIQwBGQywHiV+XvntnZWZJIA3Nt9wxZ//Edf/WLq4ee2AU63m33eruN5eVdw3Uta7dKaJmE4a6yO1Tzo24/EO2DdJiwYZRSdjxQ3WmFAavvQdugiWm8zy0Q/O4wohQ02DAx+xpm/y1NE6nHAy4CGV+rNV4OdTYr/QXb8Fbs8AdQkK+b5IStq9CxwpfsguxYL1CbImvXQnJ3d/ctFQF5crOPszzN2wlSMHXQNfTdhGvNVfirqlItOBX8jNtUQkAjIGAem5yphCHOHFBwzlXGhD4jdA5IPKWFYT4M51DBJRoGsKgTYYBpYKZKLKmpoLRlSQjdNwFFfKgXEymKBqrj5yk2E1CvSW5uKdf68+V6Zi7228jd3N7euLKisF7zcOFHBfSjNqoX2u4VpddTrrjtQp1Onb85pRxaOuTFkLv0uHULZNVQlgxflhbTnCSx3avxYdRHeBuC4gWcDocw3RkK+YSj0u9FURMEZlL/BxC4Fg6It9P8en8LIWstDXL/8Nelv1kT7rrnO6HXmXLdMnZyOAQj6cUzUrT633N8JIVmipJvsiY0kCnc1gSugzD73VJpyT8acUPoR2wquCt9+KkpFbJkoFx+MibO4apUBcsYW2SnUPgIIwEtRj0iO5jVAkEnhbvgkPiqxwwjwROeOsmfwTupzCvnlevK68rp/sS047QC+syLLz51d/XEiatHDuFT9O6pU3cpWa/kvvDcBW1dSeodHoPoJpFc2g/sUJOkoDCIFqDCoN4TyzbAmSHnDSR6Z8BzINvp8C+jOA4RuTlW56Mr77l0X9l/6prE5u6mJvKAFBVVB1htcrcYQ0Uzp1A+gVZzRk0z65x1mRZigKp8C9f9PGdHIORN01vNtyy15q9DahK4V1fgEjcmMmQxZ1NwDRNuPaJ6QgV/5XPAKetrNNKJlYl1If0oYJbPbKOoq0YOJAWYA8eTR/M2rbFGQLJ1zPJloU+ZXg0YwHCah4nJVc3g8siTLTZ9oZXBweIkZtORoPPClcwkBBom4cZBX3yitJWzyhXlTsKNN/HVue3gHF49O8eDYG56obyAcW4ud5Ab3aTaRzjUrQU0Fd1LnU57CBd6d+ib2gd8xl6A4ZSFw2DIne3lBohKuGKU0v0UNT8WXRxQMa0TDZyduxhivVvFM1N1RB2ia0RFdWDNDnMs97WCCogC6+PS0a3iehkB3BDNjnI0feO8kXFCQ7tsIRxlMgGyUPaJzgmHFC8eM63E5zApZUtyXuMuikuP5+oUfJdqGDpl8O9g94ZlezoT3hEBgCOY6SsKVSyo/M8gihBPxVdKoDMaynHlaD+/llMDD1Lh1ft9r1Kreahc9rqq2vSaDyDTkdwYoEitGadaNS1mCFu8HxG6B+LDIm/H+8OXIehcv3Ml5xvFKm5uJNwZtbJlFRPdqF67c+fOLiqWUCOy8UroGI3SJnPA+dz5Qly8Y2v1mLSqkyb3G75gRmCqlunlX8/nq4VCr7Jlc+JZHm3mPVz0DanfcajvJJo9mSP9L/g6A/TvceVQHyC6vbq6soKmF9ZB+KI4CAQS98vb+6ZJ++04EO50bDLTBFs31qKjIRc8L5AYzClkkKAwg8NJswb8dJJ5hpQFBp2lUhuV2yhrVKS7NmV5ryenAyn+HiwJ0Ihh/ePUyZxNgnaOcOGoQWBIogpumY/577QnTX1D+s9aAeHPgqMyAOv+Dbj+E1g3hZzbkPVcOll4SHlceaLfc6XsAls55jxTUevydlkJMoeAiUx0SF1X8aEWOqSgrqm2tpVMRtluqWaXrkyfXkk87z7H3E2OMfs7opohy8Bjaey1OQhHfA/5HPzY3I9lPA5998f6G8e2mmbzBjzu7prOjhQuMM8qlwxZx8oguR5N397cciRNOkuA5kKZCIdlswShXTMsLkCHJ7RPP6hUTk3A0ZqE47eFS7bcqs24qeWlbuhvl9ZKnJv0VKT73r9wG9hcONazT7s0fylvkXC2TCA9WgzVCKe4lVSbkVZb4mi7yjVlqR8/rOeRvHxkY/vI2pqMu86yk8+flWf3QWtMrg46rLunUh8wvizh/YIbm/9AkIZSa6jtE3E/FsCEeXDkoVTiHEY54cciECJ32PKeW89ggjRhd0D4e4em0eSUtQJxuovxI5b3rLvY8LXqHDPM5cOoviweglNPYZT9MQCZhNWXZig32FQ5cgnLSl93LQNrumnHZarLVjxhEqfiE35B16wgU1JVJOWs36wywqtgtS3bhEiJz/8n5WcK9VpQmqkOWoeKvQ1aaOrcqXqvFIuedZn09MsLx4+tdLv91Zle75Qfx6fO3L5w7eaFy5eXTy3fNw1OPyy6S0vjHnzMh0NwR68DFzrQ9vFBsTmyTRDI7rCi06oeJGe/6dOiTl39YEJTSZxUPBEb2rQbXJQRka6FC6GKiMbfRM7L1GXS9pPZ90rBKlqlp4FvVxPr6YabclVW4MRrdYNZs5aJ5gTPNV0RWGBpg1yEvYUK4SYHOpW357Jgs/R2ok97g+NNxxW649pCt+1Q0sBmcTKB1gAdfq78Mp2VAmuC43xUqfXthdr8/PbRlZVtoWnRdnQP/i/ePyeFlrUwba7hYYEG3aXFIbtSWP64akkrNxyHyTH+/CdkbVjQsCeZfSLDqd8q4NYENyAEIgJuIkzzau4ryCvgQlWfkmyNuYYhIiuZbyegiUPOEXDH9x9x2Zde4O6dgBsyNunk0mRZkGh+7aXDAj6ucFRyg4BYmPuPZ3yS69mYCUdzfc4lVU3Dth43/xkLqemGYQOGWkNNnqDnBKDnAsTptvJryreUD5W7/c43f3On7FarOxnH2Zmen9+pNZs7ya6HufN716/vXPjgg51j587t3H3xxo2d937j/V9/9/033gh2gnvL8yDB3u+oktAPJovLg5DtOan4fh0/BNi9K+DkUMSPnOxQxECBj30tncTQRJ/ua/6hfN0b4TeHqV9u15YmRip0bJzQfpNicDcbwvkBE7z93KuAxc9CWJH1nPcak68wob7K5F0w/2DFXGRaxNXxMWZSSAZ2fKaT4wSbGfBRyMw/r5umup5xTVXIZKjrM1VbNuyS7niTFi66fqGAZM7Mc13wWeTrOeRpFreu5y8YBqEMgfBxCT/u+00zLymXWqwDU15kFqhKi5zhEbcMIrPCIJiZerZMhU4IdioYvixUwHdKV0PbdzdNz4k9k/hNaWhgIpxM4IAF59x12SOg9UxGCCCYA8be4DbTBLdnTRP8hfn5vyu/UH6aurmsUlPmAMcm+04ljxibPNrrTQJHxJP3bUcMdVV0zxxiqLK6JTxSnkNiSLeFmnuTRLj27U0L2ZvJwGEDYOVcKKpV0uqQbF7nWNPYd7HvYQoCVLebJHSoq9mQrSm49M8vX96KdJDe+YfLBsDISx5phqReJ27s23b0FwlGU2H/QYsUMransdtAeSZNmC6ZXv03oHYREPtIwnT1oGzmFMUMs1mz1euZuhME2MTjw9BxQZmsOR2GHiy+kYDaX25axGFSzemENFn0ty3kexGJQzWE8F+w/cszlnd20XJ/jD0HJZt42vQUtVmZ2JRRQAxXE9NrWsP/SjnG9Z4vVZ63w8N2uGAF34Y1WsywjsHCrpVxBCTvaOwmAbxMtOMvAQkAOZUOrPK2cqxfkNS2y0u6Xt66dKl8vre2Vq5pWvnhbtctuw/aaBpH0sHsM9lo2sPU9tAijnzkPZto8d6Ms3u/Zho68MSYpyO+9wzPlsu4LZHVtpCVQ1NladguKYqAYX2JOtz2C3WpFbNmyA/r9vfmDwcuILA1C6FC0jWF05xE9TlqOChkfxj6QeH5o0fVmRL1bVbpG5yEDT9T9PHCktBVaUhayGRASBpWbLo6M19ZXv4T7WmmZWYdygWdsXXeEG6Xq6an2eqx0KDpft0vgO3/Lu2PfrIrZORBjeeZps3mZw/sgqbYF+9JwAk9dXIDKGuPNUMJd7qhHk+A6GkMJnWjtngfG82rUOl3hW9MhAaLcDFyv0pCiRmUiJrnlbWOE6K5pbowjYg4XsSBdVvM4TteqDVBcIe+r2uXA+ZqKkb0d4gpQT463+A+wVilABqmiTPclvICXCxpOtH5j3Q3PFHgZ5SnlJeUzf6k1us5px+7HSH0gtqdbxQKSva3uuj07W422719Wp06d/GZSjLIWRrJ7Ft7unppX2UP5TXd91eDPcq9rZBGY48qOoNuOVAqyZbUgAfaNeDh/cF8o3EwasmPDBj6j5uPaE0QMbNkzi4wi6rYqibz3mkMAF4krGATnzLGStziyGoegorQLd2PdHURPcknri16aHalLiXN6LYXM/hmQ9hGBXt2En/tw0qlUa2+WpidiEm1xCUOCjzRNT4ljsBUK1oScwNYWvd8nVcBnmqeDmyjYlrr+rEREl3VBFLBGpOskMK5BEmw9UexYUsqnWSOYHz+GSDyT5QMoNQpZVOZ64cbtdzpxelpR4lqp6PodI3g2WW8P0Rz05nPEKGScIDWSTeWRhNgsDL3jC67aSe3B82Z7tgPYx0lA4Sk38PHofuIyt1s5Khkhq3gWSaZMOwOBYtrrVjom/n5pBXnuCsiGXqWi2PX08W3Vv4GcGneNgHFVORPn6yQiT55JJF8czXd9bRSd+rMx5DbP7I8zj08lfNK+QDaTUXIVWlFnjiRKD/5+X9B13088oXLykP9cm16eqE0V5qYgLJfksVihDSmmWakBorSjJr3bmMdeBnNFMed3oPwadwLJ8/hw8uy8xV4vA2r/RXqQuF0Oo7/6Fkn+AkUyPNL8HRl+aNpOBZm4DhReagEuo6eyety2g7nkxtE5gmfFpDdInDQv6Z8S5VYWYLsBtWSBvUIVFcCri2Vs9l8Kf/Akca+V6Vjm+PJf7y5D7TjuQSR22i+cwaOJE8bCWRaX51J3s8wkOaG4zse9oEeTTX73Y2NrXPnLkV69J3AgPy9UzH1/J/9lBW/70HOtclAxsVYk0lDFQvJpIanqPEpKPNQKYPm7Co3lC8qJ/uVLy7eOj+5WPVzi/H5+XZ7cfHk1fPnT9q+f7J3/fpJ5eTeXTb/3zQ+HhN0nc5QJtLu3t506jjT+0vSBY8m9qPdOTq8K2Ig6rudwZ+T30hx5jsBK8zYasMtTOPMRP246axKIYmvUY5QQHIqtChCRi+kjpe1vBchwRdyP1xjNjeoDvLJcDgqoILF1cNUgowLGCsa4NWdYAmtqJ+a2joINqPYWy2RzNo50yMxLjlgMpHnNXG1ANRdlRaZnE2mIJdegsa4BuruWE5g+EUdFdvMVFc8oa/eIO9iQ3WZknrOz5T/TPdEkp3+M8rTynPKrvIl5VeVi/3G1Yenm/HLL3z5sae+fOvWTDmOZ155aev552eePX58pvfMMzPKxMTmzOaDd53G9p/SDai9PXQ6gpL07pIHR7I7dqvPmFIf3EvQbowmKHu3QrTbI9sZNsf6MHn4XWpzrusW04VlZJBvEMbUWWpSDflMy/FYCpetoEXtrYBxRBD4rUm5lU7wt+0CyUF5IyTPUosiP3ZkYHjCs7ZPwLMR/DUHrQRR7uY4Tka6pNpiprYcGvrqTfIWslXP+EvOiWbohqnnoCf0CtfM7uk8nrhRqfwwcy7LualfDHQTQI21JrRmS58/9lGptF1PD+gIN52k/APkylEaSltZUTaUc8nsMrO5vo5OnjmDClGEusvLaKbTAQli1VH9QY0+pr72lPSwxOMoah+4MyZt9OZBDGsnYb3/Fpod5JgonZk/+bHp/q0U72XN30+w4EPDAnuilp5ByLmSGqFr15L5VHLuCJfbq58QHYIHhggK+U8JYluP0dJRQDhL3zKEatGnnZLNwLtkpCboVKFwM+PrFqfuhAuOBleryv8BOdadkAplbmRzdHJlYW0KZW5kb2JqCjM4IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDUxL0ltYWdlTWFzayB0cnVlL0xlbmd0aCA5NS9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAyMD4+c3RyZWFtCgAAAAAwAAEAAAATAAAAFAAAADMAAAAAAAAAAAEAAAAAAAEmAAEAAAA2AAAAFAAAADMAAAAAAAAAAAAAA//9/wL+/v6cSXSlek1gjLNclfYX/3/8Y/kC+XlqgXwRH/+sCmVuZHN0cmVhbQplbmRvYmoKNDAgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNTEvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDE1Mi9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAyNz4+c3RyZWFtCgAAAAAwAAEAAAATAAAAGwAAADMAAAAAAAAAAAEAAAAAAAEmAAEAAABvAAAAGwAAADMAAAAAAAAAAAAAA//9/wL+/v7+mcuucYEh6zWt7cxZDtQfnqRuRA/CE2cl4Ws/sCOtv1NvC3z11H0w84Rwjo0aZ9lG1Eizfe+AG3K3oKfhIUMZdoy/RQTCYzCxzps2A15emCwAJ/+sCmVuZHN0cmVhbQplbmRvYmoKNDEgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNzUvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDcyL1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDE+PnN0cmVhbQoAAAAAMAABAAAAEwAAAAEAAABLAAAAAAAAAAABAAAAAAABJgABAAAAHwAAAAEAAABLAAAAAAAAAAAAAAP//f8C/v7+xDI//6wKZW5kc3RyZWFtCmVuZG9iago0MyAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA1MS9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTQ2L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDI4Pj5zdHJlYW0KAAAAADAAAQAAABMAAAAcAAAAMwAAAAAAAAAAAQAAAAAAASYAAQAAAGkAAAAcAAAAMwAAAAAAAAAAAAAD//3/Av7+/v8GPRmp1Fts9/P+3XJ7pySd44RkAirsa1foY4+7gvfYUNy652yAqFfzZPq47/9/5RYGVyLTabq2xZK4tklWCPK10wViim06rKTEBsfL/6wKZW5kc3RyZWFtCmVuZG9iago0NCAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA1MS9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTU1L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDI4Pj5zdHJlYW0KAAAAADAAAQAAABMAAAAcAAAAMwAAAAAAAAAAAQAAAAAAASYAAQAAAHIAAAAcAAAAMwAAAAAAAAAAAAAD//3/Av7+/v8GQ0RMIY1OhJXH+KxY9myC3bx6QUg0TySROc99RK5WHMtzJTvtXn+nLldTJO6Ms/kKJd7G6exxuPLXFXu6Hs5MTkZLfUwqqkssLMP2ubv7hjvwiBP2/6wKZW5kc3RyZWFtCmVuZG9iago0NSAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA2Ni9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggODUvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMTM+PnN0cmVhbQoAAAAAMAABAAAAEwAAAA0AAABCAAAAAAAAAAABAAAAAAABJgABAAAALAAAAA0AAABCAAAAAAAAAAAAAAP//f8C/v7+/2EuUVsAE54If/9/+UPwP/+sCmVuZHN0cmVhbQplbmRvYmoKNDYgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNTEvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDE1Ny9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAyOD4+c3RyZWFtCgAAAAAwAAEAAAATAAAAHAAAADMAAAAAAAAAAAEAAAAAAAEmAAEAAAB0AAAAHAAAADMAAAAAAAAAAAAAA//9/wL+/v7+abv9EqVp3v1WJRKqgFI3dX+fe36dAa3jh7kVGGCpVMMfigP6ldYfvD1I6TYSBmgFJetwjuEPWz0EseCSb41cS8zJbuKCGzVKWhmX12Fv/SWZlwqSnBYN/6wKZW5kc3RyZWFtCmVuZG9iago0NyAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA1MS9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTM0L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDI3Pj5zdHJlYW0KAAAAADAAAQAAABMAAAAbAAAAMwAAAAAAAAAAAQAAAAAAASYAAQAAAF0AAAAbAAAAMwAAAAAAAAAAAAAD//3/Av7+/v9yBN6en+lUAK2KybARV9IGtusUK3sNZQHVLPYYnyU6d0PvOWHPZ6yGx8htacn5LBVxM1cDAJHw6v53EmUyJ8E//6wKZW5kc3RyZWFtCmVuZG9iago0OCAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA2Ni9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggODYvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMTM+PnN0cmVhbQoAAAAAMAABAAAAEwAAAA0AAABCAAAAAAAAAAABAAAAAAABJgABAAAALQAAAA0AAABCAAAAAAAAAAAAAAP//f8C/v7+/2EuUQIAGDngh/9//2PI0H//rAplbmRzdHJlYW0KZW5kb2JqCjUwIDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDQ1L0ltYWdlTWFzayB0cnVlL0xlbmd0aCAxNDgvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMjU+PnN0cmVhbQoAAAAAMAABAAAAEwAAABkAAAAtAAAAAAAAAAABAAAAAAABJgABAAAAawAAABkAAAAtAAAAAAAAAAAAAAP//f8C/v7+/vmXGPc3+SYxytw0lk2AUOmAcGtWd1vtsJGusrMnMxe7rkX2v+wnVsfRk89IVJc63WCs4D4nmu6se2nRlnOzIp4CUYQWoUWjAaJy7ZrMj/+sCmVuZHN0cmVhbQplbmRvYmoKNTEgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNDUvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDE0NS9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAyND4+c3RyZWFtCgAAAAAwAAEAAAATAAAAGAAAAC0AAAAAAAAAAAEAAAAAAAEmAAEAAABoAAAAGAAAAC0AAAAAAAAAAAAAA//9/wL+/v7+mbuOYUX+NF2h1VpafwA2dFzZc8gQYnZ88nl4/eNOw9fOCTa2/A8CpQfLOMSMJNWHn6CS7m6JkVvO4CoauuouRw5zZd9glvd9GlBN/6wKZW5kc3RyZWFtCmVuZG9iago1MiAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCAxL0NvbG9yU3BhY2UvRGV2aWNlR3JheS9EZWNvZGVbIDEgMF0vRmlsdGVyL0pCSUcyRGVjb2RlL0hlaWdodCA0NS9JbWFnZU1hc2sgdHJ1ZS9MZW5ndGggMTM1L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDI1Pj5zdHJlYW0KAAAAADAAAQAAABMAAAAZAAAALQAAAAAAAAAAAQAAAAAAASYAAQAAAF4AAAAZAAAALQAAAAAAAAAAAAAD//3/Av7+/v75PCiL2ewc1y8GO8rhzHThFG92bBrvOVCzY7XxIaAhZBUjD1J10nfJSGY5ADwuwEBSKND0GbjxL86/Gg25vec53/+sCmVuZHN0cmVhbQplbmRvYmoKNTMgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNDUvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDk1L1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDE4Pj5zdHJlYW0KAAAAADAAAQAAABMAAAASAAAALQAAAAAAAAAAAQAAAAAAASYAAQAAADYAAAASAAAALQAAAAAAAAAAAAAD//3/Av7+/v988ThDpyxrzPqHvTTd/3//S9MJD/AgOjYK/6wKZW5kc3RyZWFtCmVuZG9iago1NSAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCA4L0NvbG9yU3BhY2UvRGV2aWNlUkdCL0ZpbHRlci9EQ1REZWNvZGUvSGVpZ2h0IDE3NS9MZW5ndGggNjI0OS9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAxNDQ+PnN0cmVhbQr/2P/gABBKRklGAAEBAAABAAEAAP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAK8AkAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APf6KKKACiiigAooooAKKK8W+L/xfGhrN4c8OTg6oQUurtD/AMew7qp/56ep/h+vQAT4wfF4aKk/hvw5cZ1MgpdXcZ/49h3RT/z09T/D/vfd5j4QfGE6S0HhvxNck6eSEtL2Rv8Aj39Ec/8APP0P8PQ/L93xJmLMWYksTkk96SgD7/ByMjpRXzl8HPi+NMFv4Y8S3GLHhLK9kP8AqPSNz/c9D/D0Py/d+jaACiiigAooooAKKKKACiiigAooooAKKK8Y+L/xeXQUm8O+HZw2qsCtzdIci1HdVP8Af9/4fr0AE+L/AMX10JZvDvh2cHVCCl1dIeLYd1U/89Pf+H69PmlmZ2LMSWJySTyTQzM7FmJZickk5JNJQAUUUUAFe5/B74w/2f8AZ/DPia5/0PiOyvpG/wBT6Ruf7no38PQ/L93wyigD7/or50+D3xh+wfZ/DPia5/0TiOyvpG/1PpG5/uejfw9D8v3fougAooooAKKKKACiiigAoorxn4vfF5dASbw94enDaqw23NyhyLUf3V/2/wD0H69ABPi/8Xl0BJvDvh6cNqrDbc3SHItR/dU/3/8A0H69PmhmZ3LuxZmOSSckmhmZ3Z3YszHJJOSTXbeDfhV4n8Z7J7W1FppzH/j9usqhH+yOr/gMcdRQBxFKAWIABJPAAr6m8OfADwppKJJqrT6vcjBPmsY4gfZFOfzJr0jTNC0jRovL0zS7OyTuLeBUz9cDmgD4ng8K+IrpA9voGqTIeQ0dnIwP5CnyeEPE0S7pPDuroo7tZSD/ANlr7looA+A5YpIZGjljaN14KsMEfhTK+9b7TLDVIDBqFjbXcTdUniV1P4EV594h+BngzWw72trJpVy3Iks2wufdDlcfTFAHyXXuvwe+MP2H7P4Z8TXP+icR2V9I3+p9I3P930b+HoePu8n4x+Cnifwskl1bRjVtPTkzWqneg9Wj5I/DcOOSK82oA+/6K+dvg98YfsX2fwz4muf9F4jsr6Q/6r0jc/3fRv4eh4+79E0AFFFFABRRXL+PvGdr4G8LT6rOFkuG/dWkB/5aykcD6Dkk+g9cUAct8ZPiQnhLRH0rTLorrt4g2GPBNvHnlz6EjIH59q+Vo47i+u0iiSSe5ncKqqCzyOT0A6kk1Y1TU77XdWuNR1Cd7i8uZC8kjdWJ7Adh2AHAAAFfTPwf+FcXhSyj1zWIQ+uTplEYf8eiEfdH+2R1PboO+QDL+G3wLtNNjh1bxbEl1ekBo7A4aKH/AH+zt7fdHv1HtiqFUKoAUDAA6ClooAKKwfEvjPw/4QW2bXtQFmLksISYnfdtxn7qnHUdam8OeKtF8W2Ut5od6Lu3ik8p3EbphsA4wwB6EUAbFFclp/xL8Kal4nufD8Gqx/boXEa7+EmbuI26MQeMdc9M11tABRRRQAV5b8RfgxpXixJdR0hYtO1nBYsoxFcH/bA6H/aHPPOa9SrJXxPob68uhJqtq+qMrN9lWQFxt6ggdDjnB5wCe1AHxFquk3+h6nPpup2slteQNtkikHI/xB6gjgjkV798C/iWLu3Twnrd4xuk40+WU/fQD/VZ9RjjPbjsBXdfE34b2fj3RyYwkGs26n7Lckde/lv6qf0PI7g/ItzbXujapJbzpLa31pLtYZ2vG6n1HcEdRQB960V558JPiGvjjw6Yr2RRrViAlyoGPNX+GUD3746H0BFeh0AFfH/xe8bHxj40mFvLu0vTy1vaBTlWwfnk64+Yjg/3QtfRHxc8Tt4W+HeoXMMhS7usWdswyCHcHJBHQhA7A+oFfH1paT397BZ2sZluLiRYoo16szHAA+pNAHsHwD8BrrOrv4n1CINZ6fJttUYAiSfru+iAg/Ujng19M1keFvD9v4W8MafoltgpaQhGcDG9+rtjtliT+Na9ABRRRQB4b+0rCG0PQZ+6XMifmoP/ALLWd8JfDN54q+D+q6dZ65daS8mqSq7wKCJB5MXyt0bH0I685rZ/aS/5FLSP+v8AP/otqtfs4/8AJPNQ/wCwrJ/6KioA8R8Y/DLxL4Icy39r51jnC3ttlo/bPdT9QPbNdl8Ovjlf6E0OmeJmlv8ATB8qXP3poB7/AN9fryO2cYr6ZlijnieKWNZI3BVkcZDA9QR3FeBfE/4Gqkc2t+EID8uXn0xeeO5i/wDiPy7CgD3fT9Rs9W0+C/0+5jubSdd0csbZVh/n8qqeIPEOl+F9Il1TV7pbe1j4yeS7dlUdST6CvlL4a/E7UPAWpCGXzLnRZn/0i0zyh/vx56N7dD0PYil4v8Xa58TfFMZ8qVw7+VYafFlhGCeAB3Y8Zbv7AAAA6Hx38bdd8TyS2ekvJpWlHICxtiaUf7bjpn+6OOxJrnPBXhXxpqWqW2qeGdPuxNBIJI7wgJGrA/3mwp9xzkcYr274e/AvTNFhi1HxPHFqGpEBhbH5oIPYj+M/Xj0B617AiLGioihVUYCqMACgCjokmqyaRbtrcFrBqO398lrIXjz6gkAjPpzj1PWvG/2gPAS3VivjDT4QLi3Cx36qPvx9Fk+q8A+xHQLXulQ3dpBf2U9ndRLLbzxtFLG3R1YYIP1BoA+J/BHiu58GeLLPWbfcyRtsuIlOPNiP3l/LkZ6EA9q+2LS7gv7KC8tZVlt7iNZYpF6OjDII+oIr4f8AFnh+bwt4r1LRJiSbSYojNjLoeUbj1Uqfxr6J/Z88TNq3gufRp3LT6TKFQkf8sZMsvPchg49gFoA4/wDaT1hpNb0XRF3BILdrp8NwxdtoyPUCM/8AfVct8C9ETWPidaSyhGi06F7xlcZyRhVx7hnVv+A1U+NF4Lz4sa2VkLpEYolz/DtiQMB/wLdXf/sz2qmXxJdtGN6rbxJJjoD5hYfov6UAfQVIzKilmYKqjJJOABS1DdWsF9Zz2l1EstvPG0csbdHVhgg+xBoA8Tb9oywt/E99bSaW9xoyS7Le6t2xKVHBYq3BBOSOQQMZ5r0HQvin4M8QBVtNct4pm/5Y3R8l8+nzYBP0Jr5W+IHh2Lwp471bRbdt0FvKDFk5IR1DqCe5AYDPtXbwfs/eIL/RLHU9O1TT5VuraOcRTb42G5Q2OAQevtQB3H7SDK/g/RmVgym+yCDkH921W/2cf+Seah/2FZP/AEVFXh3i3wP4t8HWECa5E0enyS4h2XKyRl8HooPBxnkgV7j+zj/yTzUP+wrJ/wCioqAPYKKKzPEWtQ+HfDmo6xcYMdnA8u0tjeQPlXPqTgD3NAHyj8Zn0xvijqy6ZBHEqFFnMbZWSbaC7Y7HJwR6qT1Nbf7Pup6ZZePJLS9tozd3kBSzuG6xuMllHYblzz1+UD+I1y3gXQLjx/8AEW2trxnmW4na6v5TnJQHc5JHTcflz6sKPGei3Pw8+JNxBZM0f2O5S6sJCM/JkOnXrj7p9SpoA+z6KoaHq0Gu6DYatbjEN5Ak6qSCV3AHBx3HQ+4q/QAUUUUAfNv7SOipbeItI1mMAfbbdoJAFx80ZBDE9yRIB9ErA+AusNpnxNt7U48rUYJLZtzYAIHmKfc5TH/Aq9U/aKtDP8PLWdUBNvqMbM2OVUo6/wAytfOvhO+j0zxjol/KxWK2v4JZCDj5VkUn9AaALPj1i3xE8SliSf7UuRz6CVhXuX7NioPC2ssPvm9UH6bBj+ZrxT4j2kll8SvEcUowzahNKPo7Fx+jCvWv2Z7gmLxLbFhtVraRV78+YCf0WgD32iiigD5A+Nv/ACV7Xf8At3/9J46+pfB//IkaB/2Drf8A9FrXy18bf+Sva7/27/8ApPHX1L4P/wCRI0D/ALB1v/6LWgDy/wDaS/5FLSP+v8/+i2q1+zj/AMk81D/sKyf+ioqq/tJf8ilpH/X+f/RbVU+C2jv4g+DGv6VHeTWclzqEqJcQuVZG8qEg8c4yOR3GR3oA9hsfEejanq15pVjqNvcX1mA1xDG+SmSR9Oo5x04zjIry/wDaK142Hg+y0WNismpXG6QAcGKLBIP/AANoz+Brw7w9q+qfDXx+lxNE8dxYTmC8twf9YmcOvocjkHpkKa3/AI3+JoPEnjxTZSiWytbOFIZFbKyb183cPT74H/AaAPQv2b/Dyw6VqviKVB5lxILSAleQi4ZyD3BJUfVKq/tKaGNuia/HGMgvZTPnr/HGMf8Af2vUPhdpf9j/AAx8P2pYsWtRcHIwQZSZMfhvx+FYvx10+O9+FWoSuhZ7OWGePHY7whP/AHy7UAZv7Petf2h8PpNNd1Mmm3Txqg6iN/nBP1YyflXrVfN/7NeomLxHrel7fluLRLjPp5b7f/av6V9IUAFFFFAHnnxwVT8JNYLYyGgK/Xzk/pmvkOvqf9oa8e2+G0UKdLnUIon+gV3/AJoK+W4YZLieOCJS0kjBFUdyTgCgD0r496bJY/FO7uHYFb+2huEA7AL5WD+MZP41L8ANXXTfiUlpJu26jayW4+bADDEgJ/BCB/vV3X7SOgmbSdI1+JFzbStazEKSxVxuQk9gCrD6vXz9peoz6Pq9nqdqVFxaTpPHuGRuVgRn2yKAPvSiqOi6ta69ollqtk262u4VlTJGQCOhx3HQjsQavUAfIHxt/wCSva7/ANu//pPHX1L4P/5EjQP+wdb/APota+WfjYQfi9ruD/zw/wDREdfUXghzJ4B8OOeraXbE/wDfpaAPM/2kv+RS0j/r/P8A6LarX7OP/JPNQ/7Csn/oqKqv7SX/ACKWkf8AX+f/AEW1Wv2cf+Seah/2FZP/AEVFQBzn7RHg0JJa+LrOLh8W19tHfH7tzx6fKSfRBWJ8F/D/AIO8ZwX+i67payapB+/gnWeRGeI4BGFIGVOOvXd7V9F+IdEtfEnh6/0a8H7i7haMnGSh7MPcHBHuBXxLINV8La9cQx3E9jqVlK8DyW8pRkYEqwDKc46/UUAfdccaQxJFGoVEUKqjoAOgrnfiDAlx8OfEiSKGA024cA+qxlh+oFfMEJ+LNxBHPA/jOWGRQ6SI10VZSMggjqCKJrT4s3MEkE8PjOWGRSjxuLplZSMEEHqCO1AGh8Bb57T4qWcK9Ly3mhb6BDJ/OMV9Z18UWfhHx3pl0l5ZeH/EVpcR52TQWk0brkYOGAyMgkfjV+U/FJR++PjAD/aNzQB9kUVxvwpa/b4Z6OdTNyb3bL5pud3mZ818bt3PTHWuwd0jjaSRgqKCWZjgADuaAPnn9pTWA+o6HoiO4MUUl3Kv8J3kKn4jY/515j8NtOl1T4leHbaFVYi+jmYN0KRnzG/8dQ1D498Sf8Jb421TWVJ8iaXbACCMRKNqcHoSACfcmvRP2c9B+2+LL/W5UVo9Pt/LjJzkSyHAI/4Arg/7woA9/wDFnh+HxV4U1LRJiFW7hKo5zhHHKNx1wwU49q+H7y0nsL2ezuomiuLeRopY26q6nBB+hFffNfOn7QPgRrW+Xxhp8JNvcbYr9VU/JJ0WQ+gYYU9OQOpagCx+z546WNpfB1/LgOWm09m9erx/+zD/AIH6ivoOvgW2uJrO6hubaV4p4XEkciHDIwOQQexBr67+F3xJtPHmjCKdkh1u1QfarfpvHTzE9VPcfwk47gkAsa18JfB3iHWLnVdS06WW8uGDSOLmRckAAcA4HAFdbpun2+k6Za6daIUtrWJYYlLFiqKMAZPJ4FWqKAPFf2kiP+ES0cZ5+3H/ANFtVr9nH/knmof9hWT/ANFRUz4/6HrevaZolto+l3V9smlkl+zxl9nCgZx0zk/lWj8BtG1TQfBV9Z6tp9xZTtqLyqk8ZQspjjGRntlTQB6lXzB+0N4cGmeMrbW4lxDqsPz8/wDLWPCnjsCpT6nNfT9ea/HXRP7X+GdzMiM0+nzx3MaouSedjD6bXJ/4DQBU+Avipdc8DjSZpC15pDeUdxJLQtkxn6Dlcdgg9a9Vr5n+Dng7x1ovi2z1pNGlt9NkBguvtbCEtE2CSFb5jghWGBzjGcE19MUAFFFFABXkPx58croXhz/hHLOX/iYaohEuOsdv0bP+9yo9t3Tiu48c+N9N8C+H31G+PmTtlLW1VsNO/p7Adz2HqSAfjfXdbvvEet3er6lL5l3dPvcjoOwUDsAAAB6CgDOr7I+E3hRvCPgCytJ4yl7dZu7pTkFXcDCkHoVUKpHqDXg3wU8Bt4q8Urqd7CW0jTHEkm5crNL1SP3/ALx68AA/eFfWFABVbUNPtNV0640++gWe1uIzHLG3RlPUe31FWaKAPjL4j+ALzwF4ha2YSS6bOS9ncsPvr/dJHG5eh/A965rSdWv9D1S31LTLqS2vLdt0cqHkH+RB6EHgjg19ueJPDemeLNEn0nVrcS20vII4aNuzoezD1+oOQSK+SviB8NtY8BX3+kKbnTJXK298i/K3cKw/hbHbvg4zg0AfQPw4+L+leNIorC/Mdhrm3BgJxHOR1MZP57TyPfBNelV8AAkEEHBHQ16z4L+POv6AsdnraHWLFeA8j4uEHHR/48c8Nyf7wFAH1NRXFeHPiv4N8TIi22rxWty2B9mvSIXyegGflY/7pNdqCCMg5FABRRRQAUUVzHiH4h+FPC4ddU1q2SdDg28TebLnGQCi5I+pwPegDp64vx78S9E8B2ZF1ILnU3TdBYxN87ehY/wLnuffAOK8g8Y/tDalqKPaeF7Q6dA3Bu5wGnI46Lyqdx/F7YNeMXFzPeXMlxczSTzysWkllYszk9SSeSaANXxT4q1bxhrUmqavceZM3CRrwkS9lQdgPzPU5PNO8JeFdS8ZeIINI0yPMj/NJKR8sMY6ux9B+pIA5NSeEfBes+NdVFjpFtuC4M1w/EcKnux/A4HU4OBX1z4H8D6X4E0NdP09fMmfDXV264ed/U+ijJwvb3JJIBf8MeG9O8JaBbaPpke2CFeWP3pXP3nY9yT/AIDAAFa9FFABRRRQAVXvbG01Kyls762iubaUbZIpUDKw9wasUUAfPXjn9nyaN5L7wdIJYycnTp5MMvPSNzwRz0Yg8dSTivDr/T73S7x7PULSe0uY8b4Z4yjrkZGQeelfe1ZeueHNG8S2f2XWdNtr2IAhfNTLJnqVbqp9wQaAPhStTTfEuu6NH5el6zqFlHu3FLe5eNSfcA4NfQeu/s5aBeyGXRdUu9MLMSYpVFxGB6Lkqw+pZq4DUv2evGVnG8lpJpt/gkLHDOUcj1+dVUf99UAYUPxl+IEEaxp4ikIUYBe3hc/mUJNOb40/EJgQfETYPpaQD+SUk3wY8f28Zkl0Dao6n7ZAf/Z6ZbfB3x7dqWg0HeB1P2yAfzegDB1Pxj4m1lJI9R1/UrmKX78Uly5jP/AM7f0rEr1LTf2f/HF8rG4i0/TyOi3NzuJ+nlh67rRf2bdOhYSa5rtxc/KD5VpEIgG7gs24sPwU0AfO8EEtzPHBBE8s0jBEjjUszMeAAByTXr/gf4BavrBjvfEzvpdiRuFuuDcyDAIyORGOe+TxjaOte/8Ah7wZ4c8KRldE0i3tGIIaUAtKwJzgu2WI4HGcVu0AZ2iaDpfhzTE07R7KK0tUOQkY6n1JPLHgckk8Vo0UUAFFFFAH/9kKZW5kc3RyZWFtCmVuZG9iago1NiAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCA4L0NvbG9yU3BhY2UvRGV2aWNlUkdCL0ZpbHRlci9EQ1REZWNvZGUvSGVpZ2h0IDE0NS9MZW5ndGggNjE1OC9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAxNDU+PnN0cmVhbQr/2P/gABBKRklGAAEBAAABAAEAAP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicgIiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAJEAkQMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APf6KKKACiisvxB4i0rwvpMmp6xeJbWyHaC3LO3ZVA5Y+w9CegoA1K5PxV8SfC3g/fHqmpobtRn7Hb/vJicA4Kj7uQRjcQD614L45+OuueIXks9BaXSNNyRvRsXEozwS4+50HC+4JIryy1tbrULtLa0gmubmVsJFEhd3PsByTQB7jrv7Sd48jJ4f0KCKMMcTX7ly6/7iEbT/AMCauA1L4wePNUjeOXxBNDGxyFtY0hK+wZAG/Wt7w58AfFmsCObU2t9Ht2IJE58ybaRnIRePwZlNejaX+zl4YtkibUtS1G+mX74Rlhjf/gIBYf8AfVAHgL+OPFsi7X8U62ynsdQlI/8AQqSPxr4rhGIvE+tIPRb+Uf8As1fUQ+CXw8GP+Kfz9by4/wDi6Vvgp8PGOT4eH4Xk4/8AZ6APm/Tfip460rd9n8TXz7uv2phcfl5gbH4V3Gi/tHeILQqmsaVZahGq43wkwSMfUn5l/AKK9A1P9nvwZeuz2j6jp5xhUhnDoD6neGJ/OvPdf/Zz8QWMbS6JqVrqiqufKkX7PITnouSVP1LCgD1nwx8ZfB3iZ1hF+dOu2OBBfgR7unR8lTycAZyfSvQK+ENY0PVPD96bPV9PuLK4GcJMhXcM4yp6MOOoyK6vwT8WfEngt44I5zf6WpANjcsSqjP/ACzbqh69OOckGgD7EorlvBXxA0Lx1Yedpk+y5QZns5cCWL3x3Xp8w457HiupoAKKKKACiiigAoorM8Q6/YeGNBu9Y1KQpa2ybm2jLMegVR3JJAH17UAZnjjxxpfgTQ21DUG8yZ8ra2qNh539B6AcZbt7kgH5E8WeMNY8Z6u2o6vcFzyIoV4jhU/woO3bnqe5NL4x8W6h408RT6vqDEFzthhDZWGMdEH+PcknvXpvwf8Ag+NaEPiTxJAf7NyHtLNx/wAfPo7j+56D+L/d+8Ac78O/g7q/jXy9QvC+naLkfv2X95OO4jU9u248c8bsEV9LeF/BegeDrL7Po1hHCxUCSdvmll/3nPJ9cdB2AreVVRAiKFVRgADAApaACiiigAooooAKKq3+pWGlW/2jUb22s4NwXzbiVY13HoMsQM1PDNFcQrNBKksTjKujBlI9iKAKesaJpniDT3sNWsYLy2frHMucHGMg9VPJ5GCK+fPiF8BbvS1l1Pwn5t7aDLvYt800Y6/If4x14+90+9X0lRQB8GaXqt/oeqQajpt1Ja3lu26OWM4IPp7g9CDwRwa+rPhf8VLTx1afYrwR22uQpmSEcLMo/jT+o7fSsT4tfB+DxDBPr3h+BYtYUF5rdBhbv1IHZ/fv355r5t0/UL7RNUgvrKaS2vbWTdG68MjD2P5EHr0NAH3pRXHfDfx5bePfDK3oEcWoQER3tup+4/ZgOu1uo/EZODXY0AFFFFABXy38d/HLa/4mPh+zlP8AZ2lOVkwTiS46MSP9nlR77uxr3z4h+KB4Q8D6lqyOouVj8q1BI5mbhcA9cZ3Eeimvi6CCe+vI4IUea4nkCIi8s7scAD1JJoA9C+D/AMPP+E28Qm6v42/sawYNPxxM/VYgf1bHbjjcDX1siLGioihVUYCgYAHpXPeB/Ctv4N8JWWjwhTJGu+4kUf62U8s3vzwM9gB2roqACqOsavY6DpNxqmpz+RZ26hpZNjPtBIHRQSeSOgq9XIfFNBJ8L/EKntaE/kQf6UAT+HPiL4U8W6i+n6Hqv2u6SIzNH9nljwgIBOXUDqw/Ouor4k8E+KtZ8Ia1LqGhwRzXT27QsskRkGwspJwCO6iu+/4Xl8Rf+gZaf+AMn/xVAH07WTqfinw/ot0LbVNb06ynZA4iublI2KkkA4J6cH8q+eP+F5fEX/oGWn/gDJ/8VXAeNfFOs+Ltbj1HXII4bpIFhVY4jGNgLEHBJ7saAPevjFpPiLx9pGkW/hOzj1PStzXMlzDdRBHblVAy4zgbunHIrwG807xV4E1NTcRalo12QQkqM0W8DrtdThhyOhNfWXwuTy/hh4dA72an88n+tcT+0gB/wgumNgZGpKAf+2UlAHQfBnxhf+MPBTTapKJr6zuGt3lwAZFwGVjjjOGx+FeiV4r+zaP+KS1g/wDT8P8A0Wte1UAFfPHx6+HKWrN4w0mBUikcDUY04AcnAlA9zw3uQe5NfQ9QXtlb6jYXFldxLLbXEbRSxt0ZWGCPyNAHxn8OvGc3gfxdbakCzWb/ALm8iUZ3xEjOB6jhh05GOhNfZ8E8VzbxzwSpLDKoeORGyrKRkEEdQRXxD4y8NzeEfFmoaJMSwt5P3Tn+OM8o31KkZ98ivor4BeKn1vwVJpNzIz3OkOIgWySYWyY+T6YZcDoFWgD1iiiigD58/aT10mfRfD8bsFVWvZkxwckpGc+oxL+dcn8B/Dq618Q472aPdbaXEbk5XKmQ/KgPocksP9yqPxtv2vvivqy+cZIrYRQR+iARqWUf8DL/AJmvUv2bdNjh8K6xqeGEtzeiA56FY0BGPxkb8qAPa6KKKACuQ+KT7Phh4hJ/59GH5kCuvrnPHmiXniTwRquj2DRLdXUQSMysVX7wJyQD2BoA+fv2d5Y4fiFeNLIqL/ZkgyxwP9ZFX079utP+fqD/AL+CvmD/AIZ48af899J/8CH/APiKP+GePGn/AD30n/wIf/4igD6f+3Wn/P1B/wB/BXzB+0NLHN8RLVopFdf7NjGVOR/rJKP+GePGn/PfSf8AwIf/AOIo/wCGePGn/PfSf/Ah/wD4igD3v4Ztu+Gfhwj/AJ8Yx+Qrh/2kP+RE03/sJp/6Kkr0PwPo134e8FaVpF+YzdWkHlyGJiy5BPQkDtivPP2kP+RE03/sJp/6KkoAg/Zt/wCRS1f/AK/x/wCi1r2qvFf2bf8AkUtX/wCv8f8Aota9qoAKKKKAPAv2kvDymHSPEkagMGNjMcnJBBePjpxiT8xXDfAvXP7H+JlpA7osGoxPaOXPAJG5Me5ZVX/gRr3/AOLulnVvhbrsShd8MIuVLDp5bBzj32qw/GvkXRdSfRtd0/VI1DvZ3MdwqnoSjBsfpQB940UUUAfEPj1i3xE8SliSf7UuRz7StX0z8DIUi+EulOqgGWSd3PqfNdf5KK+ZvHgI+IfiXIx/xNbr/wBGtX018DpVk+EmkKrAmN51Yeh85z/IigD0SiiigD5f8d6t8Q0+IWtw6LdeIzZpckRJamZo1GBwoHGPpWBeeL/ippFss1/feILSBnCCS5hdFLHkDLL14PHtX1/XkPxd+H3jDx3fW39nXGmppdmhMUEk7rJJIfvMRs2jsBz6nvigDymPxB8YpY1kjPid0YZVls5CCPUHbTv7c+M393xT/wCAUn/xFVl8H/FLwG/2mystWtFLbmbT5fORsd3WMsMf7wxXT+Gf2idasXS38SWMWowg4aeACKYc8kj7jfQBfrQBg/258Zv7vin/AMApP/iKP7c+M393xT/4BSf/ABFfSfhbxpoPjKx+06LfJMVAMsDfLLFnsynkfXkHHBNGueNvDHhsONX1yytpEALQmQNLz/0zXLH8qAPmz+3PjN/d8U/+AUn/AMRWbrcXxP8AEdolrrGneJL2CN/MWOWxlIDYIz930J/OvWtf/aN0S0LxaFpdzqEgJAlnIhj9iOrH6ELXlmt/F/x34qmFrDfSWiSkBbbS0MZY+zDLnPpux7UAVtFh+Jvhq2lg0fTvEdlDI+91isZQC2MZPy+lT3OufFgAtPceKogOp2TIB+QFew/AiLxVp2jXuma7pF7bWSyGa1mul2MGJ+dNrHdgn5gcYzu55FevUAY3hCS5m8FaDLePK90+nW7TNKSXZzGu4sTznOc5rZoooAyPFdt9t8H63a/89rCeP842FfC9fdPim5Fn4R1q6b7sNhPIfwjY18LUAfRf/C1tQ/57/oaKq/8ACr9S/wCecv8A3zRQB578abH7D8V9ZCxGOOcxTpn+LdGu4j/gW6vWP2b9Sjm8Iarpu8ma2vfOKnoEkQAY/GN6wf2k9Ddb7RfECLIyPE1lKcfKhUl0/E7pP++a5v4A+IRpHxA/s6WQrb6rCYcZAXzV+ZCfwDKPd6APqqiiigAqlq2rWOhaXPqWpXAt7OAAySlSQoJAHABPUivOPjf4t8QeENH0m70HUPsjTXDxzHyY5N3y5H31OOh6Vi+ArzXfi58NfEWma7rGZpZ0hjuPsyfu1G1/uptzyPXvQB38PxT8DTjKeJrAf77lP5gVz3ip/hN4zgb+1NY0UXLD5byG6SOdeOPm749GyPauTX9maIfe8VufpYAf+1KkX9mizGd/iec+mLMD/wBnoA8V8R6XH4Z1+e00zW7fUbYr+6u7OUEOjcYbB4PYj+hrqvC3w+8L6rpltf6z8QNLsDKAzWa481R3DFmG1vwI+tT/ABQ+FEXw+0ywvYNUkvUuZmhYPCE2nbkdCfQ1P8M/hNYfEDQLi/fW5bSe3uDC8KQB8DaCGzkdcn8qAO60jwd8E9Lw02uWOoyBtwa81JTj22oVUj6g12tn44+Gnh+BotO1XQ7OInLJZqqgn1wg5rhD+zRY4OPE1wD72i//ABVRN+zPCR8viqQH3sAf/alAHtei63p3iHTI9S0q6W5s5CypKqkAkHB6gHqK0K8wvY7z4NfBx1sJ4NSuLKUbZJ4SiN5kvOVD54DetUfhN8VNc8e6/e2OpWenwQW9r5wa2RwxbcowdzHjBNAHrtFFFAHGfFnU/wCyfhdr84AZpbf7MAT/AM9SIz+QYn8K+P8ASdOl1fWbHTICBLeXEduhPQM7BR/Ove/2kfECpY6R4djZTJJIb2YAnKqoKJ+BJf8A74rzz4I6H/bXxOsHeNHg09HvJAxx90YQj3Dsh/CgD67ooooA5L4l+Fv+Ev8AAeo6bHGHvFXz7TjJ81OQBkjBYZTPbca+NLO7uNPvoLy1kMVzbyLLE4HKupyD+BFffFfKfxx8Dv4a8WPrFpERpequZQQOIp+rp17/AHh06kD7tAH0h4P8S23i7wrYa1bYAuI/3kYOfLkHDr+Bzz3GD3rcr5R+C3xDXwhrzaXqUwTRtQcB3dsLby9A/oAeA3tg5+Wvq4HIyOlAHin7STqPCejxk/M18WA9gjZ/mK8x+HHxYk+HumXlkmjpfC5mEu9rgx7cLjGNpzX1VqeiaTrSRpqul2V+sRJjF1bpKEJ643A4rO/4QTwf/wBCpof/AILof/iaAPGv+GmJ/wDoVY//AAOP/wAbo/4aYn/6FWP/AMDj/wDG69l/4QTwf/0Kmh/+C6H/AOJo/wCEE8H/APQqaH/4Lof/AImgD598U/GnTvGVnbWeteDxNbwTeesaakybm2leSEzjDHoRTfDXxi0Xwf8AaP7B8Cx2YuNvm/8AE1lk3bc4++p6ZP51f+PjeHNKuNP0DRdG0uzul/0m6ltbSONwCCEQlQDzySP92o/gF4Js9f1HUdY1axgu7G1QQRRXEQkRpW5JwQQdqj/x4UAan/DTE/8A0Ksf/gcf/jdH/DTE/wD0Ksf/AIHH/wCN17L/AMIJ4P8A+hU0P/wXQ/8AxNH/AAgng/8A6FTQ/wDwXQ//ABNAHzz43+N0vjTwpdaG+gpaCdkbzhdF9u1g3TYPT1rR/ZtcDxbrCcZNiD+Ui/417r/wgng//oVND/8ABdD/APE1d03w3oWjTtPpei6dYzOuxpLW1SJmXOcEqBxkDj2oA06iubmCztZrq5lSKCFDJJI5wqKBkknsAKlrwP49/ERUibwdpUx8xsNqMqHgDqIs+p4LfgO5FAHj3jnxRL4x8YahrL7hFK+23jb+CJeEGMnBxyccZJr379nzwu2k+ELjXLhCtxqsgMYPaFMhe2Rli59xtNeCeA/CNx428W2mkQ7lhJ8y6lH/ACyhH3j0PPQD3Ir7VtbWCytIbS2iWK3gjWOKNRgIqjAA9gBQBLRRRQAVjeKfDNh4u8O3WjaigMUy/I4HzROPuuvuD+fIPBNbNFAHwz4o8Mal4Q1+40jVItk8Ryjj7kqHo6nuD+nIOCCK9g+Dnxfjs4YPDHiW5CQLhLK9kbiMdo3PYeh7dDxjHrHxA8Aad4+0T7Jc4gvYcta3YXLRN6H1U8ZH9RXyN4l8Mar4S1mXStXtjDOnKsOUlXs6Hup/xBwQRQB9z0V8r/Dn42aj4Tjh0vWkk1HR0G2Mg5mtx2Ck/eUdNp6cYIAxX0noHiXRvFFgL3RdQhvIejbDhkPoynlT7ECgDVooooA57WvAvhXxC0r6poNjcTTYMk/lBJWwMD94uG6D1qz4Z8L6X4R0j+y9IhaK1815cMxY5Y56nk4GAM9gOtbFFABRRRQAUVWvtQs9Ls5Ly/uobW2jGXmmcIq9uSa8D+IXx9M8cumeDt6Iw2vqbrtYjv5ankf7x564A4NAHX/Fn4tweEbaTRtGlSbXpVwzDDLZgj7zdi/ov4njAb5fiivNW1JY41mu726lwBy7yyMfzJJNLb297q+pLBBHPd3tzJ8qqC7yOf1Jr6k+E/wmg8F266tqyxz6/KmOPmW0UjlVPdj0LfgOMlgDY+F3w/h8B+GxFJiTVbvbJeyjoGA4Rf8AZXJ+pJPcAdzRRQAUUUUAFFFFABWH4p8I6N4x0ptP1m0EyYPlyrxJCx/iRux6exxyCK3KKAPkrx18GPEHhFpbuyR9V0lct58CfvIlxk+Yg5AHPzDI4ycZxXAabquoaNepeaZe3FncpwJYJCjY9Mjt7V96Vw3ir4SeEfFsj3FzYGzvXOWurIiN2OcksMFWJJ5JBPvQB474e/aK8Q6eixa3YW2qoB/rUPkSk56kgFTx2Cj616Rpf7QHgm/yLuS+00gA5uLYuCfQeWWP5gV51rv7OWv2e+TRdTtNRjVciOUGCUn0A5U/UsK4TUfhj430ucQ3HhjUnYjObaE3C/8AfUe4frQB9S2PxR8D6goaHxNp6A/8/D+SfycCprr4keCrSMvJ4o0pgP8AnlcrIfyXJr4xu9PvdPk8u9s7i2fptmjKH8iKihgmuJBHBFJK56KilifwFAH1hqPx48B2UHmQX91fvnHlW1q4b65kCj9a4HxB+0jeyh4vD2ixW65IW4vX8xiuOuxcBT/wJhXltn8P/GF/LHHb+GNWPmfdd7R40/76YBR+JrttD/Z78Xag6tqklnpUO/DiSQTSY9VVMqfoWFAHnviDxVrvim6Fxrep3F468qrnCJ0ztQYVeg6AVreDPht4j8bzqdOtDFY5w99cArEvrg9WPbC57Zx1r6C8L/AnwloBjnv45NZu1wS12AIgeekQ4wfRi3SvTY40ijWONFSNAFVVGAoHQAUAcd4D+Gmh+ArUm0Q3OoyKFmvplG9vUKP4Fz2HtknArs6KKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/2QplbmRzdHJlYW0KZW5kb2JqCjU3IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZVsvSW5kZXhlZC9EZXZpY2VSR0IgMSA1OCAwIFIgXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDYwL0xlbmd0aCA3Mi9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCAyMTA+PnN0cmVhbQoAAAAAMAABAAAAEwAAANIAAAA8AAAAAAAAAAABAAAAAAABJgABAAAAHwAAANIAAAA8AAAAAAAAAAAAAAP//f8C/v7+q/9//6wKZW5kc3RyZWFtCmVuZG9iago1OCAwIG9iag0KPDwvTGVuZ3RoIDE0L0ZpbHRlci9GbGF0ZURlY29kZT4+c3RyZWFtCnicY2Bg+P//PwAGAAL+CmVuZHN0cmVhbQplbmRvYmoKNTkgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlWy9JbmRleGVkL0RldmljZVJHQiAxIDU4IDAgUiBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNjAvTGVuZ3RoIDcyL1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDIxMD4+c3RyZWFtCgAAAAAwAAEAAAATAAAA0gAAADwAAAAAAAAAAAEAAAAAAAEmAAEAAAAfAAAA0gAAADwAAAAAAAAAAAAAA//9/wL+/v6r/3//rAplbmRzdHJlYW0KZW5kb2JqCjYwIDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZVsvSW5kZXhlZC9EZXZpY2VSR0IgMSA1OCAwIFIgXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDIyNS9MZW5ndGggNzIvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggNzU+PnN0cmVhbQoAAAAAMAABAAAAEwAAAEsAAADhAAAAAAAAAAABAAAAAAABJgABAAAAHwAAAEsAAADhAAAAAAAAAAAAAAP//f8C/v7+q/9//6wKZW5kc3RyZWFtCmVuZG9iago2MSAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCA4L0NvbG9yU3BhY2VbL0luZGV4ZWQvRGV2aWNlUkdCIDI1NSA2MiAwIFIgXS9GaWx0ZXIvRmxhdGVEZWNvZGUvSGVpZ2h0IDU3L0xlbmd0aCA0MzQvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMTkyPj5zdHJlYW0KeJztldlWAjEMhv8fUFBQQBAEURH3HVwBxX33/d9HQKbTznSEi8GD5yQXbSZJ0685TYccRdCVwaRm/DhUgBbnKq4ZptmJIy12N384AnNwVQToWozOadgs+fz+8fAbuQP2hX/xyPxhsuucbmIYdl/99AvgLaaRAv6QsItvbAvPZxfScodUCQd+ncdTAZXWag+P3pdWcWLgdRpP44FaCW8eE1frexqOEE/gzWrcG6gjOIP328vlu13WvgmRfdh74Qmx8Qf1+V+9P8arDf/eNv7BtbLyD5vDO0Dw/8YxmHFa/wasc9pFKRa/iIiIiMjYBJEoY1PkNOKRBDmD2SRT+bmeaz6NTHYBuTy5iMInuZRmqdxftVwhV7D6VcV6jrWNrmUTlS1s76DKXezts3KAwyOyXOpFH+cLPKn3tEY2g3QUpVPyLEWe46KGy6s4my20r3HTATpkrI1Wk7xN8O6eD0ny8QnP/W1f8o3eVE93cV7x9o6PsvALv/ALv/ALv/ALv/ALv/ALv/ALv/AP4V/7R/zFSeCPKP7ib/wR4Rd+4Rd+4Rd+4Rd+4Rd+4Rf+yeP/Bp5ZRbQKZW5kc3RyZWFtCmVuZG9iago2MiAwIG9iag0KPDwvRmlsdGVyL0ZsYXRlRGVjb2RlL0xlbmd0aCAyNDk+PnN0cmVhbQp4nGNgYPj//7+9vb2KioqXl5eHh8fkyZOZmZkVFRV37dqlpKSUmZnJysoqLy+vo6Nja2v7/fv3srIySUlJCwsLBweH2bNnc3Fxtbe3h4SEGBoaJiYmhoeHW1tbL1iwgI+Pr6mp6fXr11ZWVmZmZjExMW/fvtXW1j5+/PjSpUs/fPhgY2NjbGxsaWkpKipaXV0tJSWVkpKip6cnIyPj7+/f09Nz7do1IyOje/fu9fX15eTkKCgomJiYmJqa3r59e+LEiYWFhb6+vq6urpqamsXFxdLS0hs2bODg4Hj69Onq1asPHTqkoaHR0dHR3NzMMApGAQ4AAMYvV2QKZW5kc3RyZWFtCmVuZG9iago2MyAwIG9iag0KPDwvQml0c1BlckNvbXBvbmVudCA4L0NvbG9yU3BhY2VbL0luZGV4ZWQvRGV2aWNlUkdCIDI1NSA2NCAwIFIgXS9GaWx0ZXIvRmxhdGVEZWNvZGUvSGVpZ2h0IDIwMS9MZW5ndGggNDYzL1N1YnR5cGUvSW1hZ2UvVHlwZS9YT2JqZWN0L1dpZHRoIDU3Pj5zdHJlYW0KeJztmG1vAyEMg8P2///z1N0LEKoqfgq0tOcP1VTVwzgm4S4lBwvC89JPEA0Rr4jxG8QbSJ2PhQKAiTgA8zE/qwu5iqUu1KwWwpXVB8BSr746AuOzuvmTXYoSM0GUagdJ7T5PEe32qUpN2zZ1c0SBDyC5mgpv1DrKmvFusTsrj6twOWz/+UGMB2CngHIYJeYzqUlN9UHWzLEO5zEqVbTEO0SkmnM1OlibciimVsT4/lIq26rgqisLruME0JW9OQovkWnVEJUA7BNSIyZvzRs/sPyTjfTVvRsjV+ffcwixMQeXY0YAcAqsMkYIQH2MhQCw22PjrzACam8UV6Gpz6DYokDqNeakDlASFaloBPCh0w1qRE+tQlZrYnhFv3R4S/4LJQDIHFHgS+HfA4R5/g/J1emD9cXvATAxPFi7vc+RiGU5cABwHeNMV8dwAO78I1ZHXTFmyiudDwL5i3D9rShHOKuHULLi9ntIPIEDoNiKrtbNZX7KscINuZIqNKtOzx2YOL+v4nLgAChSq74a5lmvvjoc/d6vCq6yvto8d0SzygOQe/lyUHZYYX5WL6kjpGJgqdicb3B1IVwB+AxgV8OXwG4rLhSAb5A6PAB/Ekcu9QplbmRzdHJlYW0KZW5kb2JqCjY0IDAgb2JqDQo8PC9GaWx0ZXIvRmxhdGVEZWNvZGUvTGVuZ3RoIDI3Pj5zdHJlYW0KeJxjYGD4//+/g4NDQ0MDwygYBSMMAACarQU+CmVuZHN0cmVhbQplbmRvYmoKNjUgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNTQvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDgyMC9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCA3MDY+PnN0cmVhbQoAAAAAMAABAAAAEwAAAsIAAAA2AAAAAAAAAAABAAAAAAABJgABAAADCwAAAsIAAAA2AAAAAAAAAAAAAAP//f8C/v7+/3POQXG46ILcwMo0/UhmMIiHmLMMAd/Q12go8gVwKbxEk6YsTSPSxuj6UOIvvQjy/DWSvZuVlxc1e2DJ9NpWsCDjdP5Kj48DWM81OFMDGaJdoRKVcj3ptvHqo4nS91yhvJ9PgcYra1OClTt/tIzOM2sDTFneHBZdRRAGdPcWkLitiLJGRcXMi5Sdkm1G03XKURObVekOVT3UiVMrrCC2GDWAL0wAETxRRQdmkHBihmYUzrqMLvg0IiABIl/dbqaD39vBbKw1ruQjeMzawnbdMzN5+hQqv1WPuz7z4RxhN3ucW7JcX1cBNBSMf2sKeq4lFx/mDkWkeKFiOYQbIPZzIWsUPnrrhF0UcoCt5GgQcs9lUzRbs2FF2VnEg2nk0KU3IaqRStzRtCzq2Z8ChHuDYXaiHJB5Y+7jxAyeh6PRXHLopnpiP8AfwdTcujKxGCNPNfoZCJT37baWZ06zr0VGVznVfKdFsUlizILM0ondzTVqArgd9Yd2xF7qUO00NPlxO31sOYOaPFtchlVsiqIsHnnb2GpHAF/fnzuG+6gx9DzIa/xYN9BbczaV6dDwAD2xwU4s9hUGZjiLe4uPxUwMtqG4LDLJYuSU/y8dq5N8qCZlcVMr35Ci+5oY18Pmr4WxeOkMji4BW3FrxTHy1IgfrTisJ51Zt+XTNhIUuWGn0fgfOtYsecHNDcHtbaIdpn+yXE+5k4Bvimc0q0SOo8wTBx8bI9vYmuPwPNjwpNPWOEbpwYB7KRRHXcwEG4jtU46abb6OuUPdTt6u+szzpKdZBRpfNP3MLngthQ8Qx9oRHa2eU1oR8oGlDIApVkwRKRNAJss2fVrz60pKsjQ1tyvSPiVMfq97BXAyiWnuWRl/OEe83VL3RJHYiEJFk161F0OJy6dZ4j4w5oiMNG4ti9Gm42rteRKp36kwtX32GTbHaUYblZrp4qbAC1j653sLnVJne1Du/kKvaNGink4fkHICtFqAhhD0wAHAyFPQVYC+D/+sCmVuZHN0cmVhbQplbmRvYmoKNjYgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNzIvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDkyMi9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCA2NzE+PnN0cmVhbQoAAAAAMAABAAAAEwAAAp8AAABIAAAAAAAAAAABAAAAAAABJgABAAADcQAAAp8AAABIAAAAAAAAAAAAAAP//f8C/v7+/3zzSZx6lde5gSVRbmNHf4JkkT1Z/DLlcm9StEckB7R6wv7Ae7aoxCUxxcZo46gzGljS7jNEc0/PR0h8ZzZ3LTe0RGA1qgAjB66I07PYtKWwZQT4cbCKSHJBMZJ01PykBAvrUN4tesu+t5XWX92SlC5JXyoaY0O1g9TPAfvKWG2wkrHYmobU1oz1IHRq2uvRJVBnxfuyNM3+H5o2odTNjjch1Ivo3hVifrbXL6fNBHnkm2/QcnjsDexGdmgZuP2nCKm7PgoLeKXXnRXfJDq9WD9xV+CqNSfWqYgrJG4tUE8cY4iz9CxBU5++hkY4AqxGsbuEwjl8EyLtvBVYxGQAbAlXkLt7/w2DnXRBaQQ1MATNxaEa5Cwsw1v/agtf6R2nhLHwwgEab2TwfMcyMoUw3QDkAoKyYwQEfO+gPsYPuGfw0j4Gb6bYOQvwwqRbfgmLiykwGkCqtWJ5YoZUn7y0SGyraPHpbnS7/qollhPNReMKM5+ROWT6YP5cNriwi3YJ3YzMgkVZDTBwx+mHCrhX4J1NtDX9wSc3tONFSuUrJS4Fh42GXNZcOwc70Nn21npmbFdS8bQt5MfGLCB1UWOk+rDy3zjuCZL2nn203izpWK/RRJ2nAxpkWMVjuMQFcuBPYBVtYzeY7FdCcWtKXSRsT+HOXB3Carkz6cycfDRPA4rSm1OddHkTC0c+97+vWTRMifDPAByhKRvF+Kn1zdBmRpM/TicGER3F4XBDg0oNpOwSqM4PX4j1BMi56/Easm56c4pWhpl0dVZDBd3JDewEZ+HHRf4YVm9zapL2Z13HGSt3T0A736bbZj51aXhAOSQDi3do9P8Gs3FlnqTBvgcpWkfG/DRe/HQHuuXilji9zqVcS6+oNldWSAt4QmWBb4GAa0N5Aw7Qu1dj5pqeqBEmzHfP+9syP9nhw+NmaLbTBuEgwnO5HsH+4jlcK/980sZT3uyoh3gndEc3s1A/F5IbyAY4h42JgbkBy8MZCXxcWYFhJ9Ii91cueXe91DCqLkesf/9JmrTQon+nPgckRjLuSxIy6tHw79JiW6HGN0cb3v1yPX1UIhcFHNttn32SB0isTts0kGVqQeDyt0ChzYt40CBjwe4RT5WQ3MfhCADacJYHjLSGj/+sCmVuZHN0cmVhbQplbmRvYmoKNjcgMCBvYmoNCjw8L0JpdHNQZXJDb21wb25lbnQgMS9Db2xvclNwYWNlL0RldmljZUdyYXkvRGVjb2RlWyAxIDBdL0ZpbHRlci9KQklHMkRlY29kZS9IZWlnaHQgNzIvSW1hZ2VNYXNrIHRydWUvTGVuZ3RoIDYyNi9TdWJ0eXBlL0ltYWdlL1R5cGUvWE9iamVjdC9XaWR0aCA0MzA+PnN0cmVhbQoAAAAAMAABAAAAEwAAAa4AAABIAAAAAAAAAAABAAAAAAABJgABAAACSQAAAa4AAABIAAAAAAAAAAAAAAP//f8C/v7+/33DZ6QEZi043gjfIV5Un3TFBlgIcSkIzgMz3kvJ6MQDINCD7/lRINE9jylyR0Kb/qap+1V7QqalkqNXLCc/FU63hvvtavzkHSBrLFLs42bIjd5jObkIOUtQRk9f7thADuobDEreR7NgpAZjcVRu0qoelzkBXJ0ee/VNLoDBOmo+ONGEaxE4ZT9YG3eTQlWJMrglixM8h6mywH17GTOsUc+iSZ7dXEPRHMEi5vktxb2fCGS8B03rgcjdDM7Ho6fbVLgCQA64juIXxfx0xoSrTKAv+GMBic22N0hX7rWQdm+Nk806b6i3XoDZihLML6S+cZ3GNwf7jVzn3weCrDyHZH/SwPK6VogQcFqN3Dah4NGgY1HFXpgpC/eU4BbvfJsmdILafvMcI0UEpPAF+yYGYDMJfwPjCGcA+64CyZhbQ3qxGSdmUwgUj0RjVfp+gDg+w3fWkOn4zf9X3AWF12aqnmKmLfk+x1HaX8MBYWW3OeRXQAjgoDI5c+SLokaH11wdsO09FN5fxAjW4oUVbb6uOJjB55Co7pgWNKA8njXs/FIon/D32KITcLg8bVmqe/VCqJLwr+ErfjjSF9YLsWlCwem9XXaR9Vu1l2CNjZQzRkQxpROYPvDOOlFluLt+5ajB81iWKUhLFYn/TM4ThRTlhtlmeugm2aBN2BbkHETer8YDAOgGAu0nRaGUu1NuzjN/A1/T94olpPMRi7j2mMp3loWeD7/xvFgSilKO7l//rAplbmRzdHJlYW0KZW5kb2JqCjY4IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDY2L0ltYWdlTWFzayB0cnVlL0xlbmd0aCA0MTgvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMjYxPj5zdHJlYW0KAAAAADAAAQAAABMAAAEFAAAAQgAAAAAAAAAAAQAAAAAAASYAAQAAAXkAAAEFAAAAQgAAAAAAAAAAAAAD//3/Av7+/v94JUgh7NICxtlQ5CPIeDrZAUkD3cRKqmoDtE2HuXwpiwVuzq84LJDb26LMwjfrZZrrsxgjI2ThnVw/P5pyqfnrUn3po6ucbxezzykVWNad8Z4Dv6dd/R5s0BR9wUVvSeg9mHcT+ShiGi/6hXwP4QE/InhMjlx9rU1I9IQpbxxE08pekVBWi4LS4agL3T5nRXAjbl2KVOIomqoZZx76aQN9pnp+OuZx3Z1u2eFM3ig2bbRZxJmFKsZ+SrUZ5Sb9d7zlTeSdZsP39DVfIs87YPRDNaKAElCFOjjI+XyPcV49nRWbnXMKynTckXpo7TEFYbUnOfT+Mu68Ql1qDDOdVXnvTu8+EO21zPL4z3ZmdOpXreZST8bZ8n8Li2W2EFx/FDvs/lkshPib/c7yJycILU1M1cUYTTNwMlFpRukd6D5zp/H1oVvFHzp/kFb/UKckOqODWqpP0j++OUNnH1//rAplbmRzdHJlYW0KZW5kb2JqCjY5IDAgb2JqDQo8PC9CaXRzUGVyQ29tcG9uZW50IDEvQ29sb3JTcGFjZS9EZXZpY2VHcmF5L0RlY29kZVsgMSAwXS9GaWx0ZXIvSkJJRzJEZWNvZGUvSGVpZ2h0IDcyL0ltYWdlTWFzayB0cnVlL0xlbmd0aCA0NDIvU3VidHlwZS9JbWFnZS9UeXBlL1hPYmplY3QvV2lkdGggMjUzPj5zdHJlYW0KAAAAADAAAQAAABMAAAD9AAAASAAAAAAAAAAAAQAAAAAAASYAAQAAAZEAAAD9AAAASAAAAAAAAAAAAAAD//3/Av7+/v9GCaRVJ5xy5AYxCkEZ+TCG0GG53DhEQtWMBhZqI6bL6QcQTL3d2P0EdY8rB3TnfKPxnXtJLaXzhOnxh89gSlbjSrcTSdbnm4xKEOX/Phbt9WKBdk0mBDxMpjALMTAp0adtFH0U4v7OxXh2Cvr7txlBcghA+zjYY9fymteboi/AgT5/3wvl6RpBwvopaNluoWK86QdD4jg9QjuBwhLmbjb9pQraEcE8pddCVNy8G8D/P31BzqpjMpoCwzhSLTPJy8C1fx3RJ09YazUJDqMkY+XWwCbUI10YU/rvgKOZmz8WOnjWqngevMS1OqBeAoVjIEGGE5duD10qFCZj+yy244wC41dRxo7+SJi5/jbugrfEYz99JOC9WEf/P9m5DV1UbbJa904dOGPY06M11dMIFkJAG71DkwjnrErOyUq9n/bdyhw+TdSa3mKxWcL0LIHtcE+XC3xl8Ex2i8wAIjAtSdzRHqNwJlNy/0tBp4hawrdkXhFR11//rAplbmRzdHJlYW0KZW5kb2JqCjcwIDAgb2JqDQo8PC9PcmRlcmluZyhJZGVudGl0eSkvUmVnaXN0cnkoQWRvYmUpL1N1cHBsZW1lbnQgMD4+CmVuZG9iago3MSAwIG9iag0KPDwvTGVuZ3RoIDE3MjEzL0ZpbHRlci9GbGF0ZURlY29kZT4+c3RyZWFtCnic7b3LjiY9kh24z6fIdQOV7XTeAUELQTMNDaDFjArQQtCiKlR/1yJTgnoW8/rj7jQ7x2j0iIyIzu7+W/IqoCq+k04jabQbb8b/+eVv/+4/ta9///9+2b/lfTv+8/X87x/yty1dv+q3C92+lrZ9y+cn+9eXH1/GZ//w98cff/flb//Df6xf//3/+PJ/f/mfPyMXtm8pvYNefy+9+O0g9AvbV771/R30wrYS3BsJbt9iGQQ7CNb2LR5/7/2WYHhnC/f9W+3nfz7OwdsG7u0XNzCG9zXwvUMS5a/w0Q6Hb227oZe2b9v5D/vPhji+l2D8Ft8lMwtBDMJF8BDlQT6VoSRHC2v/FsJJ/JZgeicLU/3W2mdY+Aq9HI5WfWaIX+lwTt/S2b744Q6/MiS5DGGPHx6SQ7vKHcH+PiEMWQluX/9e/vX/+bu5/1//vy/h+ofxvweV0OPVj6+l50N59vD1xNI1aAeWvuVDLQ9Tki+GHcjxeRXk+P+BlEMIv758ObGWBItaDkjIHtmWcvtow4QUV9/+LcXjm1FOWrV/i0G+Sk2Q0G+RUW5P/qswUT+Q60cPUgQske6eSNpmJg2PcLHyavTLDXu/f/nrgW6XbzvQw0aT6aFY7PuFlbOhdTuc10nx+xfTof6tZsG2y5J6LCu9q8Xfb+rV1kgbw7d+lj5bE0bNJ9ZGf3dl0WFlgyB7ssjZ3/3Ss7mctFeoG2T/tlWUE6yw99tl3SasdRWMCZOy9VvU3mO8DJa1bXW07cSKcsTUGy8z/QomfXXYPoRmVyHdRknDtW2MzOgrOBkGJ8Ol+xeShribMQFv/Tjp6MnYGwUO2vs8FOP7hSWVxK1CHopK9dU6w19VvNY5mEcjWlPSaMRZCLZgi9L8lEQ5YhZkbubL2fiD2q6svoT0h8XUihAJompEhNFny6p2ZoPAE1PhI4IuV6qtqnurKhZJyxVvAVumSVBLdmAykPHbLkxmSTUUpF7EKrINddT3YstVcrqo6FCEWWcb1mzq9x3Wla+CnOYl5hkJsJYHr2GEstIS/qPkdztupk5Ii8G6qmEbIjYEcWu+r6B3h5UxClMd5VsOIsS7GoldhJjmJSh/u/JXxt3IcYbwE8ksB2z4CotEpQTa4CPaIApoOAEp88gotyf/VdgdJTZnUlJ0rak9L4tSFXXgf/3ynySAsKGFBhBP8PAED0/w8AQPT/DwBA9P8PAED0vw8NvfXNEDnFHddjFkY1Xp6x+CGNF/+MuX//w3X//7h1Yq9kOqpCtiDSdMjMyJCBPEGU+IGA+DQRUOnlAUrmafCHo5ROF0h4uX7uor4aXPkuKPhT8nIjysQxHONshANBWPE4N/LtqfSzygLCfSVKW6ltuHdTe+/sSSfnd5mIHBh4N+V08fJvpnu8CvrAa4sY/lWqKjSTixSvXMWbCk4nyHFY05zjpy8VhRPsITH3VQWx2pFUssltUBGqzoACe1EmcXZFjScLCO3ooFli3XWp3HijrFzDoQ1lSlh4G4wzYNJlY1OB350Rry94ctaHgOzPA3rT9R4q9zmYu5E23DyLT+NMPhqTjawtQfMxO6JeZ+mmHwVAbtOGQTOvLjwmoR97TVeRChNyfSiyAXPSCIj1++TFjWr0RrRBtOpKp+7BXliuqfaFuixm/xFhnlYvFf7clSn5AcUC5oG9r4Kg4rZ+yJ59UVXJ1marecOSPDxtY3tYfbHBZYRJ0lsSYe5fxjcuMnAqujzvI0Nmp1ZGLVaEuiUpqRUS41/xXsEigBESt3YuCgTDir+gQZ+4kvUdvpefVdOBjUL2zKwarGQJ0vawCCVtD9s0dZJ52dYWDN4mHStjk5hdfpVPJNjVQjrTJ5vhPB7GkdxUyuNg0uZBbbOEFvFW330/jGeUJekG0phzkj5AEznUZDmskrxARolZ99tq92XsJBwDQTCGb5BoGgGSwv5Ur1CAVt5kbQCVAOHqnZ9yrqGDWGdrvKNFxXAhft8ED8kk6wIaTJcmMW3O8fXhl6grUnWHuCtSdYe4K1J1h7grUnWHuCtX/WYE1W4j50EKg1IdTqsFoTFrgiDWyT/TaLBF0eHEjtGOmD7FjVPzCs+ip2lJS1TyBBdgMsonuFxCo3coA1rpQL0rVdBtHhPT/fBdPtDvao2dVj8MfwoiTLs2sttRVljC6+nqvxMsRYyD0wLAAPo3ggbgH4QDaWEyyLNFikajmhncl2XRQ+sDQvHB9I1CVhaWeGmVwwLhwbSmyOXTg+NxpUDoS3RVRukbKxk1PEeiijflzY8DqkBgQsMIhudFlMmmmQoXusL3EHyGBVd22GBTuQovUJy5N67RMTdibdQbhD9rSWmzHuzxhkLqKbRmzQm4iaI4vJ9lNh3029wp/RulmUTN+L7huAP0a8/UgO7xpUDqpGpgZrahEDNVG8q247Gn3FZq/RV2yKGn0lVjWOPXcmtrRiUgdtCXb0D0xmS+d3dZLcCUvDP9jNY4vptrsOytg8Hl67xRFnfbd9M5huFLfdHxVQi3jWuSuCCADt2NTd6YkHWFtsYKvlfjGb2oed7mx/mTCegjiQqqcnBs/Uvo8DDEXbkOZN7qOlEpXqQQDt8zXGMwv0PMFRSAK7jY4DpiZtrnrsUh0YTkDoZiHZElQodu6oi0iYJunpB9MubN0pZmyrQYJ+Y1xOSV5EUOeEZTUIEkYEGlSoCFRrr2ir9NG4KrS1gj5ba9TBq+pQYKNMu4bHwNRAE8nKyZ0dejHHVGZ9WfzqUt3HV6CeeOaJZ5545olnnnjmiWeeeOaJZ35/8cwnFmmu9XTVYf1ZuECeVTzvsMqNn2R/jtX9ps6xcnUfvmFXYpGDumLZboXM9HSdP6l2Xtrzw2JBV8aB7FzzhvgWXZvftVs7d+igiW6NlVaEu4SMAE1P92G5T+pZxT4M6rvsqR09xzp/oD/dImhBYYrS3xaryv1L5SR3GA8kdo9gjTjQy8q+Z2BgA05EjTTkUB93XqxogK93mBEX3Ye0GEa4srWpeSQ4VTa8qFzjBrfvsKY7OzvjYZELtKtptHRiYirEc5qWdh1LjHe3/Knqq/PSBvHfJ3e2ZGs8EUTWEqJOWKr+K8g0kF3bEGk5ZGwj/bvsCMneMXj1AnXmvqAORFOBSOxcUARMgUrBUnRrPcB0YWdWN990Ez+T5WAB6DdVKd1MY+cSrTW6YqyV2VYG07GRWDhRycR25yUMJnOYCRFeAMlsP9qR7Z40MBi6tP5MtvZNldVgeVJqu4ttDURRRYF/NtiuvDeI8Lkwtuh6IAB1Bj1IUGgGRVn10IAaxokLKIfRDyqQkC2JNsboA8NhBkjSrgqte/wW6Qstjxmumj4H5UJUSTKYKKFBRJYL3Tc3b2d7nqwjStZPpa9YMni5cW4jztDjJuqUflxYU7ck29GbC3eNmdw0YjOGXiI9Y+wkAJ5aEZfRwFfgIJDKUBrHW6oLr+U4h4aoFD6NoifEqBLWSWCOYpkR2dVG9G09vGL0YQeC80NJGbDRw2CeIO3cyJSs7AUDEBB3CjvOD2GlRvb6OsU/s9yuwymzF90vV+XivreuAtk9wqMNuqtOXnMnkl3jXp925PuFzZLCzXJbfZ+kcFQ/Lyt8N0cGZgzhRZr3SLGSolvqdr2Fbc2889SWsNCwtOglDzM8GZdGqElZbcqqXUPndGNVvd0P2wszyW70ipsO+BxQmNY1bll3hibSf4hO03lCpx/D1np3vm1CRHQ6QyEjYGkKtUyrKkU1ulDL9MZ8hXkUNq978e1s9N1RN70RUTQV8ZnHH788+sxlnrnMM5d55jKGV89c5pnLTKbrmcs8cxkiz1zmmcs8c5lnLvPPMZeRzRmdv4xd4M1nDwzlNMi99/I1x+HHYrhNzld8tr+Z4j6yJDqKY2M2xVuKS4bDd7QxjRPTe7ml2H5GsZeV4jjQHtItxSWr4zso5nBJdbhNcrgvyU/fQzFf8rDdJhfdl+Si76BYTjN3iGC9pbh/hmJ+K/nkT/h4Kz2lv8HHT0lPvY6ub/leen4i4fcUxxWT1N5L8RzGW4rXnwfFI8I8LXu6beO+5Nx8x8gcduJ1Lfy59Nz0+jwzcPQ6/jo+9mEV470WNiYGfd/STPlatq4xnh4x23ApRZEU9HphcT/47V+/6HkBUtRzXvxKERLRUitiaQdNGEXiIdtPzl8kgc9voImsxiGGrDolQ1shQ00L3kC2guNfDO1d5+b8BBAJnWXmX5bibx9beysSRZpGVPGUphEKmWq14A00dbDLzI0VHP4xuF4CMtS04A1kK5DUzFMFesTLVKAQqaHgDTRV0BfRinrkxFSgkKHWFyFbaJ0VJD2YwgqSZt7id4BIDQVvoM+LRCoyNzXNqTKVM81RyNStBW8g25y8LSOWw2IJAJEaCt5AUwXRNfeoIC1CDchQi0unFlpXBWUZsVwn2nWiUZZxWiicZI9gojnGlLiIMiBjaLelKwutjwvCGYk4wT8gr4GATN150eaF1tXfthif0pdmAzLU2mJ8FlpnBTUsxqempSGASA0Fb6CpgrqI8gH5hgAy1Ooiyguts4IWFuPTdLGU3wEiNRS8gT4vEi05Pb2g7qgCMnWnRZsXWld/22J8zvPaTgUAGWptMT4LrSsICTJbNFFIkgmrCUMUMlGHFryBpgp8mPTjhHxDABlqazS10Lpikm1z7T2CknNXwo0CMRODoOwd9nm5COcKfvJtKks0Q8zWvy8KvtIbPdcFD1NL2JawipilqGXvsKmW4KOws5Y0V5AmOmEN0lYqg3Zxjv2k3ReLQcxSLEsEsNIbwfC+OMAT8/aLmA2D90W3VnqfkJA9LXoR9rLYDmK2/rSoxkpv9LytAfu+ThiIWYptlZqF3lVLjIsRCTEtHp2YoYiyd9hci55Xt7WskwhilqKWvcOmWpIPvY5aUlr0gpihmNYYbaX3CVlJefECIa2zC2K2/rxY1pXe6HlbRzGtUwxilmJbR3Ghd9VyRKiLzXpvLSh7h/2vWstv05rHCHY3WfPACkjCE07bSE6z36547Dev05R0Q0/ykZ5vq7xNMHuCWIaZCe5j//jnLVxWeeK0ygOCx9xUn5N5m+CyoBenxTKycKRC/3mXl9XgVwjmgvdp3ia4LGJiuW0mWMr7BiUua8Gv8LAWvNT1QR6+IjZtLIycu6YfFptbue71nS1cBPsVgkeM88tIhYZHprbyxjNdcVkLfUViTvd6Osif8+9GZO7bGDte1vpwr28V+TRmex0PTb1Tk9+9+BbCiGFSQ64hgxXkH6/ie+8xpHtZ6Y0lRqBXFiVXS8OlL1K8x1L0tQCztfTLvs+1nFcRfbtvMSn7/Yaeq6WufTn3/bqneIfVtS/ETC1525a+5O06oDFRvMe2pS8G+/BCLWnIZeoJq8hjzvrvsIJDDws91/Ou95WJhR3bzKB4h2nZ7zf05lpCXvsSkNjO1HKH5bUvxKZauLYNbN/02BUp3mEBkclKb67lmCRt0dey45Yta7nHNieRBvu8rOwVuQWJNdzyZf13WMWZwYXe3PMohzRsLXHHYQtQvMU2HARb6Llakl7QNFjG+wWkeIfxqNpCz9VS9QWJCdP706R4jxU/isRsLWlf7H0+JljVS98tti/23mCfl5XEXJEWW3r5Cpb9KCabNZKo5CC0teSgh8tI8Q7Tst9v6M21nKv2chabWF7t4S0WcbxvoedqaTd96TjIQ4p3WFv7QszWUuJqI0ta232LxdVGEvu8rJSyeodSVxtyi5XVO5Ry5x1qQIZRi2VvPV/Bgu85samWiJsHxOrqCW6xiLPjC725lratfWnbag9fwZa+EJtqieNw048ZW+zhK1j09p7Y52XliEUXi9qYKYf132F5tajEbM97WL1Dj0sce4+F1TsQm2rhTRJivN1PincYT1Qv9KZaypnD1o1i2XaeI8Dq3B224bD1Qs/VgoeeDFaQvYAU7zDmzF7o/SNkpWwVeX+BhW3R7ltsw/s+K72552FfNP7EvPV8DfMab7CplnLTl7bEfvdYWftCzNayb4t3KHtYouV7bFu8g8GmWiSmmmppi6W6xxCPrfT+MbJyRIle409s6eUrmNd4g9mex32JoEtMiye4x/YlgjbYX2eKC3/fXUta+Uvsf61aVFZylYneYW/+sMuFgZ+8JZXa3RmHsSV+nrqUgLGP7Scg34lEHDbQUiuSGSjmsfmTy65OGV/tar4MJQ13y+iNhfIV3WkiG0mJZGoPsoN7C/FkedYIjBBo4Zx6iGPf8vxKbayhtUCM8LL2hZBkoDohnTNEFlQXub0BNQQqsntlIUnMdJ5w7cHV2LVDcvLLIFUjNbzw18bRixMRiy8ZwM6YUTy0DpWWkvfyTrqXRsvZsbN9ksU5jWOBZ78uCx+1JXKDcVcB4RWtsW9yImJHx0o2ByiNkx5gMoQMR90zqbbpi+RK4FrReTRT+iaR9KkGiKMlKuvKEeFRkFxMJzBO8G86Qh0JoTYN8OWGAgdWMxfKg45g41EoiFAehEfuQQPEqZCOxQslpuqbmdqaKs9q+j6e/Yb6NbVZUHZIGRBIZ6Gge6TRVhWnDj8spc3RzotBWJHK9SA5JptLwAxUJSeoBEdVDkSykL+g8ii1y72fpIOFe0BNZSWo9ZEsh+fB90vlVJeKxA2qbRl3pbJo5DG7vfxwErHJsuakLc8V91aJiMYmGcsDueaJKsMHjatvksHv/C3XA6voibajqbbKRTbDwTjaqUiWm1mdNK868LvgTUWVbm36dwNJ7wjI9IYqwdtWmyo12ByCcl6vTsnxZNKJyhPh68tp/MbgHNBIUq8GUvkGI0pmB8nWd0IjuWcRTUIX5KgnyL58sZAGr1mk6YDGNRxJIYhljRA5JnqhSo75nFATVW9N+j2S2AUVOLJLKzfsgnOAZ6U7gkZY1i/QjtknLNJOEyDCgqUTIHLr0vxOVli0po9nRXgikycyeSKTJzJ5IpMnMnkikycy+aeMTN5OQHu7cKKLLmCZhUTW90DGj0wbgZIrsr0HbohJCgrhswGgUlpoozjJFXPhjFZNwORsJiSJFtQvbpoJx4n2VdM86mivAYShLKT9BmHDrJH1wXPvHIV9V1GJ2B3eKT2jIEhr+o7A8Q2oHvZVktKoiSGQtBDy9Cgzds2IQGGTtAEKRKbUJiQ5KFQnomamcT7eslSTRIGlBKRPLLQz9hyEDbNG1Z57n0hE9sj0I9O/e5n+hLFOu1bedDJ5Hp1PFvpuIEy5WPAGapxQpqBBXtSjQCkp87HjSijo9IYFb6DIY0BJXbapoHJctIJKl6zUEuVkgWwFpiGyOWibK6EEINVJ09wbiAX/OjVEKzDN1QoqrYBSM9GKh6YKMK3YUIGZ0yiLAieUlxzqjeETuGKotPPvY6bYOLmSbeAk903MeYpUSVV74psjXJaGS6I/K5uYWVpI4hzK5i2kEoz4C3MUQpIO0AIXTwhUDdHRw9I09tKbzCcr5aiVVaG8KodCgbNxLRhI/upyQmwpSXQsINaCkMzRSUUOESzMfRlSITFz1bxBlFic5rNC7C5430KYVaTGOF7vfAPSaZUCRXJCEYg6s07NmUcjZiWZBgSFgmu5gSD1LIh5jNRIQLwFASTPAqQejoB47YW5J8ejWaCRJ3ijzgK5ZnGm9NFVgauR0az9BAGyCo7MiKLOHXU2HxuXdq4mxqbC3NVjxKYcknUMC/SpUN00z1KsXMdwzROlX7p59b1xgGT6z9okA2jstLyaDwHzl5czRQKc/+hj14WmHcMAvylch7Ex4wtAa+raMu1jp8zloC0TmSEjs8YgsblVsdioklEqwbk3VtIUkinhVQ0OSsTGlUjNJYHlDkJYw8PKTjQLbErZ0FJIB1I9+AFEjV4uK4GBLHjOJBYyV+4dMTqLZjFGYtfznqP6o6V1Ms+MZol5iCoWaPB+TDRrNpfIA9AJPlp/aBzl21sliCGKmcWhywQtgvrx2cITVD1B1RNUPUHVE1Q9QdUTVD1B1RNU3QZVn1iuyjvZK3FJ3tX8FHW6eedxgLGdvOsgiHTlQPGUzdgcdKdR95wDlWVs4OGLqBYiB+6yXMOXg8qfAmahTlSOzRM6eae5vIaG3YT25KgSKRwkIP5o4c3J42xuvUgompP2S+wRAbmRdgDBiWhOHEw0V+1y3ujhREqyLsLmogEEeH58FacGg07UxfCuD+xqKjaIes7KT7EcABhE5cx9dQlCFz5IsjaRSkpTJhPl3lEuNE3XvplmaEMkRIDSVGiGhzQVhtmDi0WtGbxyrkYmKi9qjaMa1R3gOb+nRQ3yzWxiTx1tVmquQtitj3lqiIRsC1suQWo0DXJp59ymnrYhvp9QUh8+eKVAkdTxBLA3SghvUZwC0OygfmcDKk7tn7u2syQDKB7AfgEhyU0OAG32XX0ZGfiikpbLMQcUnKyUTfktlufs9iQrmn0PQ/TyhZA4zzMmKnbsT+HfZlkp5tKefpMnc3XOwJolexVqk8CcWyS7bY39QgSGdERg2BpRiIU3F8OiymJX5SppmaOc3slNbght0iYFijzjSgDvEQBS00FABpEAjFSJMjh0ZYTEJqEbunfFfm2GztzVjz9F/zi2x7E9ju1xbI9jexzb79yxfWLaphlyzb39qgujutxysk7n15fSnf/QZuYXLG7IkkCpXHsazCj0W1oIE+6oWlgafc5gRleJV2nG+kVR71Y3HmO+CqFXurpQd+eAjkJ6WJD6vjDjShesJxH1pPKVjxgSJKtY1Rwev3p3AFgAvb6phWsZ4jQqVvFEqmvjCZSL07WTi1qoU38uxjYcohH9acHq0vUra39YWthZm1oCMR8Vq40Y3KPp4O9VJXhS5DE29JZHqBe+XaeYOy8NiLiVzlUXWaqhwGHd8hgtcIYQFk8vQahmt+GqkZKMt6SqOUCr4oRF2qHpZmFFFtUKFl9wnRsqcHw1Ti5v7uQXW7MpnaPF85HpA8ApqsHH6EKNi/nJ91wP2apDq8Wd6wLztZvXeMDMVBmzpOvaWQrhCJz4iUPS2/xN4mL4ANaDwxYSm2uLXVyGCulZYtYEW8kWS/RW/eHiag4Xa4t1A+bo+SVh1ewtjaqxzZF02a6uK+y1UFHkygbZDnVa5Pnj84vHAj8W+LHAjwV+LPCvs8CfCIR75IU8Sal2QLvaJ9nM6bjkJPPGjlt5oocdO0BNT1R3c8vu6ls3e1hXXT1z512GsGd32bFjH0mOm1hA9h0tdJkSUpFdUFaNvVR9NwGGsyfuyF7jtfDmnGy1wt0myWbTik7Fq+7wt6YCI3Oi1t1EqpupqFi7Hnja/OJhx3xQJKjvyjDMiPrGQ/4XD1tnay7C52uHzq4QwppRwxKD9AutwdUt3CjrYDymbKIGYKpqV89UN6n8gKBwQ5h0Z1Bb3AvXr8RpEmrqNA9ovrrQMw8xXPrVs7unYEZd71NBtHXWCfE3PMb9UTkbQGmXxQ5KMkczU7W1xYmqLUrbE42sOCF9qmOGZgPQgzsOQ1Ep6nF64a1XCXLYJqR6pGZgUdfSItQ1EmsiDEEtwlataPIMQY92XRBN1vMCFhIFowYo1Y19EEk4Hwt1DW6dBxpkdaFvLiy6dLJNocIFwQZc4toazdhl11rjGR9Z1oJua9DXmg6YtAjqxUiGhLN6ctsRHZ+NBQF9xUmIZtbPLtewGKMX82wMBO/HJGUqi9GdqoC104Ny0Heu/RzQfICvBypClRHcXNx42cw5tv5hoGoGA3xVqPJKsBynaoUiLEuhlpaHuP7VdFmYq5oNC9oQyWbWuIfhzhTJa0gI4LhYwzYDGxCdr7ug4rtsaC0QDkKxoMSbbefhpSGlOy9gyrXaFnm/U6Jg0pEzTy25IxmsHFsogDSsMU2Ey8m8eXZ1tiWGfHoJOrmgr0UX4YFltNYW0mFM9AGkKd6G9SKWY9vEAbXs7hu37HzWVQgx9TUIkCf1NRaQ0IViiGOlFGm8Yn9AWNKlSM/q8fHZ9BPGPWHcE8ZJr54w7gnjnjDuCeOskDxh3BPG/UuEcZ9Ykjsfw0zTGQSLqdf+brGmGZ0C3fRIQ7PtjrdnopxIXo70MBuuNQExSW80o9Rm8t7IV5VBiiB6j8OWQ+YH/SpsLnYIIaztDDvbOXqjD1UyN08wJ5s0iZX9qupXiOO6Utonfp7lAmMIyaNjMkmM1D8h8JRUY7myWey7xTT1EHsoNZ4IshGJUzKY5vsJgfsEI9lG2JzKvVzPiM5Bk+G6yPo5NnVCzrGpLgnUOcrRIZkt2ClDbZu/irQe0oJ9MR8nFqdY7kTCPDZEkP6KmNq470Yeb7GAZHmbrsyrwXTYSK9BJKruAJGVeMsvPcL1nQ/FmlDGtANPFp19wLMSwAJvoyHpYOAxuCGHtAiyTbDaiJfryVbsyDXNCnPIz1fcDvp+fYIplMQmp6ggOuoZjcU2IrAoooGcchAD9bM0JeqfX/hCrnHQFASmozMX5YIi8L6qbBu26OQoWO88ZTeyRjVus2gI21walCNw8ikq8QYxhoLGU+OWYcyyi2UMllQZwNGgQt0pmOhLY+64quaz6gab8LNx6w5Z+rBbi6+wj2SQzRsqi2nOr619xYlPU5nMkGjPmV7n7IoMgaYXO5C2zeWw3RtgM8LmbueeyHy3yCA4+WukWmZSBpFLTavkX/pAq5H1gQOjmZmCXRgwbRRQ7PKuGMp+dKXm8e6Pd3+8++PdH+/+ePfHu//+vfvbE/hDNm9yM3bpZQp4VklvWSR5BytuwvkU5b65rg2npDdyoi7gpqzJV6IupB6QXIQgpTRqixtfZLwcz66bFkddMlps4i5ZtHVVVdu86yKlAlehIWCJD9Z1GfQkBxJ33bZIYgxYOTJGR13UTZIWnF1QQBeQz6QXUQsNQ5DkVB9ZKvs8u259RBy1RDejmEN0IXb0u2uh6AvBBuy6Mh0174J2IcoKd9Ql39h1gwQjqnXFwLrGJXS9KMEWR12tTRueWTX90vvthhlhlh65dBU1LfoxwCQtDItKOury/wHJwiUaeUBKuqiojFajrl1X5xaJv55Z0lX5WPFGHFhbtCsQmCgWH8IQJdNBjBff5TQhehGRmoW8l/1HViMklqZcuSp2FdWouWgwIIYfmgFcFfVKz1DaK1BEfnHwzUC67h5xjSnu5MgwDDpwBmjTFybjQURYgWQh0WZ+2HwDMhnjIdOZShEgtKuREZ1A2ghl3/eVox+fHj2287Gdj+18bOdjOz8ZfCaddagF+8GEXHyiO1VVFbxsmPQQPlue8vXByI+lx+SVCIGsokwSGfnB9DWFhCdXkx7JV6Ob9LmZ448oQElWlA7Suv5w/CFjdPyV9CvN/BUpXczYB1paMDmHknQJ5AAuQ5b0hgJtKAuJtT7HaRc7cg0Ycr8lnDNKukaSmBZP59RJ5tQkrHT09oG6gRdmmsM3OtcDlUrbpyzTeaS2BznWDNCSa3FXPithndneAbIEYAtpxrdepvYCCDqBY+XiuAjs8kqPAWTVENkIFfrOzHE6Vqlx8KK0JmrlYgktFEbl5m9dBTLfV7rvoQ56AUQHKZXF7bKQBAocJBW8SknUpHOVbiVDWbdJ0Fm5cCHprRtl3aWLwhZ5xTXpUx7qwqzC6+h743HlbNS1nNj1Pj7kmm4VChqx8oRkmQZSpVF3w2Ji1pOu08QCswKIuR91rSrqi05JTb+c5oHeRzyJdHS4+fYAglEnJId3UmETh3VQ9mvlRtci86Q20hlNVMVRB546OyHeCZqkEEZEG2iBvc6jpv7LArP6RT6rpZoUkYmOEIsBmC3IVHnRXvVgtc10AbzRbuq9PjrhpMusKFbInS5sj9oaTU5aGCbqiDZKq0LGNjLNKkRTG+DFXHKqipHHC+SEREcIqFYDCLqyjKyrsJCbi2eRSjI2FNIrg6osyGGoLIl6hzBmnWggBaFRlo2cHBKtrYlyXinpejMjcKQb1fYkXd/WeJIMw/otXCAEZqcEXQKzAFch6KB+A/EduhwZjTEe2DdbOb9h85q2N/nmyVQk7W4qYhkhC5TIj6vSQ0B9gQHU9O8mmFDGwRLrwrMKjOEBjLPyQOed6DAnoqQTdWfKQjoACG2GFgVObjjUWSVaZiAY/ZR1M2NRBdGPOJG/9GObfNqZ8JLuSfNk1oljsdNn60xXBVndOIRd/TS/2PQIH/KJqp6RMAGEZBUqgzBopKrsPnxBn4Lu5SHBKKKMjdPIPgNw7h/O2/0E89sTzD/BvB2pJ5jfn2D+CebnwOYJ5q1MP8H8E8w7RjzB/PYE8786mP/E8nzeuEVxmYofTOAacXAs66lA9S7IkGuAOn1xJbeEaRY/jnyfqnxXJs8y+ejva5uujK3RTSp+MD0rA4qst3A0KvrOxMETlKZQ6YKaasBIqBrddtrSgCs3qiEur5kgK61C3w0EH8GCNxAK/pUJbU0FjToQwETEyBF1llchW4FpiOzs2eZqClaFuFOHgjcQC/51aohWYJrLHK+wsDHPzb2BpgoizYnm8o269ydzxRwpKpoyed73e2GWYpUKSL0qXd64Nao5ZQFtyIRril2+AboBOjuVVxMA74w/vDxE3OKzPFeJN4xbIBbUIwERVwkJCXupiRI1AOCxgYwzAjtsQ6MyaRbuSk6qyhnZIzSHNtRn1UHNrsxJBFIWq1tCtmRVS2RCpp4iA7Oex/g+2Q4VrshFCIUSiY+RS0pcXBeyVCvwssrjJ5KdP1b5scqPVX6s8mOV/0mt8icC5qJJYfTU3gwJ+4tmPbiBaHhR8B4Sa1DMoSEP8ejg0q6Pe51/VV37zNCZSd8lcCbnqkLVzLyuueKZQ8St7yLDqc7yqlmAuabPALg+SKihJliNXbIL49iXJhDduBBxES6dayDXVL7ok28KXBmI0/xNpcnSzK7zAbMrsyus01V5KVzVuxTWAjKLtlD133SpCQu3mjJfj5/pchDyzBogJQtchXJx38AsKtC2pSbYUm1Nm5ZoLFDDUih3983lOFg1Ln9YaCTTRXuVe4blspxgoZonwuIhkAPajFPjqb+RFrpxbXqIiJEIWcspnYtpKkbz2itySXO5jbJH+Yy7ZRYBrGcB0iOv1KfN1aTrIS+TEmoq4nmTpXT+ffEAx5DHPzceVFYAIYEoLXipUQLGVRuC8eCGFWRVoe9MgXxuLA5jVM2iLSEErrJ6htGdINQo/p+tYldwKjt319kKoSiTYYMMAPCm7+N7v4/1fKznYz0f6/lYz08vtiPLPZcNCKnFjG43oEYKBfPKz7yu5tzHMKGJE2AR45q4UTm+wcEUpZK5v6FibI6LjMcbsjtYYQGZjhKSEwSkElE1dpL4SsI8Y6zmTNDQIHOSR31JpOyMb8CZ5LkXDfdw2me0ZndLDMs4neNd9bBRxKtWqE0hklYF9md0rrcP5l0kvOgAHps9PT6YAEibiAMX+oICNvl08LCrJ1PnihNMcvPDslS8EqVCv8mcuQ8eF/JPB6+401LVHCLRFwuKsymElFlKRT0OHm/glSFIjlpwvJ+g/rommn3x6Rwn/Sa63f5qNoFVX3Zn5avZf9aBAyBeqZpN4DAXUj+w82iEWOTqN5NXwOw/Jze45hs4GAXAzgjRB6TqgVMA47EOA1CM5pMCFijCTh8RLZAFYr8DrkKluW8WoG1unDxUzTEgNYaQCBrD2e/XbLqTeRhB1qqgBPDe5riP2rg2eUhrPFXTM/eLY7c16cqpeWgEWoGmqpHxhujjsfzjiB5H9DiixxE9juhxRL/YEX1iWtQCbYrsOxASPW6BV7f1sbd5y+nlS9vcXnDbuJ00ZF4zBxnL3Tkj1W/22cw0npZT7Wr0I4OhOCcue2IW0KE2UJgLyR5dNQfQK2pyLswAOTtA1xEMFIP75jLktia17AbaqmueAjhauKFPGDr9JngqYanJtMwcUh9vLBpAzuUTUj/Z3D1+NhW7i9WcNh8+xwz08CedPlt8jpWgC6LYCZUWGDBomu5AhzdEM7jjlc3vYV+F5s1YUhHGNbM/LSsVLfA2grYGLvxqzfnGIcOztjkFrZ1xQhQA9lxWNsBLOIrG9a9hmnHmupqa4Pw0C3rgL6izGnOwkZYNndN6wQBdSwSL1C1fKdLRfs1/H3jiV5+zrGzdDSS78adYmi6G3TEBDa6QMFjeIerdHRinudk0AmjmZEIWG4VoeAzhxtUncbHNH3mwFnOkbvcm9ONzgscKP1b4scKPFX6s8K+1wp8JiKs7q/bjSzNn7PTdjcplE33FojKuHwa7MvIfL05UXkdQZlRyUN+ZAaBPPc3AXChnV2ioklbNbFxND4EpdAekthSKxX2zAPtU9Qt5w9aYv/W0GveXD/ZiIYuvuGCHua/QeDnnLUDNhYcsMDTKA3OhYWOy2+8+gDYp6gtlRNUZvTLAPO2+Cs3QAWD6rsC+1jTfh7KAthcA+zRDFlDObG3h3mwa3wR6nvtkRjNRILJCRnojRWLISGQ6N5WpyEufQ+5ugOxFPvLOl36zt9cA1hSKaw0AbS8A1cjo3MwdAKunum+gkG0XdHEWnOHCISTE2KLozKV5FkgXlEmaAPaZK9iF/do6dUK3Xgkg/LFQ6O6bmceMzhYII2WAvC+FSnLfLEAtS6E5uDoFDy1LS2BmpVeffVIZ59F4C/VJefSW3wIYbUJA/1NgLjREwgCxWwvBE8GUEQ3HboA0BWzGgJlvcBBgAbKzr6Y1ALS9ANinGbLAFu8AW4gsfx1QtczLKQX4H574P90TRKJSJNST7snJlIfgFA2QvMhXTiVmF30H0P3OsxgLDG2rLma2hTRUMkCLd4B5PRK6X929zSUu+sQs9wmtntDqCa2e0OoJrZ7Q6gmtXgGe0Gr+5n/T0OoTS1d4uVdvdP04nyYV/4pLXhbSl5X1hd8biDfNUPAektthaMQNxEZ8+E37f01d+8TQnc8r4bKGxMZ8g4YOyXyH6PjEun433krbkJwPzzelxUkSU086IfIwkkdcObwqNzt7toAxw4rxCSkiOLdhykVekMBXK1KmFrwYXrFVkfczgMwr1tcjVjbE4vtVjJgnTB7uehPBo2Iem5DLGqyIKzeeT7KIvGrl8zjZx9Q06r06d/vj5XqODKmh5AN9qcsiZalF8wyxLQaR9hoEvfLYhNRwi7hyeDbtDaRn1z87uhuFJBNL0yyQb5FRcDZeBoLAGUzEUvMLKYLHyCjfvXOKqd8sQN3nunrnFPOCLHC12QL61ruBenDf9KkmmgkLhWy7oLE0ucNgmpJjjZfJpJSIbZM3JHkCfhsQ7VbIAtf4E4D3tlDo7puZzwwuMBYK3QHzPuaL7dROcVmRfVvLxd1/laY4hQLL0HoSbLyFaPKB1Rusz+ql8eCKWIXTuPI9iCsnomIQPAY453GdhCfqI3eBO+D6mqSNsY2z5Ac8QbEiyzOVbJBBpNEGQdc8NiFbvEWmchiCNxE43X0e3UhJCYwDvKxEygr8XWle6nBw3Hy1In335ZJLg2rijjvExAGYoyIO2Kepw4SI/hpMwu8JafEWsXGHWgvTm6COx8dfH1/efGK4J4Z7YrgnhntiuCeGe2K4J4Z7YrjfQwz3qcW4TnuGQM7kGoctNM8jIJDr3OYQmeruituKjKe222TGJ0QCOY+4cu6Jbvq5zsDKPO09H4S9R1Jay8GL4ivvMfuNX+30otKqRjcKZN59Hy+ZY+cO/r4younEEPeIGL2JIA7x2ISIYHnElZPoyLRKIiiPvBg5YjRWGeUASdMFwlFuxk4E76sCCTf1bcm3CghaDsT0b8YmBJyaEVcOXH8D6dn1z45zpoTk17ATaW5CkJdY68SKk9LsDmWsyCgXi/9qT68ipr7gos08NXrW4mwV3xR1iDUY/togm8+gzlw+jBxYzCJhyPzLNN8Nw2hfcTXcILi1XMmwMIV6V+do3PPsD7J1GP65ngkxnN2dy8r0tUD8NuGKmS7uXnLmcm2pb057PyGhrxINl29ejqk3WJ/1ilGIR6ymMXr5OeLKiZgYJKquz4/VjHJz/l8jSgZJ0862tXj2Kx8aGiR7y2xbNV+DmRDTvxmbkC3eIlM5Mw5vINBd46Ewzv660cC81PRlQtFvJhQeow+2yJzl2Xp4+1VZ6puv6NuIwrazTbOuCYEqA0NoZ5DmIh8T2hmsznEHDY2PyD6zPPdEdU9U90R1T1T3RHVPVPdEdU9U90R1v8eo7jMLdiHRqmloFyL3T9Ui8juGdgeGrZAhWMG89jEEa0GODobMkGmIkUVGaLcgrlye64NTsYgOYMhuG4otfx15ufo370SdyHyFhXwxrm7BTgSOFMj8JuPLxff5RcTvF4agpt9gQ4xCZDC0IuqJFmxChmAtiCs3AiTbghFEQWZMqGWxoPUh0BHEv0Jyltt5kwVfzRdZJgT17bzdIq3aeZdFWm4Q9M9jE1LDLeLqE66/iWhohz7bcQ6UkExslpEJETkKa6gVAuMlkdJgf2iSACvqHjuRWjxSlqrwvBIaZBBptEGgygbrwX/V5/qs6di4ryomJ5j4Dtww8R0kxVqzwDgtEUOcJlJgsikAQRbqStbhWkuduwIzT4TuwWKh+68cy40bYxt2sny+T7Iil1TYD4KLIw1LbBEfR1pERYtRZCDLm4/0oAgm0rNYD5O6IDJZEKuwiGjegbhyIjCGeuweycGLkMZnYXf3UIxSM9KjQcdX/iUwmlJbn8HibJbZcoMEOpAZm5At3iJTOYyDuQy1ItBiY8gwzokSEhgopDZLTfIzjQUZjrTu/is391iQFxuY7AwLXGQZzNNqJlCYMYYcVFKDQJUzT3b0PH8FEwDajPQsVucwhCbHB2ifWL97grwnyJvCmyfIe4K8J8h7grwnyHuCvNeQJ8hzqvzPHeR9ZjlvNzTOIK/xvoSaxd1Yzusn00AOcTqQMsd3B+LPRRODKbfIiO8WxJXL2Zcbw4YWGOe1YCfi9qvQl7mc2526Rea9qZfBJvq77rKBTAhCu8atbrh88zJuv8FEbt5E4IQ8NiEiSR5x5SRAMogEUe0m1GoMa4LWtyI+gcyJxd1/tW8e2Zb69Klftsog0nKDoH8emxDhlEdcOeH6m0jPrn92nOsc1fmMQicy549ZkZer3JxB5kQQMgFJy+yn8AoSvlqRcFPflnyr5mcMJwROwWA9+K/6XJ8N7Qo3W0OeesP4rjD8ixRhzDAR3xXGaYlYdvEd6BvEZ5lh62mkDSKiULgvCadgsND9V47v1nkVOlrwfUXS4iwLo0d8VdLbyIvllfmqOXdd5/jOSDn8vnmMu95gfdY1xiMesdrHOObniCsnAmOQqFZwW+ItiBCiMvTQID4FjfGh5isfKTZGitlba9sqINJyg4S8lgvZf7Ut9W3Rl8M4vIlAlY3Xwjh3igviu+4FZrfyBB9qpA6e1n61ItFrBzy7/cqFkoxJduvrZ2xChn5aRLWYmIZ2FmnxFrExCawGe6PWxkZkn1i6ewK6J6B7AronoHsCuiegewK6J6B7ArrfW0D3qWW6TKumod2eeHkCoV3mUUrEd5m33SW+K+409IqcfSuMkiS+M4jEdx5x5XL25WTsituMusrZgGz6kde9qQNzO1EH4jynRSBZ2e9NHQi8KZA5Y8tZLnJbW13+MQIIc/oNJnLzJqL+Z8EmRCTJI67cCJAsMoKoA9mnYO/FSA8CMvTQIs2Hdgt2InX3SFnqi3zTRlplEGm5QdA/j01IDbeIKydcfxPp2fXPjvPudi8HBqkRKd99Vp8DWeKtA3M5fG6QsGb1ObC2+a/mS0kTgvoCLyVJqwwiLTcItNhgPfiv+lyftRoGC3nqDeI7cMrEd5Aia812xmmJGKIykYfgsxOwDYzv0HpaaoOIPATuPMIzGCx0/5Xju/VgHuMIWmTJErFgpse7lytbbvfRIySU7TRI6Ku8q/OHXpggz2J91joEJQti9RDBzDsQV06kxiBRLUHxQRflSEOzW6T5II/eFF8lHy5aJHu7zVYZRFpuEPTPYxOyxVtkKodxeBOBPhv/hXHOlJnAaMFLTfYzDvhVK38eo4e2yHIA4XT0/KD4AwgWYaDgHiSbEFFSg0CVC8939DkwoQkoPO+BIK/4C1nsCEyOD9A+s3T3BHn+6yfIe4K8J8h7FXmCPGOVnyDvCfKeIO8J8v6Zg7zPLOfFQPuGSK9z01VtI79jpHdg2C4ZMhWDOxK9Ii9XuTpbdouMSG9BXLmcfbkxgKjP+LIY/LYVWv46Msq5basDcYmQwRfjAxcsxI0eFkib/PnLxXckfUAs0BntdGKIiUSM3kTgkzw2ISJYHnHlJHIyrZLoyiMvRo4YqXVGQEDiFAWOcsiHjK9WJKz12QY1n9TFIuiaxyZEmeS4OLF5/dE5nHEJ4SsFIb+GnUhzU4R6E2pVn+TnQOYkPysyysXdf7VvHtlu6nNpfw5L5RK4WMRM0LoL5Awlh9jQrnKfNeSpNwztKsO/SHHF5BKhXWWIloghIJOxV85YZJ92VSwfaJ+1h9au9yW0M1joc693z3frsqpPGsF2voqMcin5r1waCfJlKucDR4OgnQgbA/mOyy1w+X2O6roNG7qNPcwPUTJGKqqSryNWlRkHdRsmQSpMMGWwombTpR6mFpvgrTMQxFc+6DOIqQ9YnM2taTSRQEsyYxOyxVtkKkee3yB1Cd6M5dKRhMMywRvcGuSCYcJOhzwjw0G6bMNwtRZZThzAkduvVgSBoXHktfh2zpvKE6IaS0wjOIs0F+AwgrNYncMLWJYl8PrEMt0TvD3B2xO8PcHbE7w9wdsTvD3B2xO8/UsGb59afivr62Exz8Fb4b0JBG/FPxwWK0M8Cd7qeuQZGIO3yjBJgjePjHLu4TBLScauun2lUc7tNaHlFmlL8OaxE3G7T+CLDd6KfybsFomTxz7LpfV9qZgZtvQbTCToTUS9zoJNiMiUR1y5EQdZZMRKMa/BlMWC1Gd/JIZJGrcdmHsw7EBceuMDyUtVHjuRNF/xsAi65rEJqeEWceWE4W8iPbv+2SE2r8plYrN4nMg+B3QL8nKVc0l84u6T+BxIW1TEYyfikvgcSFnq233KHotIyw0CVTZYD/6rPtdnTcfODdOQp94goANfTEAHKbImLTIw04AO3KKRBX2D4NxzJf/cuWf0h2Z+52Yi3IPBQvdfOb5bN7bT5YLvK7LkfGD/dkqRy/lAvuxWrlwAGc0LUtJO835U6Ku8IwxIdLj1Buuz1iE8WRCrhwhr3oG4ciI1aIEGVhbJwcuRBmnsoUHmt8ZexJvig+xjRthTW5XBYvdfSaMNgq55bEK2pT6w0mTB7rN3uEWgysZrYYgLhSMwWvACU/zsglHGbr2pO1MAv/w68mKjk93HBhZZnhdbMMYdVFKDQJUrz230OTqhCfCIjU5oOoo/27EEaJ9ZpnuCvCfIe4K8J8h7grwnyHuCvCfIe4K8qZ2/zyDvU8t5jdbyGniLHZZXutd48j0NQcNLXHUM8tlwvOFVh9CGk2gSZAjogYgPFOQol5AqFV8hBysoIZtrHX7yLBf8ht/JMfX61SEMq4DBZ4DSgQwFTIFr0q2iXNBhGDFFMvlMR0yRTKbSmNE/DLJEHp0DKtFJ54Ai9sFLK9KGE8G+1eDLMn6nIEytaDKqyWRobXHiDcTqlFTfilPq95k3u39lDojl8s7cJjIWu89jcjZFx1ktox1plYbrx7BUVoBgqfDEnH4FRoHI2QoVWB3QMzbUJib9Krggp3F7D5a4uTOwJzI/o20GxlhwDGjisHdFZAiQjDYhKKXgJQ6UBAVJWs7BTAiCOZxxKOk5BDjEXXXoNu+cLDY8jUWgoktyiQXjAMPTUNXoadgb81VcKC0Po1OkozccbHlYPanFoO5vIPWmvpr9V21pgTEcwGQcgCSqAsYYqheMqNDWGKQkP+SwNUbESpuqin3N00HLgiDBvyI12Zq1XCD1OFnAybalinKwgFV9hXOOixX7zErG498e//b4t8e/Pf7t8W//GvzbZyZxKetsV5gysJRmdmayQMYy8YAQnJXJLF/0q+gantxRw1EO2SNRzl0nRn1moRatUhPJlh+IyLj2T5GzHDL04Stk/wOlwgVl1Fe5Bi2tqrx8Ly1XxPavLu6l8uadlCvuTNhoZ3EahFx1ZmTm8RtOzvRaQ5eEx3jgL/A0DviQGFxo6HIqtAY4Io7RvyoCxPY6UkS7flVnT4D6rAVCjn3Tx12RPI+q9QTI2oevqiVSaSRRVeU651iUSpVeXhpdXW6CUa4XP+w+utL6LCvrLHPJjYcftU8ErY8+P/r86PPvWJ8/46Rz4LvCOmfJJlfDEMK8c4AGww4EczAV+hwZtI9A7UCgwiNUBGLmLMRUWUAJ+6RHfVV5pLzNu5vVnr3p+8SoA9n9xCVvFGb5aqMwS+DbWR9koLO+ql+5l88sAnEzWNWv5tfeDNKxVM/6dEXgQKBOQHD5J7A+5N0ZX+WbH1pL3sjr0RaLtOgR3Uu0mMiEQcb0KI8fmJJ3ZyknBAzEsgSUwWAiWNYA29HLYR3jqK3DrBfSsk/y83LpA1ZTVpkas/+M/DCc1FIWjcTmWc+zyUej2z/ULD2KYhHUh7wrpj7oqNRnsqeMGcCBzHOCwRdYraijXXePpEW3NzqmMVAYbayTYJjMpB0Sq9j3C8MMSne0D43fbzBsQOpueJ5/QvzNrh4bZjrkMrhmn+XVsabNxsMis7n8RBz1mNzH5D4m9zG5j8n9vMn9VKib+Sgt7K7BpOGZM76xapiRetDYwUz1EFkv1AiR4sK1b8h6dfJ/IsVRqpR+1Nco/9KqRnsmLTeIntogBlPU/FsQ2Vy07QHtdJdMj95gGVJ0pHD+Ch0xSSvFUvjUlieS/IG5A8MJ2TFN4sjonsAyftf8NZurypct/TFjYhUbZ+2ef9wEsZzH6ETn3cyoovVIi4mvjMzs2h+MIOpLHHtpVfIPGVuksZy74kxKejL5QOZTz5bLHMPsZuPTCKozyCZLlli+zGXjNI8X1fRsA847bXVqJ842WUTPahHTHQZSipQrvJ1q2gkrJ9wrfg8H42fWAzDK/Kpy1cBpl62v+WN2B4JjdnudEdM/gwkXGi9sblrOL8ObNoDr1W9pWs1FOytlobreQCub84q2nZSqxjhHJM/rn2plmHr9w2K62QFbpAsthu/cx8m4sK1bKbCiWLKxowr/WejfILXYzAkq//O62ZCitM2tMrIGbZ7fzR3lgMGGpfnKeM7uMq21HtiUORC4Sowz3CL6V+kY42zJ6XSNfBgp2hZZC4s8Bie1H5/nPP728bePv3387eNvH3/7+NuP+1uZ5P67P8LN/u3/+ce4f+3fji//+Bsc7pmZ5uz3UfxMh3xUcRD4+scf1lXLHPm//Jv9tz//9m//69c//l9f/o8/vo98LB8gfwjanz5G/tzKen/r/1sME3lO+s8R3ManfxjrORc/rwWGLR7E8yVLMZ3ByRzE/If/GOvXf/8/3tfePLZft/BPw+0ydGbL7+J22v7yMfI1fYh83D/C7ZZ+HZtbPhS9997e09AtxQ9KXU8fIL//Vj7I5rDFD9BPKfx2y+exwql8Hnbr+BXCeRLuoH7eU90uUxf2W3435bdSHOv+NxTHHvQp1QfFM3QN9ZZif/cInjnxTxb0+q4h/NNeP8jjq6HvpR//vP23j9Ifp+y2/V3tr7V/jL4x2yH/VETqby+3IjIWcZcBjSPEuqxqeGM80/bu8Uwj0dXJjp+39+PDmfoHyIff/nTPjk0ZcLGjfy0nA/YrCgu3JimFVUVuOVrGYv/PObq/U+cOS69K/DbB+F6CI6/Zln5GMHmCYwdGCY4Y5vhV88W8kEOv7ZZSfifz6rmRI6r6S5jXxuHly7G/SbC8s4VtnKj5OcH63hb29w0vLepPRqMnmqM3B6W9qtInrXsTlHpWJXnVBJW/5Fe8VGtsb1LDEysUZtuuCH2/b+/CgFcIppEt7vRRv4jguF59cvQXEazXdOPXEczjxPovJHjOuEdc8osIVkTYHyQYB6WsMU4ZG31XX8MbQWTe3m4aCeZDS46+lp8RXF2Ap9Sgy29TWszX2LdemlaPaew1Dj8jGD+jy61ck+utv67L+S8/iYY8+ZhVtN9BPoQ/h4+RPw989osh7yD/7lmg8D4Hsuao+PRE5Zbb6d3czucK1Lvbu/+5fYwdDDbeM5gvJX6QfFcr8J7BfO8sULhdqyrLL+N2PdfO39ve7U9/fvkYO45mSjDxLnb86YPc7lndzHta38sHp7IIENJ5CnwY4Fcb/6dt++AsqHyAfA7bTwR9mQTlD5Df+m8fnMOdaU/ErPyc/DEL/2DrjdV6B+9r/OBa0HkC7yOtLx9cagofIL/tLx9kTt00on5X6/sHW187TOR7eL/lj5Fv7SPkS/jzB9ef6gfIp5L2j64/lQ/Qj/ufPtj8cEzR1SL/UyjW+Rbe++nn7eUniw1hczY5HMFhqldwGHv7+ULo/pMBWCuo5dsVIKT3VJC3n/mstYLTax01tPqeCuJvzjocQe3hqK/9iD3I7sMfZE/qH/7y5T//zdf//uWV43Xnp8t2/0lvH3s6P77sQZ5qBPYdpwdKamML7FdVe24udVetYqbaTc9MHmbv2pX6x1Wb+xDLa6dNd8wUY7W5Ntmc+kXV1oTcl6i24gAnqj23h+MvrPY8yhtdtYqZajc55Pyrqt2SihSrVYzVpiY7nL9IpFLF2QaIFDBW+36SaLwRVmALZawDyWrCqOUPe9B4e7wJum04VH5uGP64YuplQe4w1N0Q4U8QSb1fu5dhUyLLmtl5CFeW2i8qaeTZ244A69oHvnqRNLQVKstC2TuolDNbBWbDJ5Vl2eCYNoyelP0Ss/2KYdaSZVkmaEcwGC6LfBEoI+g/KtUlu7MP/QxHb+fiZeFt23RV8yI4zhScw6LjlkoxrF0ILnw+j8KPeZknKAsc6dx4f3Utu6xrk0HXaS6CmCoUrCWeFOO5VXW7alPWDaTtWxwrF6/1+fDXr+9IFYzn6Rza0GSqbUySIu8nitvvTngbd7MHOULzhxjlcMtB8VSv/x9OC5QzCmVuZHN0cmVhbQplbmRvYmoKNzIgMCBvYmoNCjw8L0lDVig1QkI2OTI3MzAwMkI0QzFCOTJGNDFDMTEyODMyRUMzRl8xMikvVFlQRShURVhUKS9SRVBJRCg2NUFGQkZENjMzQkVERDdFMDlEOEY5QkMwMzhCQzExMCk+PgplbmRvYmoKNzMgMCBvYmoNCjw8L0RvY0lDViA3MiAwIFIgL0xhc3RNb2RpZmllZChEOjIwMjYwMzIwMTEwNjAzKzA4JzAwJyk+PgplbmRvYmoKNzQgMCBvYmoNCjw8L1dQU19JQ1YgNzMgMCBSID4+CmVuZG9iago3NSAwIG9iag0KPDwvVHlwZS9Gb250L0VuY29kaW5nL1dpbkFuc2lFbmNvZGluZy9TdWJ0eXBlL1RydWVUeXBlL0Jhc2VGb250L1NpbVN1bi9GaXJzdENoYXIgMzIvTGFzdENoYXIgMjU1L1dpZHRoc1sgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgMTAwMCAxMDAwIDEwMDAgNTAwIDUwMCA1MDAgMTAwMCA1MDAgNTAwIDEwMDAgMTAwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgMTAwMCAxMDAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgMTAwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgMTAwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgMTAwMCA1MDAgNTAwIDUwMCA1MDAgNTAwIDUwMCA1MDAgNTAwXS9Gb250RGVzY3JpcHRvciA3NiAwIFIgPj4KZW5kb2JqCjc2IDAgb2JqDQo8PC9UeXBlL0ZvbnREZXNjcmlwdG9yL0ZvbnROYW1lL1NpbVN1bi9GbGFncyAzMi9JdGFsaWNBbmdsZSAwL0FzY2VudCA4NTkvRGVzY2VudCAtMTQwL0ZvbnRCQm94WyAtNyAtMTQwIDEwMDAgODU5XS9DYXBIZWlnaHQgNjgzL1N0ZW1WIDA+PgplbmRvYmoKNzcgMCBvYmoNCjw8L0xlbmd0aCAxNzEzNy9GaWx0ZXIvRmxhdGVEZWNvZGU+PnN0cmVhbQp4nO29y44mPZIduM+nyHUDle103gFBC0EzDQ2gxYwK0ELQoipUf9ciU4J6FvP64+40O8do9IiMiM7u/lvyKqAqvpNOI2m0G2/G//nlb//uP7Wvf///ftm/5X07/vP1/O8f8rctXb/qtwvdvpa2fcvnJ/vXlx9fxmf/8PfHH3/35W//w3+sX//9//jyf3/5nz8jF7ZvKb2DXn8vvfjtIPQL21e+9f0d9MK2EtwbCW7fYhkEOwjW9i0ef+/9lmB4Zwv3/Vvt538+zsHbBu7tFzcwhvc18L1DEuWv8NEOh29tu6GXtm/b+Q/7z4Y4vpdg/BbfJTMLQQzCRfAQ5UE+laEkRwtr/xbCSfyWYHonC1P91tpnWPgKvRyOVn1miF/pcE7f0tm++OEOvzIkuQxhjx8ekkO7yh3B/j4hDFkJbl//Xv71//m7uf9f/78v4fqH8b8HldDj1Y+vpedDefbw9cTSNWgHlr7lQy0PU5Ivhh3I8XkV5Pj/gZRDCL++fDmxlgSLWg5IyB7ZlnL7aMOEFFff/i3F45tRTlq1f4tBvkpNkNBvkVFuT/6rMFE/kOtHD1IELJHunkjaZiYNj3Cx8mr0yw17v3/564Ful2870MNGk+mhWOz7hZWzoXU7nNdJ8fsX06H+rWbBtsuSeiwrvavF32/q1dZIG8O3fpY+WxNGzSfWRn93ZdFhZYMge7LI2d/90rO5nLRXqBtk/7ZVlBOssPfbZd0mrHUVjAmTsvVb1N5jvAyWtW11tO3EinLE1BsvM/0KJn112D6EZlch3UZJw7VtjMzoKzgZBifDpfsXkoa4mzEBb/046ejJ2BsFDtr7PBTj+4UllcStQh6KSvXVOsNfVbzWOZhHI1pT0mjEWQi2YIvS/JREOWIWZG7my9n4g9qurL6E9IfF1IoQCaJqRITRZ8uqdmaDwBNT4SOCLleqrap7qyoWScsVbwFbpklQS3ZgMpDx2y5MZkk1FKRexCqyDXXU92LLVXK6qOhQhFlnG9Zs6vcd1pWvgpzmJeYZCbCWB69hhLLSEv6j5Hc7bqZOSIvBuqphGyI2BHFrvq+gd4eVMQpTHeVbDiLEuxqJXYSY5iUof7vyV8bdyHGG8BPJLAds+AqLRKUE2uAj2iAKaDgBKfPIKLcn/1XYHSU2Z1JSdK2pPS+LUhV14H/98p8kgLChhQYQT/DwBA9P8PAED0/w8AQPT/DwBA9L8PDb31zRA5xR3XYxZGNV6esfghjRf/jLl//8N1//+4dWKvZDqqQrYg0nTIzMiQgTxBlPiBgPg0EVDp5QFK5mnwh6OUThdIeLl+7qK+Glz5Lij4U/JyI8rEMRzjbIQDQVjxODfy7an0s8oCwn0lSlupbbh3U3vv7Ekn53eZiBwYeDfldPHyb6Z7vAr6wGuLGP5Vqio0k4sUr1zFmwpOJ8hxWNOc46cvFYUT7CEx91UFsdqRVLLJbVARqs6AAntRJnF2RY0nCwjt6KBZYt11qdx4o6xcw6ENZUpYeBuMM2DSZWNTgd+dEa8veHLWh4DszwN60/UeKvc5mLuRNtw8i0/jTD4ak42sLUHzMTuiXmfpph8FQG7ThkEzry48JqEfe01XkQoTcn0osgFz0giI9fvkxY1q9Ea0QbTqSqfuwV5Yrqn2hbosZv8RYZ5WLxX+3JUp+QHFAuaBva+CoOK2fsiefVFVydZmq3nDkjw8bWN7WH2xwWWESdJbEmHuX8Y3LjJwKro87yNDZqdWRi1WhLolKakVEuNf8V7BIoARErd2LgoEw4q/oEGfuJL1Hb6Xn1XTgY1C9sysGqxkCdL2sAglbQ/bNHWSednWFgzeJh0rY5OYXX6VTyTY1UI60yeb4TwexpHcVMrjYNLmQW2zhBbxVt99P4xnlCXpBtKYc5I+QBM51GQ5rJK8QEaJWffbavdl7CQcA0Ewhm+QaBoBksL+VK9QgFbeZG0AlQDh6p2fcq6hg1hna7yjRcVwIX7fBA/JJOsCGkyXJjFtzvH14ZeoK1J1h7grUnWHuCtSdYe4K1J1h7grV/1mBNVuI+dBCoNSHU6rBaExa4Ig1sk/02iwRdHhxI7Rjpg+xY1T8wrPoqdpSUtU8gQXYDLKJ7hcQqN3KANa6UC9K1XQbR4T0/3wXT7Q72qNnVY/DH8KIky7NrLbUVZYwuvp6r8TLEWMg9MCwAD6N4IG4B+EA2lhMsizRYpGo5oZ3Jdl0UPrA0LxwfSNQlYWlnhplcMC4cG0psjl04PjcaVA6Et0VUbpGysZNTxHooo35c2PA6pAYELDCIbnRZTJppkKF7rC9xB8hgVXdthgU7kKL1CcuTeu0TE3Ym3UG4Q/a0lpsx7s8YZC6im0Zs0JuImiOLyfZTYd9NvcKf0bpZlEzfi+4bgD9GvP1IDu8aVA6qRqYGa2oRAzVRvKtuOxp9xWav0Vdsihp9JVY1jj13Jra0YlIHbQl29A9MZkvnd3WS3AlLwz/YzWOL6ba7DsrYPB5eu8URZ323fTOYbhS33R8VUIt41rkrgggA7djU3emJB1hbbGCr5X4xm9qHne5sf5kwnoI4kKqnJwbP1L6PAwxF25DmTe6jpRKV6kEA7fM1xjML9DzBUUgCu42OA6Ymba567FIdGE5A6GYh2RJUKHbuqItImCbp6QfTLmzdKWZsq0GCfmNcTkleRFDnhGU1CBJGBBpUqAhUa69oq/TRuCq0tYI+W2vUwavqUGCjTLuGx8DUQBPJysmdHXoxx1RmfVn86lLdx1egnnjmiWeeeOaJZ5545olnnnjmiWd+f/HMJxZprvV01WH9WbhAnlU877DKjZ9kf47V/abOsXJ1H75hV2KRg7pi2W6FzPR0nT+pdl7a88NiQVfGgexc84b4Fl2b37VbO3fooIlujZVWhLuEjABNT/dhuU/qWcU+DOq77KkdPcc6f6A/3SJoQWGK0t8Wq8r9S+UkdxgPJHaPYI040MvKvmdgYANORI005FAfd16saICvd5gRF92HtBhGuLK1qXkkOFU2vKhc4wa377CmOzs742GRC7SrabR0YmIqxHOalnYdS4x3t/yp6qvz0gbx3yd3tmRrPBFE1hKiTliq/ivINJBd2xBpOWRsI/277AjJ3jF49QJ15r6gDkRTgUjsXFAETIFKwVJ0az3AdGFnVjffdBM/k+VgAeg3VSndTGPnEq01umKsldlWBtOxkVg4UcnEduclDCZzmAkRXgDJbD/ake2eNDAYurT+TLb2TZXVYHlSaruLbQ1EUUWBfzbYrrw3iPC5MLboeiAAdQY9SFBoBkVZ9dCAGsaJCyiH0Q8qkJAtiTbG6APDYQZI0q4KrXv8FukLLY8Zrpo+B+VCVEkymCihQUSWC903N29ne56sI0rWT6WvWDJ4uXFuI87Q4ybqlH5cWFO3JNvRmwt3jZncNGIzhl4iPWPsJACeWhGX0cBX4CCQylAax1uqC6/lOIeGqBQ+jaInxKgS1klgjmKZEdnVRvRtPbxi9GEHgvNDSRmw0cNgniDt3MiUrOwFAxAQdwo7zg9hpUb2+jrFP7PcrsMpsxfdL1fl4r63rgLZPcKjDbqrTl5zJ5Jd416fduT7hc2Sws1yW32fpHBUPy8rfDdHBmYM4UWa90ixkqJb6na9hW3NvPPUlrDQsLToJQ8zPBmXRqhJWW3Kql1D53RjVb3dD9sLM8lu9IqbDvgcUJjWNW5Zd4Ym0n+ITtN5Qqcfw9Z6d75tQkR0OkMhI2BpCrVMqypFNbpQy/TGfIV5FDave/HtbPTdUTe9EVE0FfGZxx+/PPrMZZ65zDOXeeYyhlfPXOaZy0ym65nLPHMZIs9c5pnLPHOZZy7zzzGXkc0Znb+MXeDNZw8M5TTIvffyNcfhx2K4Tc5XfLa/meI+siQ6imNjNsVbikuGw3e0MY0T03u5pdh+RrGXleI40B7SLcUlq+M7KOZwSXW4TXK4L8lP30MxX/Kw3SYX3Zfkou+gWE4zd4hgvaW4f4Zifiv55E/4eCs9pb/Bx09JT72Orm/5Xnp+IuH3FMcVk9TeS/EcxluK158HxSPCPC17um3jvuTcfMfIHHbidS38ufTc9Po8M3D0Ov46PvZhFeO9FjYmBn3f0kz5WrauMZ4eMdtwKUWRFPR6YXE/+O1fv+h5AVLUc178ShES0VIrYmkHTRhF4iHbT85fJIHPb6CJrMYhhqw6JUNbIUNNC95AtoLjXwztXefm/AQQCZ1l5l+W4m8fW3srEkWaRlTxlKYRCplqteANNHWwy8yNFRz+MbheAjLUtOANZCuQ1MxTBXrEy1SgEKmh4A00VdAX0Yp65MRUoJCh1hchW2idFSQ9mMIKkmbe4neASA0Fb6DPi0QqMjc1zakylTPNUcjUrQVvINucvC0jlsNiCQCRGgreQFMF0TX3qCAtQg3IUItLpxZaVwVlGbFcJ9p1olGWcVoonGSPYKI5xpS4iDIgY2i3pSsLrY8LwhmJOME/IK+BgEzdedHmhdbV37YYn9KXZgMy1NpifBZaZwU1LManpqUhgEgNBW+gqYK6iPIB+YYAMtTqIsoLrbOCFhbj03SxlN8BIjUUvIE+LxItOT29oO6oAjJ1p0WbF1pXf9tifM7z2k4FABlqbTE+C60rCAkyWzRRSJIJqwlDFDJRhxa8gaYKfJj044R8QwAZams0tdC6YpJtc+09gpJzV8KNAjETg6DsHfZ5uQjnCn7ybSpLNEPM1r8vCr7SGz3XBQ9TS9iWsIqYpahl77CpluCjsLOWNFeQJjphDdJWKoN2cY79pN0Xi0HMUixLBLDSG8HwvjjAE/P2i5gNg/dFt1Z6n5CQPS16Efay2A5itv60qMZKb/S8rQH7vk4YiFmKbZWahd5VS4yLEQkxLR6dmKGIsnfYXIueV7e1rJMIYpailr3DplqSD72OWlJa9IKYoZjWGG2l9wlZSXnxAiGtswtitv68WNaV3uh5W0cxrVMMYpZiW0dxoXfVckSoi816by0oe4f9r1rLb9Oaxwh2N1nzwApIwhNO20hOs9+ueOw3r9OUdENP8pGeb6u8TTB7gliGmQnuY//45y1cVnnitMoDgsfcVJ+TeZvgsqAXp8UysnCkQv95l5fV4FcI5oL3ad4muCxiYrltJljK+wYlLmvBr/CwFrzU9UEeviI2bSyMnLumHxabW7nu9Z0tXAT7FYJHjPPLSIWGR6a28sYzXXFZC31FYk73ejrIn/PvRmTu2xg7Xtb6cK9vFfk0ZnsdD029U5PfvfgWwohhUkOuIYMV5B+v4nvvMaR7WemNJUagVxYlV0vDpS9SvMdS9LUAs7X0y77PtZxXEX27bzEp+/2Gnqulrn059/26p3iH1bUvxEwteduWvuTtOqAxUbzHtqUvBvvwQi1pyGXqCavIY87677CCQw8LPdfzrveViYUd28ygeIdp2e839OZaQl77EpDYztRyh+W1L8SmWri2DWzf9NgVKd5hAZHJSm+u5ZgkbdHXsuOWLWu5xzYnkQb7vKzsFbkFiTXc8mX9d1jFmcGF3tzzKIc0bC1xx2ELULzFNhwEW+i5WpJe0DRYxvsFpHiH8ajaQs/VUvUFiQnT+9OkeI8VP4rEbC1pX+x9PiZY1UvfLbYv9t5gn5eVxFyRFlt6+QqW/SgmmzWSqOQgtLXkoIfLSPEO07Lfb+jNtZyr9nIWm1he7eEtFnG8b6Hnamk3fek4yEOKd1hb+0LM1lLiaiNLWtt9i8XVRhL7vKyUsnqHUlcbcouV1TuUcucdakCGUYtlbz1fwYLvObGploibB8Tq6glusYiz4wu9uZa2rX1p22oPX8GWvhCbaonjcNOPGVvs4StY9Pae2Odl5YhFF4vamCmH9d9hebWoxGzPe1i9Q49LHHuPhdU7EJtq4U0SYrzdT4p3GE9UL/SmWsqZw9aNYtl2niPA6twdtuGw9ULP1YKHngxWkL2AFO8w5sxe6P0jZKVsFXl/gYVt0e5bbMP7Piu9uedhXzT+xLz1fA3zGm+wqZZy05e2xH73WFn7QszWsm+Ldyh7WKLle2xbvIPBplokpppqaYuluscQj630/jGyckSJXuNPbOnlK5jXeIPZnsd9iaBLTIsnuMf2JYI22F9nigt/311LWvlL7H+tWlRWcpWJ3mFv/rDLhYGfvCWV2t0Zh7Elfp66lICxj+0nIN+JRBw20FIrkhko5rH5k8uuThlf7Wq+DCUNd8vojYXyFd1pIhtJiWRqD7KDewvxZHnWCIwQaOGceohj3/L8Sm2sobVAjPCy9oWQZKA6IZ0zRBZUF7m9ATUEKrJ7ZSFJzHSecO3B1di1Q3LyyyBVIzW88NfG0YsTEYsvGcDOmFE8tA6VlpL38k66l0bL2bGzfZLFOY1jgWe/LgsftSVyg3FXAeEVrbFvciJiR8dKNgcojZMeYDKEDEfdM6m26YvkSuBa0Xk0U/omkfSpBoijJSrryhHhUZBcTCcwTvBvOkIdCaE2DfDlhgIHVjMXyoOOYONRKIhQHoRH7kEDxKmQjsULJabqm5namirPavo+nv2G+jW1WVB2SBkQSGehoHuk0VYVpw4/LKXN0c6LQViRyvUgOSabS8AMVCUnqARHVQ5EspC/oPIotcu9n6SDhXtATWUlqPWRLIfnwfdL5VSXisQNqm0Zd6WyaOQxu738cBKxybLmpC3PFfdWiYjGJhnLA7nmiSrDB42rb5LB7/wt1wOr6Im2o6m2ykU2w8E42qlIlptZnTSvOvC74E1FlW5t+ncDSe8IyPSGKsHbVpsqNdgcgnJer07J8WTSicoT4evLafzG4BzQSFKvBlL5BiNKZgfJ1ndCI7lnEU1CF+SoJ8i+fLGQBq9ZpOmAxjUcSSGIZY0QOSZ6oUqO+ZxQE1VvTfo9ktgFFTiySys37IJzgGelO4JGWNYv0I7ZJyzSThMgwoKlEyBy69L8TlZYtKaPZ0V4IpMnMnkikycyeSKTJzJ5IpMnMvmnjEzeTkB7u3Ciiy5gmYVE1vdAxo9MG4GSK7K9B26ISQoK4bMBoFJaaKM4yRVz4YxWTcDkbCYkiRbUL26aCceJ9lXTPOporwGEoSyk/QZhw6yR9cFz7xyFfVdRidgd3ik9oyBIa/qOwPENqB72VZLSqIkhkLQQ8vQoM3bNiEBhk7QBCkSm1CYkOShUJ6JmpnE+3rJUk0SBpQSkTyy0M/YchA2zRtWee59IRPbI9CPTv3uZ/oSxTrtW3nQyeR6dTxb6biBMuVjwBmqcUKagQV7Uo0ApKfOx40oo6PSGBW+gyGNASV22qaByXLSCSpes1BLlZIFsBaYhsjlomyuhBCDVSdPcG4gF/zo1RCswzdUKKq2AUjPRioemCjCt2FCBmdMoiwInlJcc6o3hE7hiqLTz72Om2Di5km3gJPdNzHmKVElVe+KbI1yWhkuiPyubmFlaSOIcyuYtpBKM+AtzFEKSDtACF08IVA3R0cPSNPbSm8wnK+WolVWhvCqHQoGzcS0YSP7qckJsKUl0LCDWgpDM0UlFDhEszH0ZUiExc9W8QZRYnOazQuwueN9CmFWkxjhe73wD0mmVAkVyQhGIOrNOzZlHI2YlmQYEhYJruYEg9SyIeYzUSEC8BQEkzwKkHo6AeO2FuSfHo1mgkSd4o84CuWZxpvTRVYGrkdGs/QQBsgqOzIiizh11Nh8bl3auJsamwtzVY8SmHJJ1DAv0qVDdNM9SrFzHcM0TpV+6efW9cYBk+s/aJANo7LS8mg8B85eXM0UCnP/oY9eFph3DAL8pXIexMeMLQGvq2jLtY6fM5aAtE5khI7PGILG5VbHYqJJRKsG5N1bSFJIp4VUNDkrExpVIzSWB5Q5CWMPDyk40C2xK2dBSSAdSPfgBRI1eLiuBgSx4ziQWMlfuHTE6i2YxRmLX856j+qOldTLPjGaJeYgqFmjwfkw0azaXyAPQCT5af2gc5dtbJYghipnFocsELYL68dnCE1Q9QdUTVD1B1RNUPUHVE1Q9QdUTVN0GVZ9Yrso72StxSd7V/BR1unnncYCxnbzrIIh05UDxlM3YHHSnUfecA5VlbODhi6gWIgfuslzDl4PKnwJmoU5Ujs0TOnmnubyGht2E9uSoEikcJCD+aOHNyeNsbr1IKJqT9kvsEQG5kXYAwYloThxMNFftct7o4URKsi7C5qIBBHh+fBWnBoNO1MXwrg/saio2iHrOyk+xHAAYROXMfXUJQhc+SLI2kUpKUyYT5d5RLjRN176ZZmhDJESA0lRohoc0FYbZg4tFrRm8cq5GJiovao2jGtUd4Dm/p0UN8s1sYk8dbVZqrkLYrY95aoiEbAtbLkFqNA1yaefcpp62Ib6fUFIfPnilQJHU8QSwN0oIb1GcAtDsoH5nAypO7Z+7trMkAygewH4BIclNDgBt9l19GRn4opKWyzEHFJyslE35LZbn7PYkK5p9D0P08oWQOM8zJip27E/h32ZZKebSnn6TJ3N1zsCaJXsVapPAnFsku22N/UIEhnREYNgaUYiFNxfDospiV+UqaZmjnN7JTW4IbdImBYo840oA7xEAUtNBQAaRAIxUiTI4dGWExCahG7p3xX5ths7c1Y8/Rf84tsexPY7tcWyPY3sc2+/csX1i2qYZcs29/aoLo7rccrJO59eX0p3/0GbmFyxuyJJAqVx7Gswo9FtaCBPuqFpYGn3OYEZXiVdpxvpFUe9WNx5jvgqhV7q6UHfngI5CeliQ+r4w40oXrCcR9aTylY8YEiSrWNUcHr96dwBYAL2+qYVrGeI0KlbxRKpr4wmUi9O1k4taqFN/LsY2HKIR/WnB6tL1K2t/WFrYWZtaAjEfFauNGNyj6eDvVSV4UuQxNvSWR6gXvl2nmDsvDYi4lc5VF1mqocBh3fIYLXCGEBZPL0GoZrfhqpGSjLekqjlAq+KERdqh6WZhRRbVChZfcJ0bKnB8NU4ub+7kF1uzKZ2jxfOR6QPAKarBx+hCjYv5yfdcD9mqQ6vFnesC87Wb13jAzFQZs6Tr2lkK4Qic+IlD0tv8TeJi+ADWg8MWEptri11chgrpWWLWBFvJFkv0Vv3h4moOF2uLdQPm6PklYdXsLY2qsc2RdNmurivstVBR5MoG2Q51WuT54/OLxwI/FvixwI8Ffizwr7PAnwiEe+SFPEmpdkC72ifZzOm45CTzxo5beaKHHTtATU9Ud3PL7upbN3tYV109c+ddhrBnd9mxYx9JjptYQPYdLXSZElKRXVBWjb1UfTcBhrMn7she47Xw5pxstcLdJslm04pOxavu8LemAiNzotbdRKqbqahYux542vziYcd8UCSo78owzIj6xkP+Fw9bZ2suwudrh86uEMKaUcMSg/QLrcHVLdwo62A8pmyiBmCqalfPVDep/ICgcEOYdGdQW9wL16/EaRJq6jQPaL660DMPMVz61bO7p2BGXe9TQbR11gnxNzzG/VE5G0Bpl8UOSjJHM1O1tcWJqi1K2xONrDghfapjhmYD0IM7DkNRKepxeuGtVwly2CakeqRmYFHX0iLUNRJrIgxBLcJWrWjyDEGPdl0QTdbzAhYSBaMGKNWNfRBJOB8LdQ1unQcaZHWhby4sunSyTaHCBcEGXOLaGs3YZdda4xkfWdaCbmvQ15oOmLQI6sVIhoSzenLbER2fjQUBfcVJiGbWzy7XsBijF/NsDATvxyRlKovRnaqAtdODctB3rv0c0HyArwcqQpUR3FzceNnMObb+YaBqBgN8VajySrAcp2qFIixLoZaWh7j+1XRZmKuaDQvaEMlm1riH4c4UyWtICOC4WMM2AxsQna+7oOK7bGgtEA5CsaDEm23n4aUhpTsvYMq12hZ5v1OiYNKRM08tuSMZrBxbKIA0rDFNhMvJvHl2dbYlhnx6CTq5oK9FF+GBZbTWFtJhTPQBpCnehvUilmPbxAG17O4bt+x81lUIMfU1CJAn9TUWkNCFYohjpRRpvGJ/QFjSpUjP6vHx2fQTxj1h3BPGSa+eMO4J454w7gnjrJA8YdwTxv1LhHGfWJI7H8NM0xkEi6nX/m6xphmdAt30SEOz7Y63Z6KcSF6O9DAbrjUBMUlvNKPUZvLeyFeVQYogeo/DlkPmB/0qbC52CCGs7Qw72zl6ow9VMjdPMCebNImV/arqV4jjulLaJ36e5QJjCMmjYzJJjNQ/IfCUVGO5slnsu8U09RB7KDWeCLIRiVMymOb7CYH7BCPZRticyr1cz4jOQZPhusj6OTZ1Qs6xqS4J1DnK0SGZLdgpQ22bv4q0HtKCfTEfJxanWO5Ewjw2RJD+ipjauO9GHm+xgGR5m67Mq8F02EivQSSq7gCRlXjLLz3C9Z0PxZpQxrQDTxadfcCzEsACb6Mh6WDgMbghh7QIsk2w2oiX68lW7Mg1zQpzyM9X3A76fn2CKZTEJqeoIDrqGY3FNiKwKKKBnHIQA/WzNCXqn1/4Qq5x0BQEpqMzF+WCIvC+qmwbtujkKFjvPGU3skY1brNoCNtcGpQjcPIpKvEGMYaCxlPjlmHMsotlDJZUGcDRoELdKZjoS2PuuKrms+oGm/CzcesOWfqwW4uvsI9kkM0bKotpzq+tfcWJT1OZzJBoz5le5+yKDIGmFzuQts3lsN0bYDPC5m7nnsh8t8ggOPlrpFpmUgaRS02r5F/6QKuR9YEDo5mZgl0YMG0UUOzyrhjKfnSl5vHuj3d/vPvj3R/v/nj3x7v//r372xP4QzZvcjN26WUKeFZJb1kkeQcrbsL5FOW+ua4Np6Q3cqIu4KasyVeiLqQekFyEIKU0aosbX2S8HM+umxZHXTJabOIuWbR1VVXbvOsipQJXoSFgiQ/WdRn0JAcSd922SGIMWDkyRkdd1E2SFpxdUEAXkM+kF1ELDUOQ5FQfWSr7PLtufUQctUQ3o5hDdCF29LtroegLwQbsujIdNe+CdiHKCnfUJd/YdYMEI6p1xcC6xiV0vSjBFkddrU0bnlk1/dL77YYZYZYeuXQVNS36McAkLQyLSjrq8v8BycIlGnlASrqoqIxWo65dV+cWib+eWdJV+VjxRhxYW7QrEJgoFh/CECXTQYwX3+U0IXoRkZqFvJf9R1YjJJamXLkqdhXVqLloMCCGH5oBXBX1Ss9Q2itQRH5x8M1Auu4ecY0p7uTIMAw6cAZo0xcm40FEWIFkIdFmfth8AzIZ4yHTmUoRILSrkRGdQNoIZd/3laMfnx49tvOxnY/tfGznYzs/GXwmnXWoBfvBhFx8ojtVVRW8bJj0ED5bnvL1wciPpcfklQiBrKJMEhn5wfQ1hYQnV5MeyVejm/S5meOPKEBJVpQO0rr+cPwhY3T8lfQrzfwVKV3M2AdaWjA5h5J0CeQALkOW9IYCbSgLibU+x2kXO3INGHK/JZwzSrpGkpgWT+fUSebUJKx09PaBuoEXZprDNzrXA5VK26cs03mktgc51gzQkmtxVz4rYZ3Z3gGyBGALaca3Xqb2Agg6gWPl4rgI7PJKjwFk1RDZCBX6zsxxOlapcfCitCZq5WIJLRRG5eZvXQUy31e676EOegFEBymVxe2ykAQKHCQVvEpJ1KRzlW4lQ1m3SdBZuXAh6a0bZd2li8IWecU16VMe6sKswuvoe+Nx5WzUtZzY9T4+5JpuFQoasfKEZJkGUqVRd8NiYtaTrtPEArMCiLkfda0q6otOSU2/nOaB3kc8iXR0uPn2AIJRJySHd1JhE4d1UPZr5UbXIvOkNtIZTVTFUQeeOjsh3gmapBBGRBtogb3Oo6b+ywKz+kU+q6WaFJGJjhCLAZgtyFR50V71YLXNdAG80W7qvT464aTLrChWyJ0ubI/aGk1OWhgm6og2SqtCxjYyzSpEUxvgxVxyqoqRxwvkhERHCKhWAwi6soysq7CQm4tnkUoyNhTSK4OqLMhhqCyJeocwZp1oIAWhUZaNnBwSra2Jcl4p6XozI3CkG9X2JF3f1niSDMP6LVwgBGanBF0CswBXIeigfgPxHbocGY0xHtg3Wzm/YfOatjf55slUJO1uKmIZIQuUyI+r0kNAfYEB1PTvJphQxsES68KzCozhAYyz8kDnnegwJ6KkE3VnykI6AAhthhYFTm441FklWmYgGP2UdTNjUQXRjziRv/Rjm3zamfCS7knzZNaJY7HTZ+tMVwVZ3TiEXf00v9j0CB/yiaqekTABhGQVKoMwaKSq7D58QZ+C7uUhwSiijI3TyD4DcO4fztv9BPPbE8w/wbwdqSeY359g/gnm58DmCeatTD/B/BPMO0Y8wfz2BPO/Opj/xPJ83rhFcZmKH0zgGnFwLOupQPUuyJBrgDp9cSW3hGkWP458n6p8VybPMvno72ubroyt0U0qfjA9KwOKrLdwNCr6zsTBE5SmUOmCmmrASKga3Xba0oArN6ohLq+ZICutQt8NBB/BgjcQCv6VCW1NBY06EMBExMgRdZZXIVuBaYjs7NnmagpWhbhTh4I3EAv+dWqIVmCayxyvsLAxz829gaYKIs2J5vKNuvcnc8UcKSqaMnne93thlmKVCki9Kl3euDWqOWUBbciEa4pdvgG6ATo7lVcTAO+MP7w8RNziszxXiTeMWyAW1CMBEVcJCQl7qYkSNQDgsYGMMwI7bEOjMmkW7kpOqsoZ2SM0hzbUZ9VBza7MSQRSFqtbQrZkVUtkQqaeIgOznsf4PtkOFa7IRQiFEomPkUtKXFwXslQr8LLK4yeSnT9W+bHKj1V+rPJjlf9JrfInAuaiSWH01N4MCfuLZj24gWh4UfAeEmtQzKEhD/Ho4NKuj3udf1Vd+8zQmUnfJXAm56pC1cy8rrnimUPEre8iw6nO8qpZgLmmzwC4PkiooSZYjV2yC+PYlyYQ3bgQcREunWsg11S+6JNvClwZiNP8TaXJ0syu8wGzK7MrrNNVeSlc1bsU1gIyi7ZQ9d90qQkLt5oyX4+f6XIQ8swaICULXIVycd/ALCrQtqUm2FJtTZuWaCxQw1Iod/fN5ThYNS5/WGgk00V7lXuG5bKcYKGaJ8LiIZAD2oxT46m/kRa6cW16iIiRCFnLKZ2LaSpG89orcklzuY2yR/mMu2UWAaxnAdIjr9SnzdWk6yEvkxJqKuJ5k6V0/n3xAMeQxz83HlRWACGBKC14qVECxlUbgvHghhVkVaHvTIF8biwOY1TNoi0hBK6yeobRnSDUKP6frWJXcCo7d9fZCqEok2GDDADwpu/je7+P9Xys52M9H+v5WM9PL7Yjyz2XDQipxYxuN6BGCgXzys+8rubcxzChiRNgEeOauFE5vsHBFKWSub+hYmyOi4zHG7I7WGEBmY4SkhMEpBJRNXaS+ErCPGOs5kzQ0CBzkkd9SaTsjG/AmeS5Fw33cNpntGZ3SwzLOJ3jXfWwUcSrVqhNIZJWBfZndK63D+ZdJLzoAB6bPT0+mABIm4gDF/qCAjb5dPCwqydT54oTTHLzw7JUvBKlQr/JnLkPHhfyTwevuNNS1Rwi0RcLirMphJRZSkU9Dh5v4JUhSI5acLyfoP66Jpp98ekcJ/0mut3+ajaBVV92Z+Wr2X/WgQMgXqmaTeAwF1I/sPNohFjk6jeTV8DsPyc3uOYbOBgFwM4I0Qek6oFTAOOxDgNQjOaTAhYowk4fES2QBWK/A65CpblvFqBtbpw8VM0xIDWGkAgaw9nv12y6k3kYQdaqoATw3ua4j9q4NnlIazxV0zP3i2O3NenKqXloBFqBpqqR8Ybo47H844geR/Q4oscRPY7ocUS/2BF9YlrUAm2K7DsQEj1ugVe39bG3ecvp5Uvb3F5w27idNGReMwcZy905I9Vv9tnMNJ6WU+1q9CODoTgnLntiFtChNlCYC8keXTUH0Ctqci7MADk7QNcRDBSD++Yy5LYmtewG2qprngI4WrihTxg6/SZ4KmGpybTMHFIfbywaQM7lE1I/2dw9fjYVu4vVnDYfPscM9PAnnT5bfI6VoAui2AmVFhgwaJruQIc3RDO445XN72FfhebNWFIRxjWzPy0rFS3wNoK2Bi78as35xiHDs7Y5Ba2dcUIUAPZcVjbASziKxvWvYZpx5rqamuD8NAt64C+osxpzsJGWDZ3TesEAXUsEi9QtXynS0X7Nfx944lefs6xs3Q0ku/GnWJouht0xAQ2ukDBY3iHq3R0Yp7nZNAJo5mRCFhuFaHgM4cbVJ3GxzR95sBZzpG73JvTjc4LHCj9W+LHCjxV+rPCvtcKfCYirO6v240szZ+z03Y3KZRN9xaIyrh8GuzLyHy9OVF5HUGZUclDfmQGgTz3NwFwoZ1doqJJWzWxcTQ+BKXQHpLYUisV9swD7VPULecPWmL/1tBr3lw/2YiGLr7hgh7mv0Hg55y1AzYWHLDA0ygNzoWFjstvvPoA2KeoLZUTVGb0ywDztvgrN0AFg+q7AvtY034eygLYXAPs0QxZQzmxt4d5sGt8Eep77ZEYzUSCyQkZ6I0ViyEhkOjeVqchLn0PuboDsRT7yzpd+s7fXANYUimsNAG0vANXI6NzMHQCrp7pvoJBtF3RxFpzhwiEkxNii6MyleRZIF5RJmgD2mSvYhf3aOnVCt14JIPyxUOjum5nHjM4WCCNlgLwvhUpy3yxALUuhObg6BQ8tS0tgZqVXn31SGefReAv1SXn0lt8CGG1CQP9TYC40RMIAsVsLwRPBlBENx26ANAVsxoCZb3AQYAGys6+mNQC0vQDYpxmywBbvAFuILH8dULXMyykF+B+e+D/dE0SiUiTUk+7JyZSH4BQNkLzIV04lZhd9B9D9zrMYCwxtqy5mtoU0VDJAi3eAeT0Sul/dvc0lLvrELPcJrZ7Q6gmtntDqCa2e0OoJrV4BntBq/uZ/09DqE0tXeLlXb3T9OJ8mFf+KS14W0peV9YXfG4g3zVDwHpLbYWjEDcRGfPhN+39NXfvE0J3PK+GyhsTGfIOGDsl8h+j4xLp+N95K25CcD883pcVJElNPOiHyMJJHXDm8Kjc7e7aAMcOK8QkpIji3YcpFXpDAVytSpha8GF6xVZH3M4DMK9bXI1Y2xOL7VYyYJ0we7noTwaNiHpuQyxqsiCs3nk+yiLxq5fM42cfUNOq9Onf74+V6jgypoeQDfanLImWpRfMMsS0GkfYaBL3y2ITUcIu4cng27Q2kZ9c/O7obhSQTS9MskG+RUXA2XgaCwBlMxFLzCymCx8go371ziqnfLEDd57p65xTzgixwtdkC+ta7gXpw3/SpJpoJC4Vsu6CxNLnDYJqSY42XyaSUiG2TNyR5An4bEO1WyALX+BOA97ZQ6O6bmc8MLjAWCt0B8z7mi+3UTnFZkX1by8Xdf5WmOIUCy9B6Emy8hWjygdUbrM/qpfHgiliF07jyPYgrJ6JiEDwGOOdxnYQn6iN3gTvg+pqkjbGNs+QHPEGxIsszlWyQQaTRBkHXPDYhW7xFpnIYgjcRON19Ht1ISQmMA7ysRMoK/F1pXupwcNx8tSJ99+WSS4Nq4o47xMQBmKMiDtinqcOEiP4aTMLvCWnxFrFxh1oL05ugjsfHXx9f3nxiuCeGe2K4J4Z7YrgnhntiuCeGe2K430MM96nFuE57hkDO5BqHLTTPIyCQ69zmEJnq7orbioyntttkxidEAjmPuHLuiW76uc7AyjztPR+EvUdSWsvBi+Ir7zH7jV/t9KLSqkY3CmTefR8vmWPnDv6+MqLpxBD3iBi9iSAO8diEiGB5xJWT6Mi0SiIoj7wYOWI0VhnlAEnTBcJRbsZOBO+rAgk39W3JtwoIWg7E9G/GJgScmhFXDlx/A+nZ9c+Oc6aE5NewE2luQpCXWOvEipPS7A5lrMgoF4v/ak+vIqa+4KLNPDV61uJsFd8UdYg1GP7aIJvPoM5cPowcWMwiYcj8yzTfDcNoX3E13CC4tVzJsDCFelfnaNzz7A+ydRj+uZ4JMZzdncvK9LVA/Dbhipku7l5y5nJtqW9Oez8hoa8SDZdvXo6pN1if9YpRiEespjF6+TniyomYGCSqrs+P1Yxyc/5fI0oGSdPOtrV49isfGhoke8tsWzVfg5kQ078Zm5At3iJTOTMObyDQXeOhMM7+utHAvNT0ZULRbyYUHqMPtsic5dl6ePtVWeqbr+jbiMK2s02zrgmBKgNDaGeQ5iIfE9oZrM5xBw2Nj8g+szz3RHVPVPdEdU9U90R1T1T3RHVPVPdEdb/HqO4zC3Yh0appaBci90/VIvI7hnYHhq2QIVjBvPYxBGtBjg6GzJBpiJFFRmi3IK5cnuuDU7GIDmDIbhuKLX8debn6N+9Ench8hYV8Ma5uwU4EjhTI/Cbjy8X3+UXE7xeGoKbfYEOMQmQwtCLqiRZsQoZgLYgrNwIk24IRREFmTKhlsaD1IdARxL9CcpbbeZMFX80XWSYE9e283SKt2nmXRVpuEPTPYxNSwy3i6hOuv4loaIc+23EOlJBMbJaRCRE5CmuoFQLjJZHSYH9okgAr6h47kVo8Upaq8LwSGmQQabRBoMoG68F/1ef6rOnYuK8qJieY+A7cMPEdJMVas8A4LRFDnCZSYLIpAEEW6krW4VpLnbsCM0+E7sFiofuvHMuNG2MbdrJ8vk+yIpdU2A+CiyMNS2wRH0daREWLUWQgy5uP9KAIJtKzWA+TuiAyWRCrsIho3oG4ciIwhnrsHsnBi5DGZ2F391CMUjPSo0HHV/4lMJpSW5/B4myW2XKDBDqQGZuQLd4iUzmMg7kMtSLQYmPIMM6JEhIYKKQ2S03yM40FGY607v4rN/dYkBcbmOwMC1xkGczTaiZQmDGGHFRSg0CVM0929Dx/BRMA2oz0LFbnMIQmxwdon1i/e4K8J8ibwpsnyHuCvCfIe4K8J8h7grzXkCfIc6r8zx3kfWY5bzc0ziCv8b6EmsXdWM7rJ9NADnE6kDLHdwfiz0UTgym3yIjvFsSVy9mXG8OGFhjntWAn4var0Je5nNudukXmvamXwSb6u+6ygUwIQrvGrW64fPMybr/BRG7eROCEPDYhIkkeceUkQDKIBFHtJtRqDGuC1rciPoHMicXdf7VvHtmW+vSpX7bKINJyg6B/HpsQ4ZRHXDnh+ptIz65/dpzrHNX5jEInMuePWZGXq9ycQeZEEDIBScvsp/AKEr5akXBT35Z8q+ZnDCcETsFgPfiv+lyfDe0KN1tDnnrD+K4w/IsUYcwwEd8VxmmJWHbxHegbxGeZYetppA0iolC4LwmnYLDQ/VeO79Z5FTpa8H1F0uIsC6NHfFXS28iL5ZX5qjl3Xef4zkg5/L55jLveYH3WNcYjHrHaxzjm54grJwJjkKhWcFviLYgQojL00CA+BY3xoeYrHyk2RorZW2vbKiDScoOEvJYL2X+1LfVt0ZfDOLyJQJWN18I4d4oL4rvuBWa38gQfaqQOntZ+tSLRawc8u/3KhZKMSXbr62dsQoZ+WkS1mJiGdhZp8RaxMQmsBnuj1sZGZJ9YunsCuiegewK6J6B7AronoHsCuiegewK631tA96llukyrpqHdnnh5AqFd5lFKxHeZt90lvivuNPSKnH0rjJIkvjOIxHceceVy9uVk7IrbjLrK2YBs+pHXvakDcztRB+I8p0UgWdnvTR0IvCmQOWPLWS5yW1td/jECCHP6DSZy8yai/mfBJkQkySOu3AiQLDKCqAPZp2DvxUgPAjL00CLNh3YLdiJ190hZ6ot800ZaZRBpuUHQP49NSA23iCsnXH8T6dn1z47z7nYvBwapESnffVafA1nirQNzOXxukLBm9Tmwtvmv5ktJE4L6Ai8lSasMIi03CLTYYD34r/pcn7UaBgt56g3iO3DKxHeQImvNdsZpiRiiMpGH4LMTsA2M79B6WmqDiDwE7jzCMxgsdP+V47v1YB7jCFpkyRKxYKbHu5crW2730SMklO00SOirvKvzh16YIM9ifdY6BCULYvUQwcw7EFdOpMYgUS1B8UEX5UhDs1uk+SCP3hRfJR8uWiR7u81WGURabhD0z2MTssVbZCqHcXgTgT4b/4VxzpSZwGjBS032Mw74VSt/HqOHtshyAOF09Pyg+AMIFmGg4B4kmxBRUoNAlQvPd/Q5MKEJKDzvgSCv+AtZ7AhMjg/QPrN09wR5/usnyHuCvCfIexV5gjxjlZ8g7wnyniDvCfL+mYO8zyznxUD7hkivc9NVbSO/Y6R3YNguGTIVgzsSvSIvV7k6W3aLjEhvQVy5nH25MYCoz/iyGPy2FVr+OjLKuW2rA3GJkMEX4wMXLMSNHhZIm/z5y8V3JH1ALNAZ7XRiiIlEjN5E4JM8NiEiWB5x5SRyMq2S6MojL0aOGKl1RkBA4hQFjnLIh4yvViSs9dkGNZ/UxSLomscmRJnkuDixef3ROZxxCeErBSG/hp1Ic1OEehNqVZ/k50DmJD8rMsrF3X+1bx7ZbupzaX8OS+USuFjETNC6C+QMJYfY0K5ynzXkqTcM7SrDv0hxxeQSoV1liJaIISCTsVfOWGSfdlUsH2iftYfWrvcltDNY6HOvd89367KqTxrBdr6KjHIp+a9cGgnyZSrnA0eDoJ0IGwP5jsstcPl9juq6DRu6jT3MD1EyRiqqkq8jVpUZB3UbJkEqTDBlsKJm06Uephab4K0zEMRXPugziKkPWJzNrWk0kUBLMmMTssVbZCpHnt8gdQnejOXSkYTDMsEb3BrkgmHCToc8I8NBumzDcLUWWU4cwJHbr1YEgaFx5LX4ds6byhOiGktMIziLNBfgMIKzWJ3DC1iWJfD6xDLdE7w9wdsTvD3B2xO8PcHbE7w9wdsTvP1LBm+fWn4r6+thMc/BW+G9CQRvxT8cFitDPAne6nrkGRiDt8owSYI3j4xy7uEwS0nGrrp9pVHO7TWh5RZpS/DmsRNxu0/giw3ein8m7BaJk8c+y6X1famYGbb0G0wk6E1Evc6CTYjIlEdcuREHWWTESjGvwZTFgtRnfySGSRq3HZh7MOxAXHrjA8lLVR47kTRf8bAIuuaxCanhFnHlhOFvIj27/tkhNq/KZWKzeJzIPgd0C/JylXNJfOLuk/gcSFtUxGMn4pL4HEhZ6tt9yh6LSMsNAlU2WA/+qz7XZ03Hzg3TkKfeIKADX0xABymyJi0yMNOADtyikQV9g+DccyX/3Lln9IdmfudmItyDwUL3Xzm+Wze20+WC7yuy5Hxg/3ZKkcv5QL7sVq5cABnNC1LSTvN+VOirvCMMSHS49Qbrs9YhPFkQq4cIa96BuHIiNWiBBlYWycHLkQZp7KFB5rfGXsSb4oPsY0bYU1uVwWL3X0mjDYKueWxCtqU+sNJkwe6zd7hFoMrGa2GIC4UjMFrwAlP87IJRxm69qTtTAL/8OvJio5PdxwYWWZ4XWzDGHVRSg0CVK89t9Dk6oQnwiI1OaDqKP9uxBGifWaZ7grwnyHuCvCfIe4K8J8h7grwnyHuCvKmdv88g71PLeY3W8hp4ix2WV7rXePI9DUHDS1x1DPLZcLzhVYfQhpNoEmQI6IGIDxTkKJeQKhVfIQcrKCGbax1+8iwX/IbfyTH1+tUhDKuAwWeA0oEMBUyBa9KtolzQYRgxRTL5TEdMkUym0pjRPwyyRB6dAyrRSeeAIvbBSyvShhPBvtXgyzJ+pyBMrWgyqslkaG1x4g3E6pRU34pT6veZN7t/ZQ6I5fLO3CYyFrvPY3I2RcdZLaMdaZWG68ewVFaAYKnwxJx+BUaByNkKFVgd0DM21CYm/Sq4IKdxew+WuLkzsCcyP6NtBsZYcAxo4rB3RWQIkIw2ISil4CUOlAQFSVrOwUwIgjmccSjpOQQ4xF116DbvnCw2PI1FoKJLcokF4wDD01DV6GnYG/NVXCgtD6NTpKM3HGx5WD2pxaDubyD1pr6a/VdtaYExHMBkHIAkqgLGGKoXjKjQ1hikJD/ksDVGxEqbqop9zdNBy4Igwb8iNdmatVwg9ThZwMm2pYpysIBVfYVzjosV+8xKxuPfHv/2+LfHvz3+7fFv/xr822cmcSnrbFeYMrCUZnZmskDGMvGAEJyVySxf9KvoGp7cUcNRDtkjUc5dJ0Z9ZqEWrVITyZYfiMi49k+Rsxwy9OErZP8DpcIFZdRXuQYtraq8fC8tV8T2ry7upfLmnZQr7kzYaGdxGoRcdWZk5vEbTs70WkOXhMd44C/wNA74kBhcaOhyKrQGOCKO0b8qAsT2OlJEu35VZ0+A+qwFQo5908ddkTyPqvUEyNqHr6olUmkkUVXlOudYlEqVXl4aXV1uglGuFz/sPrrS+iwr6yxzyY2HH7VPBK2PPj/6/Ojz71ifP+Okc+C7wjpnySZXwxDCvHOABsMOBHMwFfocGbSPQO1AoMIjVARi5izEVFlACfukR31VeaS8zbub1Z696fvEqAPZ/cQlbxRm+WqjMEvg21kfZKCzvqpfuZfPLAJxM1jVr+bX3gzSsVTP+nRF4ECgTkBw+SewPuTdGV/lmx9aS97I69EWi7ToEd1LtJjIhEHG9CiPH5iSd2cpJwQMxLIElMFgIljWANvRy2Ed46itw6wX0rJP8vNy6QNWU1aZGrP/jPwwnNRSFo3E5lnPs8lHo9s/1Cw9imIR1Ie8K6Y+6KjUZ7KnjBnAgcxzgsEXWK2oo113j6RFtzc6pjFQGG2sk2CYzKQdEqvY9wvDDEp3tA+N328wbEDqbnief0L8za4eG2Y65DK4Zp/l1bGmzcbDIrO5/EQc9Zjcx+Q+JvcxuY/J/bzJ/VSom/koLeyuwaThmTO+sWqYkXrQ2MFM9RBZL9QIkeLCtW/IenXyfyLFUaqUftTXKP/SqkZ7Ji03iJ7aIAZT1PxbENlctO0B7XSXTI/eYBlSdKRw/godMUkrxVL41JYnkvyBuQPDCdkxTeLI6J7AMn7X/DWbq8qXLf0xY2IVG2ftnn/cBLGcx+hE593MqKL1SIuJr4zM7NofjCDqSxx7aVXyDxlbpLGcu+JMSnoy+UDmU8+WyxzD7Gbj0wiqM8gmS5ZYvsxl4zSPF9X0bAPOO211aifONllEz2oR0x0GUoqUK7ydatoJKyfcK34PB+Nn1gMwyvyqctXAaZetr/ljdgeCY3Z7nRHTP4MJFxovbG5azi/DmzaA69VvaVrNRTsrZaG63kArm/OKtp2UqsY4RyTP659qZZh6/cNiutkBW6QLLYbv3MfJuLCtWymwoliysaMK/1no3yC12MwJKv/zutmQorTNrTKyBm2e380d5YDBhqX5ynjO7jKttR7YlDkQuEqMM9wi+lfpGONsyel0jXwYKdoWWQuLPAYntR+f5zz+9vG3j799/O3jbx9/+/jbj/tbmeRyXns2chv+9w9jyeIqcs2ht/g1n4mBjwpiOv3v7Kf/w3+M9eu//x/vIdjSuyn9uz+C2N/+n3+M+9f+7SDwx98QC7R8DFfvvR0k09X7o29f/zjRlOn7f/k3W4p/+rf/9esf/68v/8cf30e+pw+Q338rf/kY+bDFD9BPKfw20VfiY51K+Tyk7/gVwnme6aB+3jbcLoEN+y2/mx+5sXp7Q3HsJG7hongGIKHeUuzvHsEzs/nJgl7fNYR/2usHeXw19L3045+3//ZR+uOs1La/q/219o/RP9NCpaGIIf9UROpvL7ciMpbilgGNw1GexK9heG0807bqtpC4CPav5SSxX94o3Cp1CquQ3bapjEXPn7dpf6fUlgw1eJtgfC/Bkd9pSz8jmDzBsRKtBIctP37VfDEv5NBru6WU38m8ei5oi7D/Eua1cYjzsv5vEizvbGEbJwt+TnBxJ6+1sL9veGmTfjIaPVGh3xyU9qqRO2ndK3HqWZXkVSUuf8mv2PnW2N6kqhsrFGbbrkhlv2/vwoBXCKaRNeu08r+I4LhmenL0FxGsV9j16wjmcXL3FxI8Zx7Ds/8ighVh2AcJxkEpa5RQxobH1dfwRhiWF6M/N40Ej8nj2dnyM4KrC/CUGnT5bUqL+Rr7d0vT6hHOX+PwM4LxM7rcyjXJ2Prrupz/8pN4wpOPWUX7HeRD+HP4GPnz4Fu/GPIO8vt/i+HWEvnIXnifA1lzVHx6onLL7fRubudzJv7u9u5/bh9jB4ON9wzmS4kfJN/VCrxnMI+p2ke4Xasqyy/jdj3XEN/b3u1Pf375GDuOZkow8S52/OmD3O5Z3cx7Wt/LByeDCBDSeRp2GOBXG/+nbfvgPKJ8gHwO208EfZlG5A+Q3/pvH5wFnekfxKz8nPwxj/1g643Vegfva/ztY+TPk0gfaX35GPnDyLyf/La/fJA5ddOI+l2t7x9sfe0wke/h/ZY/Rr61j5Av4c8fXMGpHyCfSto/uoJTPkA/7n/6YPPDMedXi/xPoVjnm2Dvp5+3l5+svoTN2eRwBIepXsFh7O1n6xch7T8ZgLWCWr5dAUJ6TwV5+5nPWis4vdZRQ6vvqSD+5qzDEdQejvpal92DrML+Qdbm/+EvX/7z33z9719eOWZ0frpse5709rG2/ePLHuTJOmDfsYtaUhtbAb+q2nORvbtqFTPVbnp27DB71+r8P67a3IdYXjsOunOgGKvNtcki/S+qtibkAES1FQfZUO25TRZ/YbXnkcboqlXMVLvJYc9fVe2WVKRYrWKsNjXZ6flFIpUq9nghUsBY7ftJovFGWIEtlLEOJKsJo5Y/7EHj7fE24rbhcO25cfLjiqmXBbnDUHdDhD9BJPV+7eKETYksa2bnYURZrL6opJFvbDsCrGs/7OpF0tBWqCwLZe+gUs5b+5gNn1SWZYNj2jB6UvZLzPYrhllLlmWZoB3BYLgs8kWgjKD/qFSX7M4+9DMcvZ2Ll4W3bdNVzYvg2Fs9h0XHLZViWLsQXPh8Hgke8zJPUBY40rkB+epadlnXJoOu01wEMVUoWEs8KcZzs+d21aasWzDbtzhWLl7r8+GvX9/TKRjP0zm0oclU25gkVdhPFLffnXQ17mYPcpTgDzHKJv9B8VSv/x/L3PZaCmVuZHN0cmVhbQplbmRvYmoKNzggMCBvYmoNCjw8L0xlbmd0aCA1Mzg4L0ZpbHRlci9GbGF0ZURlY29kZT4+c3RyZWFtCnic7V3LjiW5jd3nV+TaQKX1lmI/gOGFF55ezAckpl2LTA/sWczvOxTiISlRWfnoGsMwAo3urnsqREoUXxIVir89uMe/nP/2f/7zDw+//8Mv7fEv//vgnmJxj//34K+/GP99fn3wR3xqzrnHcuSnegT/2LH01NqFpad8hPPx8y/LeOp8vBJy/n8gJZ7I80PHWiIsoh0jPq+IM+3C6MOElIVfeErxfGa0o16Fp+jpqdQI8ccWGe1CWp/yE/UTuX4cnpqwSGi4HUluFtL5V41EeXX6eSPel4fvJ+qewkCPp0OE7ovGXi6s9I5W555Sp/jyoAZ0PNVMmHs6gsUy6F09ftnwRW+oj/7p6K17b/zg3LE2xhsgIv9UPSEhaaSPN3Q9W9pRf4m6QsKTq9yOsCKjP3U2LFg7oBgTRm3rU8Toeb4UltG3OvrWsQKJKL6nZpq+MEZjXbAwlCZASd1oqaTmxsyMsbIk/ZDkSRRSS0Pd1ZywbNd5wuzR3CsD9hh9HobxcmEJmugq60OBVl+9U/KF4bVDJvPsRGsgzZ3ojdgXuEjdT4mMI2ZC5m4+986f1AJEfSnpq8bgRQTxZGqCkKB7zyoG41jhBYPyCcJDrmK2MPcTCzBualdWD9iyuAR4shOjiYxPgYQsLeEohHohryh9qIPfs25XRdIFqiMqLDzb8GbTuHfYAbkS0t1LzDPi2VuesmYnlEGL5M8tX/S8KZ6sLQo7YIZtqNhQRNfWsTK9HVbGLEw8ylP2pMQBTiKQEot78ZDvAfnSvCs9zqz8gmRpx9iIFRqJoMS0WY7cBzJAJQnWshUZ7UJan/JhoSTdmYyUh9bgz4sxqoIA/v3hl4c/P/yNkoe/9yxCJRB38nAnD3fycCcPd/JwJw938nAnDyZ5+PV3V/bAwai6QI6sDIP+5smJ/v2/H/7rd49//dRORTi1ioZC3nDCyMl0hIRAwXhCyHkojE3hlImowtXtjvAohyr0cGii9IFYyVG6t6R4TPLpCMmwDkPofaCJaFCPjnF8LhjPpR5sLB1pMKkD7cLw7irWdyzhuSvCDIxjONM/EOn9RL/3i+WV4YCbjPG0GOQN8SCeVcwzZ8IS1HmHFeQcnUcuK1YgR47EJw+x1oWUxZI0ywiACiuY4AQv0YdA05JGgF3oWcxL2/LkksUKgmIWHpzWVNDjidhhDsmENYMeyM/eiHxfdUMlc8aUfJP9yS2+z20u4U60lSCT/ammY6Wy0Cahvs5CODSx5aeahpXKoB2HbrKNvF5YLRSeXJ0nke2mI0ch5KLHCOfHzw8TlvEUWQ1ZQ0cq7CNUbldgf2RtSSzexS0y2sWyPhWSpj4h2XM7jz608VQcXk75k1VWV3LV3VTQkumZYZPeN/hDN6cFGkGwFKxRROl/mMJ4R9jrIFh2ZwOvQwurJr4kgtKMjHaprU+xX2JKjJCX6xhLkBacFTGB5n6SS0Q/V1m9kAQ94oKDBCucAYKvcGCEeyHhX0aUseg8JA2smSJMcm7RU446hxi5g5NqQqtMka8jvHqys5hFqg3JBa1imyzQW+W+r8v4JuuEbBBn2vGakfWBVzpNHGkWWXFOwL1aV5/tUa9LZBJ4mckIr/IVwoqmsGzalboiomizNDwWQNmvSM3rqCLmqElqF6DTHLoSS1FPD6tfwgKblTRpacyK+/LpnaE7WbuTtTtZu5O1O1m7k7U7WbuTtTtZ+6cma7QT96mDQK0RoVaH15owLzvSjDmqt2nEY3twIPXgmT7Jjl39E+NdX2BnS9r7ZMRTNUAjqBUKVqWQw1iTnXJCDvRLIZje/nggDOUOGVHTu8csHyWLkrTMrr3UViAYbL723XiaYt7IPTHeAB5O8USWDeATcdKOsEzaoJGKdkQ7i9ixKXxiad44PpGILWHqZ2Y3aTDZOFaUpDt647gXGqAHJNtCJme0bFRyCnkPCOr1wkbUEWqMsAgUgkKXxqibChm2J/ySVIAUVlG1GR7sRAr4kcgTonbHSJwJFYQdEpJtN2NSn1HI3ARFI+nQDxG4I41R+anI2BVfks/o3axKauwFdQOWj1LvdSZHdPXQg4rMVGENHtGLJVJ0RdlR2SsXe5W9clFU2atgFXlsr0y4ZDHiIb6EK/onRqul/lydNHfC0ogPunisMZTdMSmjeDyidosjz3rRY1MYCsUtrEcF4BE7zwCEMwDuh0O4w4kH9rZcwIbnflZF7dNPH9L/MmFyCuJEKk5PDJnBv48DDAV9SHOR++wpZaU4CIAxX3M8iwDnCc5GlNg5CRzsapJb2HOV6sT4BASKhSIWD6UIUlEnlVBdwukH1S8u3QFTvlUhHs+okFPSqiLMc8IyHAKlEV4cKpsIm1ao3FcaowpV3NfK9KW3yhxWUx0GrIwpID1mDA5akAxJBhnQszqmMtuLiauG3ed3oO585s5n7nzmzmfufObOZ+585s5n/vXymS9s0lz76bBh/CyyQZ6hnjusSuEn6Z9jd78hOFbZ3efYEEAsyqRaLOtSyEwP+/wJ1nlZz6vGPHbGGQmy583qW7A3HzCsIBU6tsRlj1W8iFQJJQNUIw3Dc3fqGWrvB/VANbVz5LzP7yWeusi02GAK6DvjVaV+CUlKhfFE4rEivEfsJcpS3dNLYsOSiMg06FCfVF60arBcd5hSF9QhNcYzXKW3qa2IX0xZyaLKHjdLe4c1VHaC5MOkF9yvhmypY+QqKHKqnh6YS57vQ8unIlZn0weK3106LmmOHeHMmlLUCUt1fYp1mpGAPkTxHDS3UeI7VYSodsyyemZzlrogJqJBIZIMzgNhobBJsac4tPdgoZM4M8J8QxE/i8hZBEy/waRQTJPBJfHWPBTlrVRZmYXOhcQiC5UsWFiihMJoDTMhJAtGsvSf+5F1TZoxdnTJ/kyau4OxKixPRq2r2NpBFBgKx2eFBcheISTnIrnFgQMBzNPjIEERN0jGikMDcIyTFLgdz76HQrJuUbYxZp8xPszAmhRg0Kjxa+QwtFZMSVWN2UMKEZqkMDJChZAuFwnfUryd/XnSgSjpOJUeecvgeRPcRp6B4yYISq8X1hCWqBztlnRXuUmHjE05esr0lLOjBHjqRTSzwU+xBBmpkkrz8Za6pNd0nAMpqigfsugJUabE+yTsjmKZEapqc/atIzwwiWEnwueHEgTgJMLwOoH66UQoGeJlAXBCfIiy8/kh3qmhWt8h6p+lXcB00uoF9XIYl9S9sQuka4RnH1BVF1lLJVKGJrU+DOTlwmZNkWK5Zn9MWjjYz9sKL+rIwIxxepHmGinvpKCkrvdbpK9Z3nlqJi1UIi14yUNNT+aXRsSSMnyKta5hcyisItq96lGoRXaTqOgw4XNCoXrXpGR9SGpC42fVaVgnHBLHuLR+LLFtQkh1DkmFlIKlKdVSvaqiqnFJtdRo1FO8juLi9VHWfjaJ3RFFb84oGlR8lvHnXx691zL3WuZey9xrGSWrey1zr2Um13WvZe61jCD3WuZey9xrmXst889Yy1BxBuuXUQV2Y23zLV6qdf7ypTvk4zjKY44jjkXfFzfzIuiPf/Ll8T/+5wcUw6WGK8VRmE1xS7H+mOK2j2mcmA5lS7G9R/EoluI40O7TluLxBYrZX1rtw47iOTtfoJgvfXDHlqL/AsXS3dypgnVLMXyF4qgwOvcVOW61pxw/kOOXtKdeR9dd3mvPOxq+pzheMUntoxT7NG4pXn88KZ4ZZvfsadvHEL8wM6efeNsK39eezaj7mYFz1PHnyfEYXjHurZDt+qNbM+WxuAM5Ho6YOX4pBcjpTej1wrL8kGe/P+C8gFDEOS95CogQQSuLaNoeF0YJcZ/1I/2XkODHN9BEFnmIIougpGgDUtTQcANpBuffKNoBa3N5hCEh1NvMvzTFXz+391Yoi1SdqBQpVScAKbZouIGmAR60chMGZ3z0yygZUtTQcANpBjFTWqUY4IiXYgBIqHHDDTQxOIxqRRw5UQwAKWqHUTJDqzNIOJgiDBJu3pLnGBJq3HADfV0lzkB+rN2ptJRT3QGkeKPhBtLdyc7MWPbGEzAk1LjhBpoYxKW7J4NklJohRS2aQRlaF4NiZizXiXadaBQzT4ZCJ3smE20RTIlGlRlSjtaZoRhan1eEnoksin9CqwUypHhnY82G1jXeZpxPOUy3GVLUmnE+hlZnUL1xPjWZjjAk1LjhBpoYVKPKJ7R2hCFFrRpVNrQ6g+aN82nYLJXnGBJq3HADfV0lWlrs9IKOhSpDincy1mxoXeNtxvn089qLCTCkqDXjfAytKwnxtFpUWUiiBatKQwCprAMNN9DEYE2TXju0doQhRc1mU4bWlZM4t/T3TEp6VWKZBcFUDsJtd9jX9cL3Hfy09qmYbEYwzT8YA7f0xsix4aG4eGfSKsE0RbTdYRMXv2ZhnUuaGaSJjrdJmqUyaJclsHfah/EYgmmKxWQAlt5IhoMJgB1b/ZdgOg0OxrYsvS9oSEjGLnwoxncIpvknYxqW3hh5swl7sAsGwTTFZrXG0Lu4xGiciI/JRHTBFEVuu8NmLjivrrnYRYRgmiLa7rCJS1pTr5NLSsYuBFMUk83RLL0v6ErKJgr4ZFcXgmn+2XhWS2+MvNlZTHaJIZim2OwsGnoXlzNDNT7ro1y47Q77d+Xy67TnMZJdR3sevAMyjP9qOi6nCdsdjxNd9lCGxzP06D5S598jmFeCvA0zEwyjfvx+D80uT5x2eZjguTbtPtjF9wiaDb04bZaJCMdV6O8P2ewGv0EwjwLc+wTNJiZvt80ES/nYpESzF/yGDGu5Mp33J8XI8A21aWNjpFdNP602W70+6gd7aBT7DYJnjvPTSPl27XNR53rVJmx30qPZC31DY3p47QHyffltVGbfxziqQS58YdRbQ+7OLPTd1ePDlvzhzTfvRw6TGt81pLDC949Xir17jK97sfTGFiOj1y1KC5fGL30JxT2W4sqFMc3luPz7zKW/irj2e4tR25cNvYVLtWPpdb9jpbjDqh2LYIpLds6MJbvrgMZEcY85MxaFfXqjVmjQy9QTVvkec+G/wwofejD0lpEfeF9ZMB+4zMwUdxjavmzozVx8tmPxfLGd4rLDsh2LYBMX2dtmLDgcuxKKO8xzZmLpzVzORZKLK5fAb9kKlz3mFo1U2Nd1JVS+W1Cwxm/5Cv8dVvnMoKE3jzzSIQ3NJQY+bMEUt5jjg2CG3sIl4QVNhWX+foFQ3GFyVM3QW7hUfEFiwvD+tFDcY2WdRcE0lxSMv8/nAquu2rfFgvH3Cvu6riS5K1JjZpRvYHmdxaRvjRSU7iDUXLLH4TKhuMPQ9mVDb+bSd+3pLLZg2frDLRb5eJ+ht3Bpm7EcfJBHKO6wZscimOZSovWRJdl+b7FofaRgX9eVUmx0KNX6kC1WbHQoZRcdqucbRjWWV+/5BubXkQs2cYn85oFg1UaCLRb57LihN3Npzo6lOesP38DMWASbuMRxuOl1xow/fAOLq78X7Ou6cuaixqM2uSlH+O+wbD2qYHrkh7fR4Ygmj91j3kYHwSYu8iaJYPJ2v1DcYXKi2tCbuJR+h+0yi8UFOUfAu3M7zPFha0Nv4cIfelJY4dsLhOIOkzuzDb3foCvFVb73lzHvjHVvMcff97H05pH7YCy+Y6v3fAtbLV5hE5eyGUszud8eK3YsgmkuwZnoUII32fIecyY6KGziQjnVxKUZT7XHOB+z9H6LrpxZ4mrxHTOjfANbLV5heuQxmAy6xGQiwR4LJoNW2PeZopHvh7kkK1/B/r24QFdypYXe6W++BXph4J1vSaW2O+MwSuL91CUljMcoPzHyIkjkwwZoZZEsiWIexZ9cAoIyPxXgvhQlpLtljEZD+crucJENXYmkuHuq4G4hOVmekYEJxLT4nLqPo27Zn4KPVbQMJBlexlgEohuoOoQ1Q5SGCJHuB1DjRIWqVxqii5n6CdfDLxwPDIhOfimkIlPjL/y1cfSiI+Tx6QawnjNShMZUoRV9L6/TvSyazo71/tEtzmkcC+zjujx8RE/oDcYABZFXtEbdpCPkR8dOtkxQGic9WMisZHzUPQvVNj2Rlhb8WlE/mkljo0y6mwHn0ZSVHZAIycjTXUwdGCf4HWbo4AuhHBJ8ekNBJhY3F9IHHVmMZyNPSnkSHncPKiBOjTAXz6IxFd/MRG8qfVZzHWMfN5tfg89iY2ctY4S1s4iir0gTX1UWc3jVlNxCOxuHYJEq+0F0TDYXzytQaI6HBkcYB2eyrH8e+kjc6b2fhMni94AadMXD+9Ath/3g+2VysKVCeQOsLfO7Upks8lzdXnE4kdpk2nNCz3Pl91YFIYtNNJcncq0TocMnjWtsdINf/02vB1ayE/SjwVrpRTYlwTj6CSTTm1mH0Lx48O/C31SEdqPrLwqi0QlAyxsxCXnbysGoWczeQ/J4dYqOJwudCJmQXJ+78xuTc0Ljkno4SMiNnagI29NtfR0al3sWsiQeAh31ZLLPDxpC8ppJm05ovIZDVwjytoaPMid4oYqO+XSokam3RuMel9h5KJyIC8yVuDg4cGSVcMQWoUVvoMCrT/ZIQVwAKQtvnTBCb12q30krCzh9/laEOzO5M5M7M7kzkzszuTOTOzO5M5P/z8zkxxfQbjdOsOnCItMQ6XrwIvhx04YXzSXdDl4KYnQFBclZAWxSaOREnegVc5IMWAug7mwWiC5aQFx0uAlnUe2L0zzr3F8FkEClEcbNhJWwxq0Pq/T6LIQAVYlcHQ6iPaMhk8b1HV7m1zN79q90KQ1cjAAJjfieHggj4EYEUTa6NgBAlCu1BaI7KGATETfTLDFeixSXRLFIBaAxSaMguecgrIQ1WK/S+8JFZLdO3zr9L6/T7KxLf2Ns0Kbc5xtlRe/shPdHjfJ3ekHOM1B2z9gL21JJpLM/i21KuNFE2AJTbB2y+0KR+LexzYd8keNMMMbK8uBzCL9wpQGfuvxJbGviD3MyW2CKbc6U4vwkttlhHSFsgSm2DrfG/CS2LkGlhK1Lq0qlRl9V/EkqlWqT2iupFGPC9uMkufNKWRkzlEGM3vh3dKSYXIDD8qbLIg55h+uumN//8U/ZHBSn7BVE5CcTScdYSXgHIuadAp9P/9nPMNdBJY0U3flHPpldUlBXR3Qq5sx1TtSHEi4FwbHotWVxchK6VMqxZWpjKiPdfmdyj92HD5RLCp4WW99ipPc1T4p9Cv4BrzBJVAplbmRzdHJlYW0KZW5kb2JqCnhyZWYKMCA3OQ0KMDAwMDAwMDAwMCA2NTUzNSBmDQowMDAwMDAwMDE1IDAwMDAwIG4NCjAwMDAwMDAxMTkgMDAwMDAgbg0KMDAwMDAwMDE3MyAwMDAwMCBuDQowMDAwMDAwMjAzIDAwMDAwIG4NCjAwMDAwMDAyMjQgMDAwMDAgbg0KMDAwMDAwMDY1MCAwMDAwMCBuDQowMDAwMDAwMDAwIDAwMDAwIGYNCjAwMDAwMTc5OTYgMDAwMDAgbg0KMDAwMDAwMDAwMCAwMDAwMCBmDQowMDAwMDE4MDYyIDAwMDAwIG4NCjAwMDAwMDAwMDAgMDAwMDAgZg0KMDAwMDAxODM3OSAwMDAwMCBuDQowMDAwMDAwMDAwIDAwMDAwIGYNCjAwMDAwMDAwMDAgMDAwMDAgZg0KMDAwMDAxODY5NyAwMDAwMCBuDQowMDAwMDE4OTk1IDAwMDAwIG4NCjAwMDAwMTkzMzYgMDAwMDAgbg0KMDAwMDAxOTYyMSAwMDAwMCBuDQowMDAwMDE5OTQ2IDAwMDAwIG4NCjAwMDAwMjAyOTMgMDAwMDAgbg0KMDAwMDAyMDYzNyAwMDAwMCBuDQowMDAwMDIwOTkyIDAwMDAwIG4NCjAwMDAwMjEyOTIgMDAwMDAgbg0KMDAwMDAyMTU5NCAwMDAwMCBuDQowMDAwMDIxOTQxIDAwMDAwIG4NCjAwMDAwMjIyMjUgMDAwMDAgbg0KMDAwMDAyMjU1MSAwMDAwMCBuDQowMDAwMDIyOTAxIDAwMDAwIG4NCjAwMDAwMjMyNTAgMDAwMDAgbg0KMDAwMDAyMzYwOSAwMDAwMCBuDQowMDAwMDIzOTE4IDAwMDAwIG4NCjAwMDAwMjQyMjMgMDAwMDAgbg0KMDAwMDAyNDM1NiAwMDAwMCBuDQowMDAwMDI0ODkyIDAwMDAwIG4NCjAwMDAwMjUwNDYgMDAwMDAgbg0KMDAwMDAyNTMzNyAwMDAwMCBuDQowMDAwMDAwMDAwIDAwMDAwIGYNCjAwMDAwNTYxNDAgMDAwMDAgbg0KMDAwMDAwMDAwMCAwMDAwMCBmDQowMDAwMDU2NDE4IDAwMDAwIG4NCjAwMDAwNTY3NTQgMDAwMDAgbg0KMDAwMDAwMDAwMCAwMDAwMCBmDQowMDAwMDU3MDA4IDAwMDAwIG4NCjAwMDAwNTczMzggMDAwMDAgbg0KMDAwMDA1NzY3NyAwMDAwMCBuDQowMDAwMDU3OTQ1IDAwMDAwIG4NCjAwMDAwNTgyODYgMDAwMDAgbg0KMDAwMDA1ODYwNCAwMDAwMCBuDQowMDAwMDAwMDAwIDAwMDAwIGYNCjAwMDAwNTg4NzMgMDAwMDAgbg0KMDAwMDA1OTIwNSAwMDAwMCBuDQowMDAwMDU5NTM0IDAwMDAwIG4NCjAwMDAwNTk4NTMgMDAwMDAgbg0KMDAwMDAwMDAwMCAwMDAwMCBmDQowMDAwMDYwMTMxIDAwMDAwIG4NCjAwMDAwNjY1MzYgMDAwMDAgbg0KMDAwMDA3Mjg1MCAwMDAwMCBuDQowMDAwMDczMDk3IDAwMDAwIG4NCjAwMDAwNzMxNzkgMDAwMDAgbg0KMDAwMDA3MzQyNiAwMDAwMCBuDQowMDAwMDczNjczIDAwMDAwIG4NCjAwMDAwNzQyODUgMDAwMDAgbg0KMDAwMDA3NDYwMyAwMDAwMCBuDQowMDAwMDc1MjQ0IDAwMDAwIG4NCjAwMDAwNzUzMzkgMDAwMDAgbg0KMDAwMDA3NjM0NCAwMDAwMCBuDQowMDAwMDc3NDUxIDAwMDAwIG4NCjAwMDAwNzgyNjIgMDAwMDAgbg0KMDAwMDA3ODg2NSAwMDAwMCBuDQowMDAwMDc5NDkyIDAwMDAwIG4NCjAwMDAwNzk1NjIgMDAwMDAgbg0KMDAwMDA5Njg0NiAwMDAwMCBuDQowMDAwMDk2OTYwIDAwMDAwIG4NCjAwMDAwOTcwMzUgMDAwMDAgbg0KMDAwMDA5NzA3MyAwMDAwMCBuDQowMDAwMDk4MTU4IDAwMDAwIG4NCjAwMDAwOTgzMTMgMDAwMDAgbg0KMDAwMDExNTUyMSAwMDAwMCBuDQp0cmFpbGVyCjw8L1Jvb3QgMSAwIFIgL1NpemUgNzkvSURbPEQxMUJCRUZCQ0NFNzk3MjdFNDgwNDZGRUNGNjNDNzY5PjxDMDNDQjc4REI2MDczMzBEMTc1MTE5NUI3N0EwMkJFNj5dPj4Kc3RhcnR4cmVmCjEyMDk3OQolJUVPRgo= \ No newline at end of file diff --git a/script/bin/ry.bat b/script/bin/ry.bat new file mode 100644 index 0000000..ea98cbe --- /dev/null +++ b/script/bin/ry.bat @@ -0,0 +1,68 @@ +rem 使用者应根据自身平台编码自行转换 防止乱码 例如 win使用gbk编码 +@echo off + +rem jar平级目录 +set AppName=ruoyi-admin.jar + +rem JVM参数 +set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC" + + +ECHO. + ECHO. [1] 启动%AppName% + ECHO. [2] 关闭%AppName% + ECHO. [3] 重启%AppName% + ECHO. [4] 启动状态 %AppName% + ECHO. [5] 退 出 +ECHO. + +ECHO.请输入选择项目的序号: +set /p ID= + IF "%id%"=="1" GOTO start + IF "%id%"=="2" GOTO stop + IF "%id%"=="3" GOTO restart + IF "%id%"=="4" GOTO status + IF "%id%"=="5" EXIT +PAUSE +:start + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if defined pid ( + echo %%is running + PAUSE + ) + +start javaw %JVM_OPTS% -jar %AppName% + +echo starting…… +echo Start %AppName% success... +goto:eof + +rem 函数stop通过jps命令查找pid并结束进程 +:stop + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% does not exists) else ( + echo prepare to kill %image_name% + echo start kill %pid% ... + rem 根据进程ID,kill进程 + taskkill /f /pid %pid% + ) +goto:eof +:restart + call :stop + call :start +goto:eof +:status + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% is dead ) else ( + echo %image_name% is running + ) +goto:eof diff --git a/script/bin/ry.sh b/script/bin/ry.sh new file mode 100644 index 0000000..a6f5d9c --- /dev/null +++ b/script/bin/ry.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# ./ry.sh start 启动 stop 停止 restart 重启 status 状态 +AppName=ruoyi-admin.jar + +# JVM参数 +JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC" +APP_HOME=`pwd` +LOG_PATH=$APP_HOME/logs/$AppName.log + +if [ "$1" = "" ]; +then + echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m" + exit 1 +fi + +if [ "$AppName" = "" ]; +then + echo -e "\033[0;31m 未输入应用名 \033[0m" + exit 1 +fi + +function start() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + + if [ x"$PID" != x"" ]; then + echo "$AppName is running..." + else + nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 & + echo "Start $AppName success..." + fi +} + +function stop() +{ + echo "Stop $AppName" + + PID="" + query(){ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + } + + query + if [ x"$PID" != x"" ]; then + kill -TERM $PID + echo "$AppName (pid:$PID) exiting..." + while [ x"$PID" != x"" ] + do + sleep 1 + query + done + echo "$AppName exited." + else + echo "$AppName already stopped." + fi +} + +function restart() +{ + stop + sleep 2 + start +} + +function status() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l` + if [ $PID != 0 ];then + echo "$AppName is running..." + else + echo "$AppName is not running..." + fi +} + +case $1 in + start) + start;; + stop) + stop;; + restart) + restart;; + status) + status;; + *) + +esac diff --git a/script/docker/database.yml b/script/docker/database.yml new file mode 100644 index 0000000..6034b39 --- /dev/null +++ b/script/docker/database.yml @@ -0,0 +1,59 @@ +services: + # 此镜像仅用于测试 正式环境需自行安装数据库 + # SID: XE user: system password: oracle + oracle: + image: tekintian/oracle12c:latest + container_name: oracle + environment: + # 时区上海 + TZ: Asia/Shanghai + DBCA_TOTAL_MEMORY: 16192 + ports: + - "18080:8080" + - "1521:1521" + volumes: + # 数据挂载 + - "/docker/oracle/data:/u01/app/oracle" + network_mode: "host" + + # 此镜像仅用于测试 正式环境需自行安装数据库 + sqlserver: + image: mcr.microsoft.com/mssql/server:2017-latest + container_name: sqlserver + environment: + # 时区上海 + TZ: Asia/Shanghai + ACCEPT_EULA: "Y" + SA_PASSWORD: "Ruoyi@123" + ports: + - "1433:1433" + volumes: + # 数据挂载 + - "/docker/sqlserver/data:/var/opt/mssql" + network_mode: "host" + + postgres: + image: postgres:14.2 + container_name: postgres + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5432:5432" + volumes: + - /docker/postgres/data:/var/lib/postgresql/data + network_mode: "host" + + postgres13: + image: postgres:13.6 + container_name: postgres13 + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5433:5432" + volumes: + - /docker/postgres13/data:/var/lib/postgresql/data + network_mode: "host" diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml new file mode 100644 index 0000000..885c236 --- /dev/null +++ b/script/docker/docker-compose.yml @@ -0,0 +1,154 @@ +services: + mysql: + image: mysql:8.0.33 + container_name: mysql + environment: + # 时区上海 + TZ: Asia/Shanghai + # root 密码 + MYSQL_ROOT_PASSWORD: root + # 初始化数据库(后续的初始化sql会在这个库执行) + MYSQL_DATABASE: ry-vue + ports: + - "3306:3306" + volumes: + # 数据挂载 + - /docker/mysql/data/:/var/lib/mysql/ + # 配置挂载 + - /docker/mysql/conf/:/etc/mysql/conf.d/ + command: + # 将mysql8.0默认密码策略 修改为 原先 策略 (mysql8.0对其默认策略做了更改 会导致密码无法匹配) + --default-authentication-plugin=mysql_native_password + --character-set-server=utf8mb4 + --collation-server=utf8mb4_general_ci + --explicit_defaults_for_timestamp=true + --lower_case_table_names=1 + privileged: true + network_mode: "host" + + nginx-web: + image: nginx:1.23.4 + container_name: nginx-web + environment: + # 时区上海 + TZ: Asia/Shanghai + ports: + - "80:80" + - "443:443" + volumes: + # 证书映射 + - /docker/nginx/cert:/etc/nginx/cert + # 配置文件映射 + - /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf + # 页面目录 + - /docker/nginx/html:/usr/share/nginx/html + # 日志目录 + - /docker/nginx/log:/var/log/nginx + privileged: true + network_mode: "host" + + redis: + image: redis:6.2.12 + container_name: redis + ports: + - "6379:6379" + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/redis/conf:/redis/config:rw + # 数据文件 + - /docker/redis/data/:/redis/data/:rw + command: "redis-server /redis/config/redis.conf" + privileged: true + network_mode: "host" + + minio: + image: minio/minio:RELEASE.2023-04-13T03-08-07Z + container_name: minio + ports: + # api 端口 + - "9000:9000" + # 控制台端口 + - "9001:9001" + environment: + # 时区上海 + TZ: Asia/Shanghai + # 管理后台用户名 + MINIO_ROOT_USER: ruoyi + # 管理后台密码,最小8个字符 + MINIO_ROOT_PASSWORD: ruoyi123 + # https需要指定域名 + #MINIO_SERVER_URL: "https://xxx.com:9000" + #MINIO_BROWSER_REDIRECT_URL: "https://xxx.com:9001" + # 开启压缩 on 开启 off 关闭 + MINIO_COMPRESS: "off" + # 扩展名 .pdf,.doc 为空 所有类型均压缩 + MINIO_COMPRESS_EXTENSIONS: "" + # mime 类型 application/pdf 为空 所有类型均压缩 + MINIO_COMPRESS_MIME_TYPES: "" + volumes: + # 映射当前目录下的data目录至容器内/data目录 + - /docker/minio/data:/data + # 映射配置目录 + - /docker/minio/config:/root/.minio/ + command: server --address ':9000' --console-address ':9001' /data # 指定容器中的目录 /data + privileged: true + network_mode: "host" + + ruoyi-server1: + image: ruoyi/ruoyi-server:5.3.0 + container_name: ruoyi-server1 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8080 + volumes: + # 配置文件 + - /docker/server1/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + ruoyi-server2: + image: ruoyi/ruoyi-server:5.3.0 + container_name: ruoyi-server2 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8081 + volumes: + # 配置文件 + - /docker/server2/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + ruoyi-monitor-admin: + image: ruoyi/ruoyi-monitor-admin:5.3.0 + container_name: ruoyi-monitor-admin + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/monitor/logs/:/ruoyi/monitor/logs + privileged: true + network_mode: "host" + + ruoyi-snailjob-server: + image: ruoyi/ruoyi-snailjob-server:5.3.0 + container_name: ruoyi-snailjob-server + environment: + # 时区上海 + TZ: Asia/Shanghai + ports: + - "8800:8800" + - "17888:17888" + volumes: + - /docker/snailjob/logs/:/ruoyi/snailjob/logs + privileged: true + network_mode: "host" diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf new file mode 100644 index 0000000..3c79d97 --- /dev/null +++ b/script/docker/nginx/conf/nginx.conf @@ -0,0 +1,115 @@ +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + # 限制body大小 + client_max_body_size 100m; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + upstream server { + ip_hash; + server 127.0.0.1:8080; + server 127.0.0.1:8081; + } + + upstream monitor-admin { + server 127.0.0.1:9090; + } + + upstream snailjob-server { + server 127.0.0.1:8800; + } + + server { + listen 80; + server_name localhost; + + # https配置参考 start + #listen 443 ssl; + + # 证书直接存放 /docker/nginx/cert/ 目录下即可 更改证书名称即可 无需更改证书路径 + #ssl on; + #ssl_certificate /etc/nginx/cert/xxx.local.crt; # /etc/nginx/cert/ 为docker映射路径 不允许更改 + #ssl_certificate_key /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 为docker映射路径 不允许更改 + #ssl_session_timeout 5m; + #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; + #ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + #ssl_prefer_server_ciphers on; + # https配置参考 end + + # 演示环境配置 拦截除 GET POST 之外的所有请求 + # if ($request_method !~* GET|POST) { + # rewrite ^/(.*)$ /403; + # } + + # location = /403 { + # default_type application/json; + # return 200 '{"msg":"演示模式,不允许操作","code":500}'; + # } + + # 限制外网访问内网 actuator 相关路径 + location ~ ^(/[^/]*)?/actuator.*(/.*)?$ { + return 403; + } + + location / { + root /usr/share/nginx/html; # docker映射路径 不允许更改 + try_files $uri $uri/ /index.html; + index index.html index.htm; + } + + location /prod-api/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 86400s; + # sse 与 websocket参数 + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_buffering off; + proxy_cache off; + proxy_pass http://server/; + } + + # https 会拦截内链所有的 http 请求 造成功能无法使用 + # 解决方案1 将 admin 服务 也配置成 https + # 解决方案2 将菜单配置为外链访问 走独立页面 http 访问 + location /admin/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://monitor-admin/admin/; + } + + location /snail-job/ { + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header REMOTE-HOST $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://snailjob-server/snail-job/; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/script/docker/redis/data/README.md b/script/docker/redis/data/README.md new file mode 100644 index 0000000..fbc5474 --- /dev/null +++ b/script/docker/redis/data/README.md @@ -0,0 +1 @@ +数据目录 请执行 `chmod 777 /docker/redis/data` 赋予读写权限 否则将无法写入数据 \ No newline at end of file diff --git a/script/leave/leave2.json b/script/leave/leave2.json new file mode 100644 index 0000000..9fce8ff --- /dev/null +++ b/script/leave/leave2.json @@ -0,0 +1,111 @@ +{ + "flowCode" : "leave2", + "flowName" : "请假申请-排他网关", + "category" : "1", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "300,240|300,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a", + "nextNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd", + "skipType" : "PASS", + "coordinate" : "320,240;390,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "440,240|440,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "fdcae93b-b69c-498a-b231-09255e74bcbd", + "nextNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "skipType" : "PASS", + "coordinate" : "490,240;535,240" + } ] + }, { + "nodeType" : 3, + "nodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nodeRatio" : 0.000, + "coordinate" : "560,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nextNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "skipType" : "PASS", + "skipCondition" : "le@@leaveDays|2", + "coordinate" : "560,265;560,320;670,320" + }, { + "nowNodeCode" : "7b8c7ead-7dc8-4951-a7f3-f0c41995909e", + "nextNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605", + "skipName" : "大于两天", + "skipType" : "PASS", + "skipCondition" : "gt@@leaveDays|2", + "coordinate" : "560,215;560,160;670,160|560,187" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "nodeName" : "组长", + "permissionFlag" : "3,4", + "nodeRatio" : 0.000, + "coordinate" : "720,320|720,320", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "b3528155-dcb7-4445-bbdf-3d00e3499e86", + "nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "skipType" : "PASS", + "coordinate" : "770,320;860,320;860,280" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "nodeName" : "总经理", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "860,240|860,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "nextNodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1", + "skipType" : "PASS", + "coordinate" : "910,240;980,240" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "40aa65fd-0712-4d23-b6f7-d0432b920fd1", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1000,240|1000,240", + "skipAnyNode" : "N", + "formCustom" : "N" + }, { + "nodeType" : 1, + "nodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605", + "nodeName" : "部门领导", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "720,160|720,160", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "5ed2362b-fc0c-4d52-831f-95208b830605", + "nextNodeCode" : "c9fa6d7d-2a74-4e78-b947-0cad8a6af869", + "skipType" : "PASS", + "coordinate" : "770,160;860,160;860,200" + } ] + } ] +} diff --git a/script/leave/leave3.json b/script/leave/leave3.json new file mode 100644 index 0000000..08daae4 --- /dev/null +++ b/script/leave/leave3.json @@ -0,0 +1,121 @@ +{ + "flowCode" : "leave3", + "flowName" : "请假申请-并行网关", + "category" : "1", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "380,220|380,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "a80ecf9f-f465-4ae5-a429-e30ec5d0f957", + "nextNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99", + "skipType" : "PASS", + "coordinate" : "400,220;470,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "520,220|520,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "b7bbb571-06de-455c-8083-f83c07bf0b99", + "nextNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "skipType" : "PASS", + "coordinate" : "570,220;655,220" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nodeRatio" : 0.000, + "coordinate" : "680,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nextNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "skipType" : "PASS", + "coordinate" : "680,195;680,140;750,140" + }, { + "nowNodeCode" : "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a", + "nextNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394", + "skipType" : "PASS", + "coordinate" : "680,245;680,300;750,300" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "nodeName" : "市场部", + "permissionFlag" : "role:1", + "nodeRatio" : 0.000, + "coordinate" : "800,140|800,140", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "4b7743cd-940c-431b-926f-e7b614fbf1fe", + "nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "skipType" : "PASS", + "coordinate" : "850,140;920,140;920,195" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "nodeRatio" : 0.000, + "coordinate" : "920,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "nextNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6", + "skipType" : "PASS", + "coordinate" : "945,220;975,220;975,220;960,220;960,220;990,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6", + "nodeName" : "CEO", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "1040,220|1040,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "23e7429e-2b47-4431-b93e-40db7c431ce6", + "nextNodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1", + "skipType" : "PASS", + "coordinate" : "1090,220;1140,220" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1160,220|1160,220", + "skipAnyNode" : "N", + "formCustom" : "N" + }, { + "nodeType" : 1, + "nodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394", + "nodeName" : "综合部", + "permissionFlag" : "role:3,role:4", + "nodeRatio" : 0.000, + "coordinate" : "800,300|800,300", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "762cb975-37d8-4276-b6db-79a4c3606394", + "nextNodeCode" : "b66b6563-f9fe-41cc-a782-f7837bb6f3d2", + "skipType" : "PASS", + "coordinate" : "850,300;920,300;920,245" + } ] + } ] +} \ No newline at end of file diff --git a/script/leave/leave4.json b/script/leave/leave4.json new file mode 100644 index 0000000..f8f4408 --- /dev/null +++ b/script/leave/leave4.json @@ -0,0 +1,90 @@ +{ + "flowCode" : "leave4", + "flowName" : "请假申请-会签", + "category" : "1", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "320,240|320,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "9ce8bf00-f25b-4fc6-91b8-827082fc4876", + "nextNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "skipType" : "PASS", + "coordinate" : "340,240;410,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "460,240|460,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "e90b98ef-35b4-410c-a663-bae8b7624b9f", + "nextNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "skipType" : "PASS", + "coordinate" : "510,240;590,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "nodeName" : "百分之60通过", + "permissionFlag" : "${userList}", + "nodeRatio" : 60.000, + "coordinate" : "640,240|640,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "768b5b1a-6726-4d67-8853-4cc70d5b1045", + "nextNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "skipType" : "PASS", + "coordinate" : "690,240;770,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "nodeName" : "全部审批通过", + "permissionFlag" : "role:1,role:3", + "nodeRatio" : 100.000, + "coordinate" : "820,240|820,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "2f9f2e21-9bcf-42a3-a07c-13037aad22d1", + "nextNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "skipType" : "PASS", + "coordinate" : "870,240;950,240" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "nodeName" : "CEO", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "1000,240|1000,240", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "27461e01-3d9f-4530-8fe3-bd5ec7f9571f", + "nextNodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc", + "skipType" : "PASS", + "coordinate" : "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "b62b88c3-8d8d-4969-911e-2aaea219e7fc", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1120,240|1120,240", + "skipAnyNode" : "N", + "formCustom" : "N" + } ] +} \ No newline at end of file diff --git a/script/leave/leave5.json b/script/leave/leave5.json new file mode 100644 index 0000000..dc99494 --- /dev/null +++ b/script/leave/leave5.json @@ -0,0 +1,121 @@ +{ + "flowCode" : "leave5", + "flowName" : "请假申请-并行会签网关", + "category" : "1", + "version" : "1", + "formCustom" : "N", + "formPath" : "/workflow/leaveEdit/index", + "nodeList" : [ { + "nodeType" : 0, + "nodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c", + "nodeName" : "开始", + "nodeRatio" : 0.000, + "coordinate" : "300,220|300,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "ebebaf26-9cb6-497e-8119-4c9fed4c597c", + "nextNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374", + "skipType" : "PASS", + "coordinate" : "320,220;350,220;350,220;340,220;340,220;370,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374", + "nodeName" : "申请人", + "nodeRatio" : 0.000, + "coordinate" : "420,220|420,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "e1b04e96-dc81-4858-a309-2fe945d2f374", + "nextNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "skipType" : "PASS", + "coordinate" : "470,220;535,220" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nodeRatio" : 0.000, + "coordinate" : "560,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nextNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "skipType" : "PASS", + "coordinate" : "560,245;560,320;650,320" + }, { + "nowNodeCode" : "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9", + "nextNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "skipType" : "PASS", + "coordinate" : "560,195;560,120;650,120" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "nodeName" : "会签", + "permissionFlag" : "role:1,role:3", + "nodeRatio" : 100.000, + "coordinate" : "700,320|700,320", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "c80f273e-1f17-4bd8-9ad1-04a4a94ea862", + "nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "skipType" : "PASS", + "coordinate" : "750,320;860,320;860,245" + } ] + }, { + "nodeType" : 4, + "nodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "nodeRatio" : 0.000, + "coordinate" : "860,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "nextNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9", + "skipType" : "PASS", + "coordinate" : "885,220;950,220" + } ] + }, { + "nodeType" : 1, + "nodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9", + "nodeName" : "CEO", + "permissionFlag" : "1", + "nodeRatio" : 0.000, + "coordinate" : "1000,220|1000,220", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "7a8f0473-e409-442e-a843-5c2b813d00e9", + "nextNodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169", + "skipType" : "PASS", + "coordinate" : "1050,220;1120,220" + } ] + }, { + "nodeType" : 2, + "nodeCode" : "03c4d2bc-58b5-4408-a2e4-65afb046f169", + "nodeName" : "结束", + "nodeRatio" : 0.000, + "coordinate" : "1140,220|1140,220", + "skipAnyNode" : "N", + "formCustom" : "N" + }, { + "nodeType" : 1, + "nodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "nodeName" : "百分之60票签", + "permissionFlag" : "${userList}", + "nodeRatio" : 60.000, + "coordinate" : "700,120|700,120", + "skipAnyNode" : "N", + "formCustom" : "N", + "skipList" : [ { + "nowNodeCode" : "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4", + "nextNodeCode" : "1a20169e-3d82-4926-a151-e2daad28de1b", + "skipType" : "PASS", + "coordinate" : "750,120;860,120;860,195" + } ] + } ] +} \ No newline at end of file diff --git a/script/sql/oracle/oracle_ry_job.sql b/script/sql/oracle/oracle_ry_job.sql new file mode 100644 index 0000000..c2dbbfa --- /dev/null +++ b/script/sql/oracle/oracle_ry_job.sql @@ -0,0 +1,914 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : Oracle + Date: 2024-12-27 22:22:15 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id number GENERATED ALWAYS AS IDENTITY, + name varchar2(64) NULL, + unique_id varchar2(64) NULL, + description varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_namespace + ADD CONSTRAINT pk_sj_namespace PRIMARY KEY (id); + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name); + +COMMENT ON COLUMN sj_namespace.id IS '主键'; +COMMENT ON COLUMN sj_namespace.name IS '名称'; +COMMENT ON COLUMN sj_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN sj_namespace.description IS '描述'; +COMMENT ON COLUMN sj_namespace.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_namespace.update_dt IS '修改时间'; +COMMENT ON TABLE sj_namespace IS '命名空间'; + +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Development', 'dev', '', 0, sysdate, sysdate); +INSERT INTO sj_namespace(name, unique_id, description, deleted, create_dt, update_dt) VALUES ('Production', 'prod', '', 0, sysdate, sysdate); + +-- sj_group_config +CREATE TABLE sj_group_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + description varchar2(256) DEFAULT '' NULL, + token varchar2(64) DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' NULL, + group_status smallint DEFAULT 0 NOT NULL, + version number NOT NULL, + group_partition number NOT NULL, + id_generator_mode smallint DEFAULT 1 NOT NULL, + init_scene smallint DEFAULT 0 NOT NULL, + bucket_index number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_group_config + ADD CONSTRAINT pk_sj_group_config PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_group_config.id IS '主键'; +COMMENT ON COLUMN sj_group_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_group_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_group_config.description IS '组描述'; +COMMENT ON COLUMN sj_group_config.token IS 'token'; +COMMENT ON COLUMN sj_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_group_config.version IS '版本号'; +COMMENT ON COLUMN sj_group_config.group_partition IS '分区'; +COMMENT ON COLUMN sj_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN sj_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN sj_group_config.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_group_config IS '组配置'; + +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 ('dev', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate); +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 ('prod', 'ruoyi_group', '', 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', 1, 1, 0, 1, 1, 4, sysdate, sysdate); + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + notify_name varchar2(64) DEFAULT '' NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + notify_status smallint DEFAULT 0 NOT NULL, + recipient_ids varchar2(128) NULL, + notify_threshold number DEFAULT 0 NOT NULL, + notify_scene smallint DEFAULT 0 NOT NULL, + rate_limiter_status smallint DEFAULT 0 NOT NULL, + rate_limiter_threshold number DEFAULT 0 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_notify_config + ADD CONSTRAINT pk_sj_notify_config PRIMARY KEY (id); + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_notify_config.id IS '主键'; +COMMENT ON COLUMN sj_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_notify_config.notify_name IS '通知名称'; +COMMENT ON COLUMN sj_notify_config.system_task_type IS '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.recipient_ids IS '接收人id列表'; +COMMENT ON COLUMN sj_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN sj_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN sj_notify_config.description IS '描述'; +COMMENT ON COLUMN sj_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_config IS '通知配置'; + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + recipient_name varchar2(64) NULL, + notify_type smallint DEFAULT 0 NOT NULL, + notify_attribute varchar2(512) NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_notify_recipient + ADD CONSTRAINT pk_sj_notify_recipient PRIMARY KEY (id); + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); + +COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; +COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; +COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; +COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; +COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_recipient.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_recipient IS '告警通知接收人'; + +-- sj_retry_dead_letter_0 +CREATE TABLE sj_retry_dead_letter_0 +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + unique_id varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_name varchar2(64) NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + args_str clob NULL, + ext_attrs clob NULL, + task_type smallint DEFAULT 1 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_dead_letter_0 + ADD CONSTRAINT pk_sj_retry_dead_letter_0 PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id); +CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no); +CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt); + +COMMENT ON COLUMN sj_retry_dead_letter_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_dead_letter_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_dead_letter_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_dead_letter_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_dead_letter_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_dead_letter_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_dead_letter_0.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_dead_letter_0 IS '死信队列表'; + +-- sj_retry_task_0 +CREATE TABLE sj_retry_task_0 +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + unique_id varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_name varchar2(64) NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + args_str clob NULL, + ext_attrs clob NULL, + next_trigger_at date NOT NULL, + retry_count number DEFAULT 0 NOT NULL, + retry_status smallint DEFAULT 0 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task_0 + ADD CONSTRAINT pk_sj_retry_task_0 PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type); +CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status); +CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id); +CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no); +CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt); + +COMMENT ON COLUMN sj_retry_task_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_0.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_retry_task_0.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_retry_task_0.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN sj_retry_task_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_0.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_0.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_0 IS '任务表'; + +-- sj_retry_task_log +CREATE TABLE sj_retry_task_log +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + unique_id varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_name varchar2(64) NULL, + idempotent_id varchar2(64) NULL, + biz_no varchar2(64) DEFAULT '' NULL, + executor_name varchar2(512) DEFAULT '' NULL, + args_str clob NULL, + ext_attrs clob NULL, + retry_status smallint DEFAULT 0 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task_log + ADD CONSTRAINT pk_sj_retry_task_log PRIMARY KEY (id); + +CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status); +CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id); +CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id); +CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no); +CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt); + +COMMENT ON COLUMN sj_retry_task_log.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_log.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_log.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_log.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_log.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_log.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_log.retry_status IS '重试状态 0、重试中 1、成功 2、最大次数'; +COMMENT ON COLUMN sj_retry_task_log.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_log.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_log.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_log IS '任务日志基础信息表'; + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + unique_id varchar2(64) NULL, + message clob NULL, + log_num number DEFAULT 1 NOT NULL, + real_time number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_task_log_message + ADD CONSTRAINT pk_sj_retry_task_log_message PRIMARY KEY (id); + +CREATE INDEX idx_sj_rt_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id); +CREATE INDEX idx_sj_rt_log_message_02 ON sj_retry_task_log_message (create_dt); + +COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log_message.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_task_log_message IS '任务调度日志信息记录表'; + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + scene_name varchar2(64) NULL, + group_name varchar2(64) NULL, + scene_status smallint DEFAULT 0 NOT NULL, + max_retry_count number DEFAULT 5 NOT NULL, + back_off smallint DEFAULT 1 NOT NULL, + trigger_interval varchar2(16) DEFAULT '' NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + deadline_request number DEFAULT 60000 NOT NULL, + executor_timeout number DEFAULT 5 NOT NULL, + route_key smallint DEFAULT 4 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_scene_config + ADD CONSTRAINT pk_sj_retry_scene_config PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name); + +COMMENT ON COLUMN sj_retry_scene_config.id IS '主键'; +COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_retry_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN sj_retry_scene_config.description IS '描述'; +COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_scene_config IS '场景配置'; + +-- sj_server_node +CREATE TABLE sj_server_node +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + host_id varchar2(64) NULL, + host_ip varchar2(64) NULL, + host_port number NOT NULL, + expire_at date NOT NULL, + node_type smallint NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_server_node + ADD CONSTRAINT pk_sj_server_node PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip); + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name); +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type); + +COMMENT ON COLUMN sj_server_node.id IS '主键'; +COMMENT ON COLUMN sj_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_server_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_server_node.host_id IS '主机id'; +COMMENT ON COLUMN sj_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN sj_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN sj_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN sj_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN sj_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_server_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_server_node IS '服务器节点'; + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name varchar2(64) NOT NULL, + lock_until timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, + locked_at timestamp(3) DEFAULT CURRENT_TIMESTAMP(3) NOT NULL, + locked_by varchar2(255) NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_distributed_lock + ADD CONSTRAINT pk_sj_distributed_lock PRIMARY KEY (name); + +COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN sj_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN sj_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_distributed_lock.update_dt IS '修改时间'; +COMMENT ON TABLE sj_distributed_lock IS '锁定表'; + +-- sj_system_user +CREATE TABLE sj_system_user +( + id number GENERATED ALWAYS AS IDENTITY, + username varchar2(64) NULL, + password varchar2(128) NULL, + role smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_system_user + ADD CONSTRAINT pk_sj_system_user PRIMARY KEY (id); + +COMMENT ON COLUMN sj_system_user.id IS '主键'; +COMMENT ON COLUMN sj_system_user.username IS '账号'; +COMMENT ON COLUMN sj_system_user.password IS '密码'; +COMMENT ON COLUMN sj_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN sj_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user IS '系统用户表'; + +-- pwd: admin +INSERT INTO sj_system_user(username, password, role, create_dt, update_dt) VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, sysdate, sysdate); + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id number GENERATED ALWAYS AS IDENTITY, + group_name varchar2(64) NULL, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + system_user_id number NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_system_user_permission + ADD CONSTRAINT pk_sj_system_user_permission PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_su_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); + +COMMENT ON COLUMN sj_system_user_permission.id IS '主键'; +COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN sj_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user_permission.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user_permission IS '系统用户权限表'; + +-- sj_sequence_alloc +CREATE TABLE sj_sequence_alloc +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + max_id number DEFAULT 1 NOT NULL, + step number DEFAULT 100 NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_sequence_alloc + ADD CONSTRAINT pk_sj_sequence_alloc PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name); + +COMMENT ON COLUMN sj_sequence_alloc.id IS '主键'; +COMMENT ON COLUMN sj_sequence_alloc.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_sequence_alloc.group_name IS '组名称'; +COMMENT ON COLUMN sj_sequence_alloc.max_id IS '最大id'; +COMMENT ON COLUMN sj_sequence_alloc.step IS '步长'; +COMMENT ON COLUMN sj_sequence_alloc.update_dt IS '更新时间'; +COMMENT ON TABLE sj_sequence_alloc IS '号段模式序号ID分配表'; + +-- sj_job +CREATE TABLE sj_job +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_name varchar2(64) NULL, + args_str clob DEFAULT NULL NULL, + args_type smallint DEFAULT 1 NOT NULL, + next_trigger_at number NOT NULL, + job_status smallint DEFAULT 1 NOT NULL, + task_type smallint DEFAULT 1 NOT NULL, + route_key smallint DEFAULT 4 NOT NULL, + executor_type smallint DEFAULT 1 NOT NULL, + executor_info varchar2(255) DEFAULT NULL NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar2(255) NULL, + block_strategy smallint DEFAULT 1 NOT NULL, + executor_timeout number DEFAULT 0 NOT NULL, + max_retry_times number DEFAULT 0 NOT NULL, + parallel_num number DEFAULT 1 NOT NULL, + retry_interval number DEFAULT 0 NOT NULL, + bucket_index number DEFAULT 0 NOT NULL, + resident smallint DEFAULT 0 NOT NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + owner_id number NULL, + description varchar2(256) DEFAULT '' NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job + ADD CONSTRAINT pk_sj_job PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name); +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index); +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt); + +COMMENT ON COLUMN sj_job.id IS '主键'; +COMMENT ON COLUMN sj_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job.group_name IS '组名称'; +COMMENT ON COLUMN sj_job.job_name IS '名称'; +COMMENT ON COLUMN sj_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_job.job_status IS '任务状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN sj_job.route_key IS '路由策略'; +COMMENT ON COLUMN sj_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN sj_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN sj_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN sj_job.parallel_num IS '并行数'; +COMMENT ON COLUMN sj_job.retry_interval IS '重试间隔 ( s ) '; +COMMENT ON COLUMN sj_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN sj_job.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_job.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_job.description IS '描述'; +COMMENT ON COLUMN sj_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job IS '任务信息'; + +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 ('dev', 'ruoyi_group', 'demo-job', NULL, 1, 1710344035622, 1, 1, 4, 1, 'testJobExecutor', 2, '60', 1, 60, 3, 1, 1, 116, 0, '', 1,'', '', 0, sysdate, sysdate); + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + task_batch_id number NOT NULL, + task_id number NOT NULL, + message clob NULL, + log_num number DEFAULT 1 NOT NULL, + real_time number DEFAULT 0 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_log_message + ADD CONSTRAINT pk_sj_job_log_message PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt); +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_log_message.id IS '主键'; +COMMENT ON COLUMN sj_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN sj_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN sj_job_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_job_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_job_log_message IS '调度日志'; + +-- sj_job_task +CREATE TABLE sj_job_task +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + task_batch_id number NOT NULL, + parent_id number DEFAULT 0 NOT NULL, + task_status smallint DEFAULT 0 NOT NULL, + retry_count number DEFAULT 0 NOT NULL, + mr_stage smallint DEFAULT NULL NULL, + leaf smallint DEFAULT '1' NOT NULL, + task_name varchar2(255) DEFAULT '' NULL, + client_info varchar2(128) DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + result_message clob NULL, + args_str clob DEFAULT NULL NULL, + args_type smallint DEFAULT 1 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_task + ADD CONSTRAINT pk_sj_job_task PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status); +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt); +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_task.id IS '主键'; +COMMENT ON COLUMN sj_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; +COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; +COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; +COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task IS '任务实例'; + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + workflow_node_id number DEFAULT 0 NOT NULL, + parent_workflow_node_id number DEFAULT 0 NOT NULL, + workflow_task_batch_id number DEFAULT 0 NOT NULL, + task_batch_status smallint DEFAULT 0 NOT NULL, + operation_reason smallint DEFAULT 0 NOT NULL, + execution_at number DEFAULT 0 NOT NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + parent_id varchar2(64) DEFAULT '' NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_task_batch + ADD CONSTRAINT pk_sj_job_task_batch PRIMARY KEY (id); + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt); +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON COLUMN sj_job_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task_batch.job_id IS '任务id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '工作流任务父批次id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '工作流任务批次id'; +COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task_batch IS '任务批次'; + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + business_id number NOT NULL, + system_task_type smallint DEFAULT 3 NOT NULL, + trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL, + success_num number DEFAULT 0 NOT NULL, + fail_num number DEFAULT 0 NOT NULL, + fail_reason varchar2(512) DEFAULT '' NULL, + stop_num number DEFAULT 0 NOT NULL, + stop_reason varchar2(512) DEFAULT '' NULL, + cancel_num number DEFAULT 0 NOT NULL, + cancel_reason varchar2(512) DEFAULT '' NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_job_summary + ADD CONSTRAINT pk_sj_job_summary PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id); + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id); + +COMMENT ON COLUMN sj_job_summary.id IS '主键'; +COMMENT ON COLUMN sj_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_summary.business_id IS '业务id ( job_id或workflow_id ) '; +COMMENT ON COLUMN sj_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.cancel_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job'; + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) DEFAULT '' NULL, + scene_name varchar2(50) DEFAULT '' NULL, + trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL, + running_num number DEFAULT 0 NOT NULL, + finish_num number DEFAULT 0 NOT NULL, + max_count_num number DEFAULT 0 NOT NULL, + suspend_num number DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_retry_summary + ADD CONSTRAINT pk_sj_retry_summary PRIMARY KEY (id); + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at); + +COMMENT ON COLUMN sj_retry_summary.id IS '主键'; +COMMENT ON COLUMN sj_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN sj_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN sj_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN sj_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN sj_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry'; + +-- sj_workflow +CREATE TABLE sj_workflow +( + id number GENERATED ALWAYS AS IDENTITY, + workflow_name varchar2(64) NULL, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + workflow_status smallint DEFAULT 1 NOT NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar2(255) NULL, + next_trigger_at number NOT NULL, + block_strategy smallint DEFAULT 1 NOT NULL, + executor_timeout number DEFAULT 0 NOT NULL, + description varchar2(256) DEFAULT '' NULL, + flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + notify_ids varchar2(128) DEFAULT '' NULL, + bucket_index number DEFAULT 0 NOT NULL, + version number NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow + ADD CONSTRAINT pk_sj_workflow PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt); +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow.id IS '主键'; +COMMENT ON COLUMN sj_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN sj_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_workflow.description IS '描述'; +COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; +COMMENT ON COLUMN sj_workflow.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_workflow.version IS '版本号'; +COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow IS '工作流'; + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + node_name varchar2(64) NULL, + group_name varchar2(64) NULL, + job_id number NOT NULL, + workflow_id number NOT NULL, + node_type smallint DEFAULT 1 NOT NULL, + expression_type smallint DEFAULT 0 NOT NULL, + fail_strategy smallint DEFAULT 1 NOT NULL, + workflow_node_status smallint DEFAULT 1 NOT NULL, + priority_level number DEFAULT 1 NOT NULL, + node_info clob DEFAULT NULL NULL, + version number NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow_node + ADD CONSTRAINT pk_sj_workflow_node PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt); +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_node.id IS '主键'; +COMMENT ON COLUMN sj_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN sj_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN sj_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN sj_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN sj_workflow_node.node_info IS '节点信息 '; +COMMENT ON COLUMN sj_workflow_node.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_node IS '工作流节点'; + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id number GENERATED ALWAYS AS IDENTITY, + namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL, + group_name varchar2(64) NULL, + workflow_id number NOT NULL, + task_batch_status smallint DEFAULT 0 NOT NULL, + operation_reason smallint DEFAULT 0 NOT NULL, + flow_info clob DEFAULT NULL NULL, + wf_context clob DEFAULT NULL NULL, + execution_at number DEFAULT 0 NOT NULL, + ext_attrs varchar2(256) DEFAULT '' NULL, + version number DEFAULT 1 NOT NULL, + deleted smallint DEFAULT 0 NOT NULL, + create_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL, + update_dt date DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +ALTER TABLE sj_workflow_task_batch + ADD CONSTRAINT pk_sj_workflow_task_batch PRIMARY KEY (id); + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt); +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; +COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_task_batch IS '工作流批次'; diff --git a/script/sql/oracle/oracle_ry_vue_5.X.sql b/script/sql/oracle/oracle_ry_vue_5.X.sql new file mode 100644 index 0000000..94024c9 --- /dev/null +++ b/script/sql/oracle/oracle_ry_vue_5.X.sql @@ -0,0 +1,1391 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id number(20) not null, + user_id number(20) not null, + tenant_id varchar2(20) default '000000', + auth_id varchar2(255) not null, + source varchar2(255) not null, + open_id varchar2(255) default null, + user_name varchar2(30) not null, + nick_name varchar2(30) default '', + email varchar2(255) default '', + avatar varchar2(500) default '', + access_token varchar2(255) not null, + expire_in number(20) default null, + refresh_token varchar2(255) default null, + access_code varchar2(255) default null, + union_id varchar2(255) default null, + scope varchar2(255) default null, + token_type varchar2(255) default null, + id_token varchar2(2000) default null, + mac_algorithm varchar2(255) default null, + mac_key varchar2(255) default null, + code varchar2(255) default null, + oauth_token varchar2(255) default null, + oauth_token_secret varchar2(255) default null, + create_dept number(20), + create_by number(20), + create_time date, + update_by number(20), + update_time date, + del_flag char(1) default '0' +); + +alter table sys_social add constraint pk_sys_social primary key (id); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 1代表删除)'; + +-- ---------------------------- +-- 租户表 +-- ---------------------------- +create table sys_tenant ( + id number(20) not null, + tenant_id varchar2(20) not null, + contact_user_name varchar2(20) default '', + contact_phone varchar2(20) default '', + company_name varchar2(50) default '', + license_number varchar2(30) default '', + address varchar2(200) default '', + intro varchar2(200) default '', + domain varchar2(200) default '', + remark varchar2(200) default '', + package_id number(20) default null, + expire_time date default null, + account_count number(4) default -1, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_tenant add constraint pk_sys_tenant primary key (id); + +comment on table sys_tenant is '租户表'; +comment on column sys_tenant.tenant_id is '租户编号'; +comment on column sys_tenant.contact_phone is '联系电话'; +comment on column sys_tenant.company_name is '企业名称'; +comment on column sys_tenant.company_name is '联系人'; +comment on column sys_tenant.license_number is '统一社会信用代码'; +comment on column sys_tenant.address is '地址'; +comment on column sys_tenant.intro is '企业简介'; +comment on column sys_tenant.remark is '备注'; +comment on column sys_tenant.package_id is '租户套餐编号'; +comment on column sys_tenant.expire_time is '过期时间'; +comment on column sys_tenant.account_count is '用户数量(-1不限制)'; +comment on column sys_tenant.status is '租户状态(0正常 1停用)'; +comment on column sys_tenant.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant.create_dept is '创建部门'; +comment on column sys_tenant.create_by is '创建者'; +comment on column sys_tenant.create_time is '创建时间'; +comment on column sys_tenant.update_by is '更新者'; +comment on column sys_tenant.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-租户表数据 +-- ---------------------------- + +insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有限公司', null, null, '多租户通用后台管理管理系统', null, null, null, null, -1, '0', '0', 103, 1, sysdate, null, null); + + +-- ---------------------------- +-- 租户套餐表 +-- ---------------------------- +create table sys_tenant_package ( + package_id number(20) not null, + package_name varchar2(20) default '', + menu_ids varchar2(3000) default '', + remark varchar2(200) default '', + menu_check_strictly number(1) default 1, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_tenant_package add constraint pk_sys_tenant_package primary key (package_id); + +comment on table sys_tenant_package is '租户套餐表'; +comment on column sys_tenant_package.package_id is '租户套餐id'; +comment on column sys_tenant_package.package_name is '套餐名称'; +comment on column sys_tenant_package.menu_ids is '关联菜单id'; +comment on column sys_tenant_package.remark is '备注'; +comment on column sys_tenant_package.status is '状态(0正常 1停用)'; +comment on column sys_tenant_package.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant_package.create_dept is '创建部门'; +comment on column sys_tenant_package.create_by is '创建者'; +comment on column sys_tenant_package.create_time is '创建时间'; +comment on column sys_tenant_package.update_by is '更新者'; +comment on column sys_tenant_package.update_time is '更新时间'; + + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table sys_dept ( + dept_id number(20) not null, + tenant_id varchar2(20) default '000000', + parent_id number(20) default 0, + ancestors varchar2(500) default '', + dept_name varchar2(30) default '', + dept_category varchar2(100) default null, + order_num number(4) default 0, + leader number(20) default null, + phone varchar2(11) default null, + email varchar2(50) default null, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_dept add constraint pk_sys_dept primary key (dept_id); + +comment on table sys_dept is '部门表'; +comment on column sys_dept.dept_id is '部门id'; +comment on column sys_dept.tenant_id is '租户编号'; +comment on column sys_dept.parent_id is '父部门id'; +comment on column sys_dept.ancestors is '祖级列表'; +comment on column sys_dept.dept_name is '部门名称'; +comment on column sys_dept.dept_category is '部门类别编码'; +comment on column sys_dept.order_num is '显示顺序'; +comment on column sys_dept.leader is '负责人'; +comment on column sys_dept.phone is '联系电话'; +comment on column sys_dept.email is '邮箱'; +comment on column sys_dept.status is '部门状态(0正常 1停用)'; +comment on column sys_dept.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_dept.create_dept is '创建部门'; +comment on column sys_dept.create_by is '创建者'; +comment on column sys_dept.create_time is '创建时间'; +comment on column sys_dept.update_by is '更新者'; +comment on column sys_dept.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- + +insert into sys_dept values(100, '000000', 0, '0', 'XXX科技', null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(101, '000000', 100, '0,100', '深圳总公司', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(102, '000000', 100, '0,100', '长沙分公司', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(103, '000000', 101, '0,100,101', '研发部门', null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(104, '000000', 101, '0,100,101', '市场部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(105, '000000', 101, '0,100,101', '测试部门', null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(106, '000000', 101, '0,100,101', '财务部门', null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(107, '000000', 101, '0,100,101', '运维部门', null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(108, '000000', 102, '0,100,102', '市场部门', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); +insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate, null, null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table sys_user ( + user_id number(20) not null, + tenant_id varchar2(20) default '000000', + dept_id number(20) default null, + user_name varchar2(40) not null, + nick_name varchar2(40) not null, + user_type varchar2(10) default 'sys_user', + email varchar2(50) default '', + phonenumber varchar2(11) default '', + sex char(1) default '0', + avatar number(20) default null, + password varchar2(100) default '', + status char(1) default '0', + del_flag char(1) default '0', + login_ip varchar2(128) default '', + login_date date, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default '' +); + +alter table sys_user add constraint pk_sys_user primary key (user_id); + +comment on table sys_user is '用户信息表'; +comment on column sys_user.user_id is '用户ID'; +comment on column sys_user.tenant_id is '租户编号'; +comment on column sys_user.dept_id is '部门ID'; +comment on column sys_user.user_name is '用户账号'; +comment on column sys_user.nick_name is '用户昵称'; +comment on column sys_user.user_type is '用户类型(sys_user系统用户)'; +comment on column sys_user.email is '用户邮箱'; +comment on column sys_user.phonenumber is '手机号码'; +comment on column sys_user.sex is '用户性别(0男 1女 2未知)'; +comment on column sys_user.avatar is '头像路径'; +comment on column sys_user.password is '密码'; +comment on column sys_user.status is '帐号状态(0正常 1停用)'; +comment on column sys_user.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_user.login_ip is '最后登录IP'; +comment on column sys_user.login_date is '最后登录时间'; +comment on column sys_user.create_dept is '创建部门'; +comment on column sys_user.create_by is '创建者'; +comment on column sys_user.create_time is '创建时间'; +comment on column sys_user.update_by is '更新者'; +comment on column sys_user.update_time is '更新时间'; +comment on column sys_user.remark is '备注'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, '管理员'); +insert into sys_user values(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, ''); +insert into sys_user values(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate, 103, 1, sysdate, null, null, ''); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table sys_post ( + post_id number(20) not null, + tenant_id varchar2(20) default '000000', + dept_id number(20) not null, + post_code varchar2(64) not null, + post_category varchar2(64) default null, + post_name varchar2(50) not null, + post_sort number(4) not null, + status char(1) not null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) +); + +alter table sys_post add constraint pk_sys_post primary key (post_id); + +comment on table sys_post is '岗位信息表'; +comment on column sys_post.post_id is '岗位ID'; +comment on column sys_post.tenant_id is '租户编号'; +comment on column sys_post.dept_id is '部门id'; +comment on column sys_post.post_code is '岗位编码'; +comment on column sys_post.post_category is '岗位类别编码'; +comment on column sys_post.post_name is '岗位名称'; +comment on column sys_post.post_sort is '显示顺序'; +comment on column sys_post.status is '状态(0正常 1停用)'; +comment on column sys_post.create_dept is '创建部门'; +comment on column sys_post.create_by is '创建者'; +comment on column sys_post.create_time is '创建时间'; +comment on column sys_post.update_by is '更新者'; +comment on column sys_post.update_time is '更新时间'; +comment on column sys_post.remark is '备注'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, '000000', 103, 'ceo', null, '董事长', 1, '0', 103, 1, sysdate, null, null, ''); +insert into sys_post values(2, '000000', 100, 'se', null, '项目经理', 2, '0', 103, 1, sysdate, null, null, ''); +insert into sys_post values(3, '000000', 100, 'hr', null, '人力资源', 3, '0', 103, 1, sysdate, null, null, ''); +insert into sys_post values(4, '000000', 100, 'user', null, '普通员工', 4, '0', 103, 1, sysdate, null, null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table sys_role ( + role_id number(20) not null, + tenant_id varchar2(20) default '000000', + role_name varchar2(30) not null, + role_key varchar2(100) not null, + role_sort number(4) not null, + data_scope char(1) default '1', + menu_check_strictly number(1) default 1, + dept_check_strictly number(1) default 1, + status char(1) not null, + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_role add constraint pk_sys_role primary key (role_id); + +comment on table sys_role is '角色信息表'; +comment on column sys_role.role_id is '角色ID'; +comment on column sys_role.tenant_id is '租户编号'; +comment on column sys_role.role_name is '角色名称'; +comment on column sys_role.role_key is '角色权限字符串'; +comment on column sys_role.role_sort is '显示顺序'; +comment on column sys_role.data_scope is '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +comment on column sys_role.menu_check_strictly is '菜单树选择项是否关联显示'; +comment on column sys_role.dept_check_strictly is '部门树选择项是否关联显示'; +comment on column sys_role.status is '角色状态(0正常 1停用)'; +comment on column sys_role.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_role.create_dept is '创建部门'; +comment on column sys_role.create_by is '创建者'; +comment on column sys_role.create_time is '创建时间'; +comment on column sys_role.update_by is '更新者'; +comment on column sys_role.update_time is '更新时间'; +comment on column sys_role.remark is '备注'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values('1', '000000', '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 103, 1, sysdate, null, null, '超级管理员'); +insert into sys_role values('3', '000000', '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate, null, null, null); +insert into sys_role values('4', '000000', '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate, null, null, null); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table sys_menu ( + menu_id number(20) not null, + menu_name varchar2(50) not null, + parent_id number(20) default 0, + order_num number(4) default 0, + path varchar2(200) default '', + component varchar2(255) default null, + query_param varchar2(255) default null, + is_frame number(1) default 1, + is_cache number(1) default 0, + menu_type char(1) default '', + visible char(1) default 0, + status char(1) default 0, + perms varchar2(100) default null, + icon varchar2(100) default '#', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date , + remark varchar2(500) default '' +); + +alter table sys_menu add constraint pk_sys_menu primary key (menu_id); + +comment on table sys_menu is '菜单权限表'; +comment on column sys_menu.menu_id is '菜单ID'; +comment on column sys_menu.menu_name is '菜单名称'; +comment on column sys_menu.parent_id is '父菜单ID'; +comment on column sys_menu.order_num is '显示顺序'; +comment on column sys_menu.path is '请求地址'; +comment on column sys_menu.component is '路由地址'; +comment on column sys_menu.query_param is '路由参数'; +comment on column sys_menu.is_frame is '是否为外链(0是 1否)'; +comment on column sys_menu.is_cache is '是否缓存(0缓存 1不缓存)'; +comment on column sys_menu.menu_type is '菜单类型(M目录 C菜单 F按钮)'; +comment on column sys_menu.visible is '显示状态(0显示 1隐藏)'; +comment on column sys_menu.status is '菜单状态(0正常 1停用)'; +comment on column sys_menu.perms is '权限标识'; +comment on column sys_menu.icon is '菜单图标'; +comment on column sys_menu.create_dept is '创建部门'; +comment on column sys_menu.create_by is '创建者'; +comment on column sys_menu.create_time is '创建时间'; +comment on column sys_menu.update_by is '更新者'; +comment on column sys_menu.update_time is '更新时间'; +comment on column sys_menu.remark is '备注'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', 1, 0, 'M', '0', '0', '', 'system', 103, 1, sysdate, null, null, '系统管理目录'); +insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', null, '', 1, 0, 'M', '0', '0', '', 'chart', 103, 1, sysdate, null, null, '租户管理目录'); +insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 103, 1, sysdate, null, null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 103, 1, sysdate, null, null, '系统工具目录'); +insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide', 103, 1, sysdate, null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu values('5', '测试菜单', '0', '5', 'demo', null, '', 1, 0, 'M', '0', '0', null, 'star', 103, 1, sysdate, null, null, ''); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 103, 1, sysdate, null, null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, sysdate, null, null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 103, 1, sysdate, null, null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, sysdate, null, null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 103, 1, sysdate, null, null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 103, 1, sysdate, null, null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 103, 1, sysdate, null, null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 103, 1, sysdate, null, null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 103, 1, sysdate, null, null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, sysdate, null, null, '在线用户菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, sysdate, null, null, '缓存监控菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, sysdate, null, null, '代码生成菜单'); +insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', 1, 0, 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, sysdate, null, null, '租户管理菜单'); +insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, sysdate, null, null, '租户套餐管理菜单'); +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate, null, null, '客户端管理菜单'); +-- springboot-admin监控 +insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', 'monitor/admin/index', '', 1, 0, 'C', '0', '0', 'monitor:admin:list', 'dashboard', 103, 1, sysdate, null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, sysdate, null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values('120', '任务调度中心', '2', '5', 'snailjob', 'monitor/snailjob/index', '', 1, 0, 'C', '0', '0', 'monitor:snailjob:list', 'job', 103, 1, sysdate, null, null, 'snailjob控制台菜单'); + +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, sysdate, null, null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 103, 1, sysdate, null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1001', '用户查询', '100', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1002', '用户新增', '100', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1003', '用户修改', '100', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1004', '用户删除', '100', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1005', '用户导出', '100', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1006', '用户导入', '100', '6', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1007', '重置密码', '100', '7', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 103, 1, sysdate, null, null, ''); +-- 角色管理按钮 +insert into sys_menu values('1008', '角色查询', '101', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1009', '角色新增', '101', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1010', '角色修改', '101', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1011', '角色删除', '101', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1012', '角色导出', '101', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 103, 1, sysdate, null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 103, 1, sysdate, null, null, ''); +-- 部门管理按钮 +insert into sys_menu values('1017', '部门查询', '103', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1018', '部门新增', '103', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1019', '部门修改', '103', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1020', '部门删除', '103', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 103, 1, sysdate, null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 103, 1, sysdate, null, null, ''); +-- 字典管理按钮 +insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 103, 1, sysdate, null, null, ''); +-- 参数设置按钮 +insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 103, 1, sysdate, null, null, ''); +-- 通知公告按钮 +insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 103, 1, sysdate, null, null, ''); +-- 操作日志按钮 +insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 103, 1, sysdate, null, null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate, null, null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, sysdate, null, null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 103, 1, sysdate, null, null, ''); +-- oss相关按钮 +insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove', '#', 103, 1, sysdate, null, null, ''); +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, ''); +-- 租户管理相关按钮 +insert into sys_menu values('1606', '租户查询', '121', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1607', '租户新增', '121', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1608', '租户修改', '121', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1609', '租户删除', '121', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1610', '租户导出', '121', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:export', '#', 103, 1, sysdate, null, null, ''); +-- 租户套餐管理相关按钮 +insert into sys_menu values('1611', '租户套餐查询', '122', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1612', '租户套餐新增', '122', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1613', '租户套餐修改', '122', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1614', '租户套餐删除', '122', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1615', '租户套餐导出', '122', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:export', '#', 103, 1, sysdate, null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate, null, null, ''); +-- 测试菜单 +insert into sys_menu values('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate, null, null, '测试单表菜单'); +insert into sys_menu values('1501', '测试单表查询', '1500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1502', '测试单表新增', '1500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1503', '测试单表修改', '1500', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1504', '测试单表删除', '1500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1505', '测试单表导出', '1500', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate, null, null, '测试树表菜单'); +insert into sys_menu values('1507', '测试树表查询', '1506', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1508', '测试树表新增', '1506', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1509', '测试树表修改', '1506', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1510', '测试树表删除', '1506', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1511', '测试树表导出', '1506', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate, null, null, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table sys_user_role ( + user_id number(20) not null, + role_id number(20) not null +); + +alter table sys_user_role add constraint pk_sys_user_role primary key (user_id, role_id); + +comment on table sys_user_role is '用户和角色关联表'; +comment on column sys_user_role.user_id is '用户ID'; +comment on column sys_user_role.role_id is '角色ID'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table sys_role_menu ( + role_id number(20) not null, + menu_id number(20) not null +); + +alter table sys_role_menu add constraint pk_sys_role_menu primary key (role_id, menu_id); + +comment on table sys_role_menu is '角色和菜单关联表'; +comment on column sys_role_menu.role_id is '角色ID'; +comment on column sys_role_menu.menu_id is '菜单ID'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '118'); +insert into sys_role_menu values ('3', '123'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1050'); +insert into sys_role_menu values ('3', '1061'); +insert into sys_role_menu values ('3', '1062'); +insert into sys_role_menu values ('3', '1063'); +insert into sys_role_menu values ('3', '1064'); +insert into sys_role_menu values ('3', '1065'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('3', '1600'); +insert into sys_role_menu values ('3', '1601'); +insert into sys_role_menu values ('3', '1602'); +insert into sys_role_menu values ('3', '1603'); +insert into sys_role_menu values ('3', '1620'); +insert into sys_role_menu values ('3', '1621'); +insert into sys_role_menu values ('3', '1622'); +insert into sys_role_menu values ('3', '1623'); +insert into sys_role_menu values ('3', '11618'); +insert into sys_role_menu values ('3', '11619'); +insert into sys_role_menu values ('3', '11629'); +insert into sys_role_menu values ('3', '11632'); +insert into sys_role_menu values ('3', '11633'); +insert into sys_role_menu values ('3', '11638'); +insert into sys_role_menu values ('3', '11639'); +insert into sys_role_menu values ('3', '11640'); +insert into sys_role_menu values ('3', '11641'); +insert into sys_role_menu values ('3', '11642'); +insert into sys_role_menu values ('3', '11643'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table sys_role_dept ( + role_id number(20) not null, + dept_id number(20) not null +); + +alter table sys_role_dept add constraint pk_sys_role_dept primary key (role_id, dept_id); + +comment on table sys_role_dept is '角色和部门关联表'; +comment on column sys_role_dept.role_id is '角色ID'; +comment on column sys_role_dept.dept_id is '部门ID'; + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table sys_user_post ( + user_id number(20) not null, + post_id number(20) not null +); + +alter table sys_user_post add constraint pk_sys_user_post primary key (user_id, post_id); + +comment on table sys_user_post is '用户与岗位关联表'; +comment on column sys_user_post.user_id is '用户ID'; +comment on column sys_user_post.post_id is '岗位ID'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table sys_oper_log ( + oper_id number(20) not null, + tenant_id varchar2(20) default '000000', + title varchar2(50) default '', + business_type number(2) default 0, + method varchar2(100) default '', + request_method varchar2(10) default '', + operator_type number(1) default 0, + oper_name varchar2(50) default '', + dept_name varchar2(50) default '', + oper_url varchar2(255) default '', + oper_ip varchar2(128) default '', + oper_location varchar2(255) default '', + oper_param varchar2(4000) default '', + json_result varchar2(4000) default '', + status number(1) default 0, + error_msg varchar2(4000) default '', + oper_time date, + cost_time number(20) default 0 +); + +alter table sys_oper_log add constraint pk_sys_oper_log primary key (oper_id); +create index idx_sys_oper_log_bt on sys_oper_log (business_type); +create index idx_sys_oper_log_s on sys_oper_log (status); +create index idx_sys_oper_log_ot on sys_oper_log (oper_time); + +comment on table sys_oper_log is '操作日志记录'; +comment on column sys_oper_log.oper_id is '日志主键'; +comment on column sys_oper_log.tenant_id is '租户编号'; +comment on column sys_oper_log.title is '模块标题'; +comment on column sys_oper_log.business_type is '业务类型(0其它 1新增 2修改 3删除)'; +comment on column sys_oper_log.method is '方法名称'; +comment on column sys_oper_log.request_method is '请求方式'; +comment on column sys_oper_log.operator_type is '操作类别(0其它 1后台用户 2手机端用户)'; +comment on column sys_oper_log.oper_name is '操作人员'; +comment on column sys_oper_log.dept_name is '部门名称'; +comment on column sys_oper_log.oper_url is '请求URL'; +comment on column sys_oper_log.oper_ip is '主机地址'; +comment on column sys_oper_log.oper_location is '操作地点'; +comment on column sys_oper_log.oper_param is '请求参数'; +comment on column sys_oper_log.json_result is '返回参数'; +comment on column sys_oper_log.status is '操作状态(0正常 1异常)'; +comment on column sys_oper_log.error_msg is '错误消息'; +comment on column sys_oper_log.oper_time is '操作时间'; +comment on column sys_oper_log.cost_time is '消耗时间'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table sys_dict_type ( + dict_id number(20) not null, + tenant_id varchar2(20) default '000000', + dict_name varchar2(100) default '', + dict_type varchar2(100) default '', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_dict_type add constraint pk_sys_dict_type primary key (dict_id); +create unique index sys_dict_type_index1 on sys_dict_type (tenant_id, dict_type); + +comment on table sys_dict_type is '字典类型表'; +comment on column sys_dict_type.dict_id is '字典主键'; +comment on column sys_dict_type.tenant_id is '租户编号'; +comment on column sys_dict_type.dict_name is '字典名称'; +comment on column sys_dict_type.dict_type is '字典类型'; +comment on column sys_dict_type.create_dept is '创建部门'; +comment on column sys_dict_type.create_by is '创建者'; +comment on column sys_dict_type.create_time is '创建时间'; +comment on column sys_dict_type.update_by is '更新者'; +comment on column sys_dict_type.update_time is '更新时间'; +comment on column sys_dict_type.remark is '备注'; + +insert into sys_dict_type values(1, '000000', '用户性别', 'sys_user_sex', 103, 1, sysdate, null, null, '用户性别列表'); +insert into sys_dict_type values(2, '000000', '菜单状态', 'sys_show_hide', 103, 1, sysdate, null, null, '菜单状态列表'); +insert into sys_dict_type values(3, '000000', '系统开关', 'sys_normal_disable', 103, 1, sysdate, null, null, '系统开关列表'); +insert into sys_dict_type values(6, '000000', '系统是否', 'sys_yes_no', 103, 1, sysdate, null, null, '系统是否列表'); +insert into sys_dict_type values(7, '000000', '通知类型', 'sys_notice_type', 103, 1, sysdate, null, null, '通知类型列表'); +insert into sys_dict_type values(8, '000000', '通知状态', 'sys_notice_status', 103, 1, sysdate, null, null, '通知状态列表'); +insert into sys_dict_type values(9, '000000', '操作类型', 'sys_oper_type', 103, 1, sysdate, null, null, '操作类型列表'); +insert into sys_dict_type values(10, '000000', '系统状态', 'sys_common_status', 103, 1, sysdate, null, null, '登录状态列表'); +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, sysdate, null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, sysdate, null, null, '客户端设备类型'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table sys_dict_data ( + dict_code number(20) not null, + tenant_id varchar2(20) default '000000', + dict_sort number(4) default 0, + dict_label varchar2(100) default '', + dict_value varchar2(100) default '', + dict_type varchar2(100) default '', + css_class varchar2(100) default null, + list_class varchar2(100) default null, + is_default char(1) default 'N', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table sys_dict_data add constraint pk_sys_dict_data primary key (dict_code); + +comment on table sys_dict_data is '字典数据表'; +comment on column sys_dict_data.dict_code is '字典主键'; +comment on column sys_dict_data.tenant_id is '租户编号'; +comment on column sys_dict_data.dict_sort is '字典排序'; +comment on column sys_dict_data.dict_label is '字典标签'; +comment on column sys_dict_data.dict_value is '字典键值'; +comment on column sys_dict_data.dict_type is '字典类型'; +comment on column sys_dict_data.css_class is '样式属性(其他样式扩展)'; +comment on column sys_dict_data.list_class is '表格回显样式'; +comment on column sys_dict_data.is_default is '是否默认(Y是 N否)'; +comment on column sys_dict_data.create_dept is '创建部门'; +comment on column sys_dict_data.create_by is '创建者'; +comment on column sys_dict_data.create_time is '创建时间'; +comment on column sys_dict_data.update_by is '更新者'; +comment on column sys_dict_data.update_time is '更新时间'; +comment on column sys_dict_data.remark is '备注'; + +insert into sys_dict_data values(1, '000000', 1, '男', '0', 'sys_user_sex', '', '', 'Y', 103, 1, sysdate, null, null, '性别男'); +insert into sys_dict_data values(2, '000000', 2, '女', '1', 'sys_user_sex', '', '', 'N', 103, 1, sysdate, null, null, '性别女'); +insert into sys_dict_data values(3, '000000', 3, '未知', '2', 'sys_user_sex', '', '', 'N', 103, 1, sysdate, null, null, '性别未知'); +insert into sys_dict_data values(4, '000000', 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 103, 1, sysdate, null, null, '显示菜单'); +insert into sys_dict_data values(5, '000000', 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 103, 1, sysdate, null, null, '隐藏菜单'); +insert into sys_dict_data values(6, '000000', 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 103, 1, sysdate, null, null, '正常状态'); +insert into sys_dict_data values(7, '000000', 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 103, 1, sysdate, null, null, '停用状态'); +insert into sys_dict_data values(12, '000000', 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 103, 1, sysdate, null, null, '系统默认是'); +insert into sys_dict_data values(13, '000000', 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 103, 1, sysdate, null, null, '系统默认否'); +insert into sys_dict_data values(14, '000000', 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 103, 1, sysdate, null, null, '通知'); +insert into sys_dict_data values(15, '000000', 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 103, 1, sysdate, null, null, '公告'); +insert into sys_dict_data values(16, '000000', 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 103, 1, sysdate, null, null, '正常状态'); +insert into sys_dict_data values(17, '000000', 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 103, 1, sysdate, null, null, '关闭状态'); +insert into sys_dict_data values(29, '000000', 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate, null, null, '其他操作'); +insert into sys_dict_data values(18, '000000', 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate, null, null, '新增操作'); +insert into sys_dict_data values(19, '000000', 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate, null, null, '修改操作'); +insert into sys_dict_data values(20, '000000', 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate, null, null, '删除操作'); +insert into sys_dict_data values(21, '000000', 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 103, 1, sysdate, null, null, '授权操作'); +insert into sys_dict_data values(22, '000000', 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate, null, null, '导出操作'); +insert into sys_dict_data values(23, '000000', 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate, null, null, '导入操作'); +insert into sys_dict_data values(24, '000000', 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate, null, null, '强退操作'); +insert into sys_dict_data values(25, '000000', 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate, null, null, '生成操作'); +insert into sys_dict_data values(26, '000000', 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate, null, null, '清空操作'); +insert into sys_dict_data values(27, '000000', 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 103, 1, sysdate, null, null, '正常状态'); +insert into sys_dict_data values(28, '000000', 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 103, 1, sysdate, null, null, '停用状态'); +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate, null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate, null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table sys_config ( + config_id number(20) not null, + tenant_id varchar2(20) default '000000', + config_name varchar2(100) default '', + config_key varchar2(100) default '', + config_value varchar2(100) default '', + config_type char(1) default 'N', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); +alter table sys_config add constraint pk_sys_config primary key (config_id); + +comment on table sys_config is '参数配置表'; +comment on column sys_config.config_id is '参数主键'; +comment on column sys_config.tenant_id is '租户编号'; +comment on column sys_config.config_name is '参数名称'; +comment on column sys_config.config_key is '参数键名'; +comment on column sys_config.config_value is '参数键值'; +comment on column sys_config.config_type is '系统内置(Y是 N否)'; +comment on column sys_config.create_dept is '创建部门'; +comment on column sys_config.create_by is '创建者'; +comment on column sys_config.create_time is '创建时间'; +comment on column sys_config.update_by is '更新者'; +comment on column sys_config.update_time is '更新时间'; +comment on column sys_config.remark is '备注'; + +insert into sys_config values(1, '000000', '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 103, 1, sysdate, null, null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '000000', '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 103, 1, sysdate, null, null, '初始化密码 123456' ); +insert into sys_config values(3, '000000', '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 103, 1, sysdate, null, null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(5, '000000', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 103, 1, sysdate, null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(11, '000000', 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 103, 1, sysdate, null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table sys_logininfor ( + info_id number(20) not null, + tenant_id varchar2(20) default '000000', + user_name varchar2(50) default '', + client_key varchar2(32) default '', + device_type varchar2(32) default '', + ipaddr varchar2(128) default '', + login_location varchar2(255) default '', + browser varchar2(50) default '', + os varchar2(50) default '', + status char(1) default '0', + msg varchar2(255) default '', + login_time date +); + +alter table sys_logininfor add constraint pk_sys_logininfor primary key (info_id); +create index idx_sys_logininfor_s on sys_logininfor (status); +create index idx_sys_logininfor_lt on sys_logininfor (login_time); + +comment on table sys_logininfor is '系统访问记录'; +comment on column sys_logininfor.info_id is '访问ID'; +comment on column sys_logininfor.tenant_id is '租户编号'; +comment on column sys_logininfor.user_name is '登录账号'; +comment on column sys_logininfor.client_key is '客户端'; +comment on column sys_logininfor.device_type is '设备类型'; +comment on column sys_logininfor.ipaddr is '登录IP地址'; +comment on column sys_logininfor.login_location is '登录地点'; +comment on column sys_logininfor.browser is '浏览器类型'; +comment on column sys_logininfor.os is '操作系统'; +comment on column sys_logininfor.status is '登录状态(0成功 1失败)'; +comment on column sys_logininfor.msg is '提示消息'; +comment on column sys_logininfor.login_time is '访问时间'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table sys_notice ( + notice_id number(20) not null, + tenant_id varchar2(20) default '000000', + notice_title varchar2(50) not null, + notice_type char(1) not null, + notice_content clob default null, + status char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(255) default null +); + +alter table sys_notice add constraint pk_sys_notice primary key (notice_id); + +comment on table sys_notice is '通知公告表'; +comment on column sys_notice.notice_id is '公告主键'; +comment on column sys_notice.tenant_id is '租户编号'; +comment on column sys_notice.notice_title is '公告标题'; +comment on column sys_notice.notice_type is '公告类型(1通知 2公告)'; +comment on column sys_notice.notice_content is '公告内容'; +comment on column sys_notice.status is '公告状态(0正常 1关闭)'; +comment on column sys_notice.create_dept is '创建部门'; +comment on column sys_notice.create_by is '创建者'; +comment on column sys_notice.create_time is '创建时间'; +comment on column sys_notice.update_by is '更新者'; +comment on column sys_notice.update_time is '更新时间'; +comment on column sys_notice.remark is '备注'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '000000', '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 103, 1, sysdate, null, null, '管理员'); +insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 103, 1, sysdate, null, null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +create table gen_table ( + table_id number(20) not null, + data_name varchar2(200) default '', + table_name varchar2(200) default '', + table_comment varchar2(500) default '', + sub_table_name varchar2(64) default null, + sub_table_fk_name varchar2(64) default null, + class_name varchar2(100) default '', + tpl_category varchar2(200) default 'crud', + package_name varchar2(100), + module_name varchar2(30), + business_name varchar2(30), + function_name varchar2(50), + function_author varchar2(50), + gen_type char(1) default '0', + gen_path varchar2(200) default '/', + options varchar2(1000), + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date, + remark varchar2(500) default null +); + +alter table gen_table add constraint pk_gen_table primary key (table_id); + +comment on table gen_table is '代码生成业务表'; +comment on column gen_table.table_id is '编号'; +comment on column gen_table.data_name is '数据源名称'; +comment on column gen_table.table_name is '表名称'; +comment on column gen_table.table_comment is '表描述'; +comment on column gen_table.sub_table_name is '关联子表的表名'; +comment on column gen_table.sub_table_fk_name is '子表关联的外键名'; +comment on column gen_table.class_name is '实体类名称'; +comment on column gen_table.tpl_category is '使用的模板(crud单表操作 tree树表操作)'; +comment on column gen_table.package_name is '生成包路径'; +comment on column gen_table.module_name is '生成模块名'; +comment on column gen_table.business_name is '生成业务名'; +comment on column gen_table.function_name is '生成功能名'; +comment on column gen_table.function_author is '生成功能作者'; +comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)'; +comment on column gen_table.gen_path is '生成路径(不填默认项目路径)'; +comment on column gen_table.options is '其它生成选项'; +comment on column gen_table.create_dept is '创建部门'; +comment on column gen_table.create_by is '创建者'; +comment on column gen_table.create_time is '创建时间'; +comment on column gen_table.update_by is '更新者'; +comment on column gen_table.update_time is '更新时间'; +comment on column gen_table.remark is '备注'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +create table gen_table_column ( + column_id number(20) not null, + table_id number(20), + column_name varchar2(200), + column_comment varchar2(500), + column_type varchar2(100), + java_type varchar2(500), + java_field varchar2(200), + is_pk char(1), + is_increment char(1), + is_required char(1), + is_insert char(1), + is_edit char(1), + is_list char(1), + is_query char(1), + query_type varchar2(200) default 'EQ', + html_type varchar2(200), + dict_type varchar2(200) default '', + sort number(4), + create_dept number(20) default null, + create_by number(20) default null, + create_time date , + update_by number(20) default null, + update_time date +); + +alter table gen_table_column add constraint pk_gen_table_column primary key (column_id); + +comment on table gen_table_column is '代码生成业务表字段'; +comment on column gen_table_column.column_id is '编号'; +comment on column gen_table_column.table_id is '归属表编号'; +comment on column gen_table_column.column_name is '列名称'; +comment on column gen_table_column.column_comment is '列描述'; +comment on column gen_table_column.column_type is '列类型'; +comment on column gen_table_column.java_type is 'JAVA类型'; +comment on column gen_table_column.java_field is 'JAVA字段名'; +comment on column gen_table_column.is_pk is '是否主键(1是)'; +comment on column gen_table_column.is_increment is '是否自增(1是)'; +comment on column gen_table_column.is_required is '是否必填(1是)'; +comment on column gen_table_column.is_insert is '是否为插入字段(1是)'; +comment on column gen_table_column.is_edit is '是否编辑字段(1是)'; +comment on column gen_table_column.is_list is '是否列表字段(1是)'; +comment on column gen_table_column.is_query is '是否查询字段(1是)'; +comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)'; +comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)'; +comment on column gen_table_column.dict_type is '字典类型'; +comment on column gen_table_column.sort is '排序'; +comment on column gen_table_column.create_dept is '创建部门'; +comment on column gen_table_column.create_by is '创建者'; +comment on column gen_table_column.create_time is '创建时间'; +comment on column gen_table_column.update_by is '更新者'; +comment on column gen_table_column.update_time is '更新时间'; + + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table sys_oss ( + oss_id number(20) not null, + tenant_id varchar2(20) default '000000', + file_name varchar2(255) not null, + original_name varchar2(255) not null, + file_suffix varchar2(10) not null, + url varchar2(500) not null, + service varchar2(20) default 'minio' not null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_oss add constraint pk_sys_oss primary key (oss_id); + +comment on table sys_oss is 'OSS对象存储表'; +comment on column sys_oss.oss_id is '对象存储主键'; +comment on column sys_oss.tenant_id is '租户编码'; +comment on column sys_oss.file_name is '文件名'; +comment on column sys_oss.original_name is '原名'; +comment on column sys_oss.file_suffix is '文件后缀名'; +comment on column sys_oss.url is 'URL地址'; +comment on column sys_oss.service is '服务商'; +comment on column sys_oss.create_dept is '创建部门'; +comment on column sys_oss.create_time is '创建时间'; +comment on column sys_oss.create_by is '上传者'; +comment on column sys_oss.update_time is '更新时间'; +comment on column sys_oss.update_by is '更新者'; + + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table sys_oss_config ( + oss_config_id number(20) not null, + tenant_id varchar2(20) default '000000', + config_key varchar2(20) not null, + access_key varchar2(255) default '', + secret_key varchar2(255) default '', + bucket_name varchar2(255) default '', + prefix varchar2(255) default '', + endpoint varchar2(255) default '', + domain varchar2(255) default '', + is_https char(1) default 'N', + region varchar2(255) default '', + access_policy char(1) default '1' not null, + status char(1) default '1', + ext1 varchar2(255) default '', + remark varchar2(500) default null, + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_oss_config add constraint pk_sys_oss_config primary key (oss_config_id); + +comment on table sys_oss_config is '对象存储配置表'; +comment on column sys_oss_config.oss_config_id is '主键'; +comment on column sys_oss_config.tenant_id is '租户编码'; +comment on column sys_oss_config.config_key is '配置key'; +comment on column sys_oss_config.access_key is 'accesskey'; +comment on column sys_oss_config.secret_key is '秘钥'; +comment on column sys_oss_config.bucket_name is '桶名称'; +comment on column sys_oss_config.prefix is '前缀'; +comment on column sys_oss_config.endpoint is '访问站点'; +comment on column sys_oss_config.domain is '自定义域名'; +comment on column sys_oss_config.is_https is '是否https(Y=是,N=否)'; +comment on column sys_oss_config.region is '域'; +comment on column sys_oss_config.access_policy is '桶权限类型(0=private 1=public 2=custom)'; +comment on column sys_oss_config.status is '是否默认(0=是,1=否)'; +comment on column sys_oss_config.ext1 is '扩展字段'; +comment on column sys_oss_config.remark is '备注'; +comment on column sys_oss_config.create_dept is '创建部门'; +comment on column sys_oss_config.create_by is '创建者'; +comment on column sys_oss_config.create_time is '创建时间'; +comment on column sys_oss_config.update_by is '更新者'; +comment on column sys_oss_config.update_time is '更新时间'; + +insert into sys_oss_config values (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '','N', '', '1', '0', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1250000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); +insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '','N', '', '1', '1', '', NULL, 103, 1, sysdate, 1, sysdate); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id number(20) not null, + client_id varchar2(64) default null, + client_key varchar2(32) default null, + client_secret varchar2(255) default null, + grant_type varchar2(255) default null, + device_type varchar2(32) default null, + active_timeout number(11) default 1800, + timeout number(11) default 604800, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_client add constraint pk_sys_client primary key (id); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); + +create table test_demo ( + id number(20) not null, + tenant_id varchar2(20) default '000000', + dept_id number(20) default null, + user_id number(20) default null, + order_num number(10) default 0, + test_key varchar2(255) default null, + value varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_demo add constraint pk_test_demo primary key (id); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.tenant_id is '租户编号'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table test_tree ( + id number(20) not null, + tenant_id varchar2(20) default '000000', + parent_id number(20) default 0, + dept_id number(20) default null, + user_id number(20) default null, + tree_name varchar2(255) default null, + version number(10) default 0, + create_dept number(20) default null, + create_time date, + create_by number(20) default null, + update_time date, + update_by number(20) default null, + del_flag number(2) default 0 +); + +alter table test_tree add constraint pk_test_tree primary key (id); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.tenant_id is '租户编号'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +insert into test_demo values (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate, 1, null, null, 0); +insert into test_demo values (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate, 1, null, null, 0); + +insert into test_tree values (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate, 1, null, null, 0); +insert into test_tree values (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate, 1, null, null, 0); + + +-- ---------------------------- +-- 钩子 ,用于session连接之后 自动设置默认的date类型格式化 简化时间查询 +-- 如需设置其它配置 可在此钩子内任意增加处理语句 +-- 例如: SELECT * FROM sys_user WHERE create_time BETWEEN '2022-03-01 00:00:00' AND '2022-04-01 00:00:00' +-- ---------------------------- +create or replace trigger login_trg +after logon on database +begin +execute immediate 'alter session set nls_date_format=''YYYY-MM-DD HH24:MI:SS'''; +end; diff --git a/script/sql/oracle/oracle_ry_workflow.sql b/script/sql/oracle/oracle_ry_workflow.sql new file mode 100644 index 0000000..b515b78 --- /dev/null +++ b/script/sql/oracle/oracle_ry_workflow.sql @@ -0,0 +1,414 @@ +create table FLOW_DEFINITION +( + ID NUMBER(20) not null, + FLOW_CODE VARCHAR2(40) not null, + FLOW_NAME VARCHAR2(100) not null, + CATEGORY VARCHAR2(100), + VERSION VARCHAR2(20) not null, + IS_PUBLISH NUMBER(1) default 0 not null, + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + ACTIVITY_STATUS NUMBER(1) default 1, + LISTENER_TYPE VARCHAR2(100), + LISTENER_PATH VARCHAR2(500), + EXT VARCHAR2(500), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_DEFINITION add constraint PK_FLOW_DEFINITION primary key (ID); + +comment on table FLOW_DEFINITION is '流程定义表'; +comment on column FLOW_DEFINITION.ID is '主键id'; +comment on column FLOW_DEFINITION.FLOW_CODE is '流程编码'; +comment on column FLOW_DEFINITION.FLOW_NAME is '流程名称'; +comment on column FLOW_DEFINITION.CATEGORY is '流程类别'; +comment on column FLOW_DEFINITION.VERSION is '流程版本'; +comment on column FLOW_DEFINITION.IS_PUBLISH is '是否发布 (0未发布 1已发布 9失效)'; +comment on column FLOW_DEFINITION.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_DEFINITION.FORM_PATH is '审批表单路径'; +comment on column FLOW_DEFINITION.ACTIVITY_STATUS is '流程激活状态(0挂起 1激活)'; +comment on column FLOW_DEFINITION.LISTENER_TYPE is '监听器类型'; +comment on column FLOW_DEFINITION.LISTENER_PATH is '监听器路径'; +comment on column FLOW_DEFINITION.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_DEFINITION.CREATE_TIME is '创建时间'; +comment on column FLOW_DEFINITION.UPDATE_TIME is '更新时间'; +comment on column FLOW_DEFINITION.DEL_FLAG is '删除标志'; +comment on column FLOW_DEFINITION.TENANT_ID is '租户id'; + +create table FLOW_NODE +( + ID NUMBER(20) not null, + NODE_TYPE NUMBER(1) not null, + DEFINITION_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100) not null, + NODE_NAME VARCHAR2(100), + NODE_RATIO NUMBER(6, 3), + COORDINATE VARCHAR2(100), + SKIP_ANY_NODE VARCHAR2(100) default 'N', + ANY_NODE_SKIP VARCHAR2(100), + LISTENER_TYPE VARCHAR2(100), + LISTENER_PATH VARCHAR2(500), + HANDLER_TYPE VARCHAR2(100), + HANDLER_PATH VARCHAR2(400), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + VERSION VARCHAR2(20), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40), + PERMISSION_FLAG VARCHAR2(200) +); + +alter table FLOW_NODE add constraint PK_FLOW_NODE primary key (ID); + +comment on table FLOW_NODE is '流程节点表'; +comment on column FLOW_NODE.ID is '主键id'; +comment on column FLOW_NODE.NODE_TYPE is '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_NODE.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_NODE.NODE_CODE is '流程节点编码'; +comment on column FLOW_NODE.NODE_NAME is '流程节点名称'; +comment on column FLOW_NODE.NODE_RATIO is '流程签署比例值'; +comment on column FLOW_NODE.COORDINATE is '坐标'; +comment on column FLOW_NODE.SKIP_ANY_NODE is '是否可以退回任意节点(Y是 N否)即将删除'; +comment on column FLOW_NODE.ANY_NODE_SKIP is '任意结点跳转'; +comment on column FLOW_NODE.LISTENER_TYPE is '监听器类型'; +comment on column FLOW_NODE.LISTENER_PATH is '监听器路径'; +comment on column FLOW_NODE.HANDLER_TYPE is '处理器类型'; +comment on column FLOW_NODE.HANDLER_PATH is '处理器路径'; +comment on column FLOW_NODE.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_NODE.FORM_PATH is '审批表单路径'; +comment on column FLOW_NODE.VERSION is '版本'; +comment on column FLOW_NODE.CREATE_TIME is '创建时间'; +comment on column FLOW_NODE.UPDATE_TIME is '更新时间'; +comment on column FLOW_NODE.DEL_FLAG is '删除标志'; +comment on column FLOW_NODE.TENANT_ID is '租户id'; +comment on column FLOW_NODE.PERMISSION_FLAG is '权限标识(权限类型:权限标识,可以多个,用逗号隔开)'; + +create table FLOW_SKIP +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + NOW_NODE_CODE VARCHAR2(100) not null, + NOW_NODE_TYPE NUMBER(1), + NEXT_NODE_CODE VARCHAR2(100) not null, + NEXT_NODE_TYPE NUMBER(1), + SKIP_NAME VARCHAR2(100), + SKIP_TYPE VARCHAR2(40), + SKIP_CONDITION VARCHAR2(200), + COORDINATE VARCHAR2(100), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_SKIP add constraint PK_FLOW_SKIP primary key (ID); + +comment on table FLOW_SKIP is '节点跳转关联表'; +comment on column FLOW_SKIP.ID is '主键id'; +comment on column FLOW_SKIP.DEFINITION_ID is '流程定义id'; +comment on column FLOW_SKIP.NOW_NODE_CODE is '当前流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.NOW_NODE_TYPE is '下一个流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.NEXT_NODE_CODE is '下一个流程节点编码'; +comment on column FLOW_SKIP.NEXT_NODE_TYPE is '下一个流程节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_SKIP.SKIP_NAME is '跳转名称'; +comment on column FLOW_SKIP.SKIP_TYPE is '跳转类型 (PASS审批通过 REJECT退回)'; +comment on column FLOW_SKIP.SKIP_CONDITION is '跳转条件'; +comment on column FLOW_SKIP.COORDINATE is '坐标'; +comment on column FLOW_SKIP.CREATE_TIME is '创建时间'; +comment on column FLOW_SKIP.UPDATE_TIME is '更新时间'; +comment on column FLOW_SKIP.DEL_FLAG is '删除标志'; +comment on column FLOW_SKIP.TENANT_ID is '租户id'; + +create table FLOW_INSTANCE +( + ID NUMBER not null, + DEFINITION_ID NUMBER not null, + BUSINESS_ID VARCHAR2(40) not null, + NODE_TYPE NUMBER(1), + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + VARIABLE CLOB, + FLOW_STATUS VARCHAR2(20), + ACTIVITY_STATUS NUMBER(1) default 1, + DEF_JSON CLOB, + CREATE_BY VARCHAR2(64) default '', + CREATE_TIME DATE, + UPDATE_TIME DATE, + EXT VARCHAR2(500), + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_INSTANCE add constraint PK_FLOW_INSTANCE primary key (ID); + +comment on table FLOW_INSTANCE is '流程实例表'; +comment on column FLOW_INSTANCE.ID is '主键id'; +comment on column FLOW_INSTANCE.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_INSTANCE.BUSINESS_ID is '业务id'; +comment on column FLOW_INSTANCE.NODE_TYPE is '开始节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_INSTANCE.NODE_CODE is '开始节点编码'; +comment on column FLOW_INSTANCE.NODE_NAME is '开始节点名称'; +comment on column FLOW_INSTANCE.VARIABLE is '任务变量'; +comment on column FLOW_INSTANCE.FLOW_STATUS is '流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回 8已完成 9已退回 10失效)'; +comment on column FLOW_INSTANCE.ACTIVITY_STATUS is '流程激活状态(0挂起 1激活)'; +comment on column FLOW_INSTANCE.DEF_JSON is '流程定义json'; +comment on column FLOW_INSTANCE.CREATE_BY is '创建者'; +comment on column FLOW_INSTANCE.CREATE_TIME is '创建时间'; +comment on column FLOW_INSTANCE.UPDATE_TIME is '更新时间'; +comment on column FLOW_INSTANCE.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_INSTANCE.DEL_FLAG is '删除标志'; +comment on column FLOW_INSTANCE.TENANT_ID is '租户id'; + +create table FLOW_TASK +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + INSTANCE_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + NODE_TYPE NUMBER(1), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_TASK add constraint PK_FLOW_TASK primary key (ID); + +comment on table FLOW_TASK is '待办任务表'; +comment on column FLOW_TASK.ID is '主键id'; +comment on column FLOW_TASK.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_TASK.INSTANCE_ID is '对应flow_instance表的id'; +comment on column FLOW_TASK.NODE_CODE is '节点编码'; +comment on column FLOW_TASK.NODE_NAME is '节点名称'; +comment on column FLOW_TASK.NODE_TYPE is '节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_TASK.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_TASK.FORM_PATH is '审批表单路径'; +comment on column FLOW_TASK.CREATE_TIME is '创建时间'; +comment on column FLOW_TASK.UPDATE_TIME is '更新时间'; +comment on column FLOW_TASK.DEL_FLAG is '删除标志'; +comment on column FLOW_TASK.TENANT_ID is '租户id'; + +create table FLOW_HIS_TASK +( + ID NUMBER(20) not null, + DEFINITION_ID NUMBER(20) not null, + INSTANCE_ID NUMBER(20) not null, + TASK_ID NUMBER(20) not null, + NODE_CODE VARCHAR2(100), + NODE_NAME VARCHAR2(100), + NODE_TYPE NUMBER(1), + TARGET_NODE_CODE VARCHAR2(200), + TARGET_NODE_NAME VARCHAR2(200), + APPROVER VARCHAR2(40), + COOPERATE_TYPE NUMBER(1) default 0, + COLLABORATOR VARCHAR2(40), + SKIP_TYPE VARCHAR2(10), + FLOW_STATUS VARCHAR2(20), + FORM_CUSTOM VARCHAR2(1) default 'N', + FORM_PATH VARCHAR2(100), + MESSAGE VARCHAR2(500), + VARIABLE CLOB, + EXT VARCHAR2(500), + CREATE_TIME DATE, + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) + +); + +alter table FLOW_HIS_TASK add constraint PK_FLOW_HIS_TASK primary key (ID); + +comment on table FLOW_HIS_TASK is '历史任务记录表'; +comment on column FLOW_HIS_TASK.ID is '主键id'; +comment on column FLOW_HIS_TASK.DEFINITION_ID is '对应flow_definition表的id'; +comment on column FLOW_HIS_TASK.INSTANCE_ID is '对应flow_instance表的id'; +comment on column FLOW_HIS_TASK.TASK_ID is '对应flow_task表的id'; +comment on column FLOW_HIS_TASK.NODE_CODE is '开始节点编码'; +comment on column FLOW_HIS_TASK.NODE_NAME is '开始节点名称'; +comment on column FLOW_HIS_TASK.NODE_TYPE is '开始节点类型 (0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +comment on column FLOW_HIS_TASK.TARGET_NODE_CODE is '目标节点编码'; +comment on column FLOW_HIS_TASK.TARGET_NODE_NAME is '目标节点名称'; +comment on column FLOW_HIS_TASK.SKIP_TYPE is '流转类型(PASS通过 REJECT退回 NONE无动作)'; +comment on column FLOW_HIS_TASK.FLOW_STATUS is '流程状态(1审批中 2 审批通过 9已退回 10失效)'; +comment on column FLOW_HIS_TASK.FORM_CUSTOM is '审批表单是否自定义 (Y是 N否)'; +comment on column FLOW_HIS_TASK.FORM_PATH is '审批表单路径'; +comment on column FLOW_HIS_TASK.MESSAGE is '审批意见'; +comment on column FLOW_HIS_TASK.VARIABLE is '任务变量'; +comment on column FLOW_HIS_TASK.EXT is '扩展字段,预留给业务系统使用'; +comment on column FLOW_HIS_TASK.CREATE_TIME is '任务开始时间'; +comment on column FLOW_HIS_TASK.UPDATE_TIME is '审批完成时间'; +comment on column FLOW_HIS_TASK.DEL_FLAG is '删除标志'; +comment on column FLOW_HIS_TASK.TENANT_ID is '租户id'; +comment on column FLOW_HIS_TASK.APPROVER is '审批者'; +comment on column FLOW_HIS_TASK.COOPERATE_TYPE is '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)'; +comment on column FLOW_HIS_TASK.COLLABORATOR is '协作人'; + +create table FLOW_USER +( + ID NUMBER(20) not null, + TYPE VARCHAR2(1) not null, + PROCESSED_BY VARCHAR2(80), + ASSOCIATED NUMBER(20) not null, + CREATE_TIME DATE, + CREATE_BY VARCHAR2(80), + UPDATE_TIME DATE, + DEL_FLAG VARCHAR2(1) default '0', + TENANT_ID VARCHAR2(40) +); + +alter table FLOW_USER add constraint PK_FLOW_USER primary key (ID); + +comment on table FLOW_USER is '待办任务表'; +comment on column FLOW_USER.ID is '主键id'; +comment on column FLOW_USER.TYPE is '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)'; +comment on column FLOW_USER.PROCESSED_BY is '权限人)'; +comment on column FLOW_USER.ASSOCIATED is '任务表id'; +comment on column FLOW_USER.CREATE_TIME is '创建时间'; +comment on column FLOW_USER.CREATE_BY is '节点名称'; +comment on column FLOW_USER.UPDATE_TIME is '更新时间'; +comment on column FLOW_USER.DEL_FLAG is '删除标志'; +comment on column FLOW_USER.TENANT_ID is '租户id'; + +create index USER_PROCESSED_TYPE on FLOW_USER (PROCESSED_BY, TYPE); + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +CREATE TABLE flow_category +( + category_id NUMBER (20) NOT NULL, + tenant_id VARCHAR2 (20) DEFAULT '000000', + parent_id NUMBER (20) DEFAULT 0, + ancestors VARCHAR2 (500) DEFAULT '', + category_name VARCHAR2 (30) NOT NULL, + order_num NUMBER (4) DEFAULT 0, + del_flag CHAR(1) DEFAULT '0', + create_dept NUMBER (20), + create_by NUMBER (20), + create_time DATE, + update_by NUMBER (20), + update_time DATE +); + +alter table flow_category add constraint pk_flow_category primary key (category_id); + +COMMENT ON TABLE flow_category IS '流程分类'; +COMMENT ON COLUMN flow_category.category_id IS '流程分类ID'; +COMMENT ON COLUMN flow_category.tenant_id IS '租户编号'; +COMMENT ON COLUMN flow_category.parent_id IS '父流程分类id'; +COMMENT ON COLUMN flow_category.ancestors IS '祖级列表'; +COMMENT ON COLUMN flow_category.category_name IS '流程分类名称'; +COMMENT ON COLUMN flow_category.order_num IS '显示顺序'; +COMMENT ON COLUMN flow_category.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_category.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_category.create_by IS '创建者'; +COMMENT ON COLUMN flow_category.create_time IS '创建时间'; +COMMENT ON COLUMN flow_category.update_by IS '更新者'; +COMMENT ON COLUMN flow_category.update_time IS '更新时间'; + +INSERT INTO flow_category VALUES (100, '000000', 0, '0', 'OA审批', 0, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (101, '000000', 100, '0,100', '假勤管理', 0, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (102, '000000', 100, '0,100', '人事管理', 1, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (103, '000000', 101, '0,100,101', '请假', 0, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (104, '000000', 101, '0,100,101', '出差', 1, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (105, '000000', 101, '0,100,101', '加班', 2, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (106, '000000', 101, '0,100,101', '换班', 3, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (107, '000000', 101, '0,100,101', '外出', 4, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (108, '000000', 102, '0,100,102', '转正', 1, '0', 103, 1, SYSDATE, NULL, NULL); +INSERT INTO flow_category VALUES (109, '000000', 102, '0,100,102', '离职', 2, '0', 103, 1, SYSDATE, NULL, NULL); + + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +CREATE TABLE test_leave +( + id NUMBER (20) NOT NULL, + tenant_id VARCHAR2 (20) DEFAULT '000000', + leave_type VARCHAR2 (255) NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + leave_days NUMBER (10) NOT NULL, + remark VARCHAR2 (255), + status VARCHAR2 (255), + create_dept NUMBER (20), + create_by NUMBER (20), + create_time DATE, + update_by NUMBER (20), + update_time DATE +); + +alter table test_leave add constraint pk_test_leave primary key (id); + +COMMENT ON TABLE test_leave IS '请假申请表'; +COMMENT ON COLUMN test_leave.id IS 'ID'; +COMMENT ON COLUMN test_leave.tenant_id IS '租户编号'; +COMMENT ON COLUMN test_leave.leave_type IS '请假类型'; +COMMENT ON COLUMN test_leave.start_date IS '开始时间'; +COMMENT ON COLUMN test_leave.end_date IS '结束时间'; +COMMENT ON COLUMN test_leave.leave_days IS '请假天数'; +COMMENT ON COLUMN test_leave.remark IS '请假原因'; +COMMENT ON COLUMN test_leave.status IS '状态'; +COMMENT ON COLUMN test_leave.create_dept IS '创建部门'; +COMMENT ON COLUMN test_leave.create_by IS '创建者'; +COMMENT ON COLUMN test_leave.create_time IS '创建时间'; +COMMENT ON COLUMN test_leave.update_by IS '更新者'; +COMMENT ON COLUMN test_leave.update_time IS '更新时间'; + +INSERT INTO sys_menu VALUES ('11616', '工作流', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_menu VALUES ('11623', '流程分类查询', '11622', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11624', '流程分类新增', '11622', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:add', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11625', '流程分类修改', '11622', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11627', '流程分类导出', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_menu VALUES ('11638', '请假申请', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, SYSDATE, NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu VALUES ('11639', '请假申请查询', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11640', '请假申请新增', '11638', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11641', '请假申请修改', '11638', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11642', '请假申请删除', '11638', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, SYSDATE, NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11643', '请假申请导出', '11638', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, SYSDATE, NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, SYSDATE, NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, SYSDATE, NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (15, '000000', '任务状态', 'wf_task_status', 103, 1, SYSDATE, NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, SYSDATE, NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '已完成'); +INSERT INTO sys_dict_data VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已作废'); +INSERT INTO sys_dict_data VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已退回'); +INSERT INTO sys_dict_data VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '动态表单'); +INSERT INTO sys_dict_data VALUES (48, '000000', 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (49, '000000', 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, SYSDATE, NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (50, '000000', 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (51, '000000', 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (52, '000000', 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (53, '000000', 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (54, '000000', 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (55, '000000', 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (56, '000000', 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (57, '000000', 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, SYSDATE, NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (58, '000000', 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (59, '000000', 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, SYSDATE, NULL, NULL, '超时'); diff --git a/script/sql/postgres/postgres_ry_job.sql b/script/sql/postgres/postgres_ry_job.sql new file mode 100644 index 0000000..1a08a99 --- /dev/null +++ b/script/sql/postgres/postgres_ry_job.sql @@ -0,0 +1,845 @@ +/* + SnailJob Database Transfer Tool + Source Server Type : MySQL + Target Server Type : PostgreSQL + Date: 2024-12-27 22:13:49 +*/ + + +-- sj_namespace +CREATE TABLE sj_namespace +( + id bigserial PRIMARY KEY, + name varchar(64) NOT NULL, + unique_id varchar(64) NOT NULL, + description varchar(256) NOT NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name); + +COMMENT ON COLUMN sj_namespace.id IS '主键'; +COMMENT ON COLUMN sj_namespace.name IS '名称'; +COMMENT ON COLUMN sj_namespace.unique_id IS '唯一id'; +COMMENT ON COLUMN sj_namespace.description IS '描述'; +COMMENT ON COLUMN sj_namespace.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_namespace.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_namespace.update_dt IS '修改时间'; +COMMENT ON TABLE sj_namespace IS '命名空间'; + +INSERT INTO sj_namespace VALUES (1, 'Development', 'dev', '', 0, now(), now()); +INSERT INTO sj_namespace VALUES (2, 'Production', 'prod', '', 0, now(), now()); + +-- sj_group_config +CREATE TABLE sj_group_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + description varchar(256) NOT NULL DEFAULT '', + token varchar(64) NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT', + group_status smallint NOT NULL DEFAULT 0, + version int NOT NULL, + group_partition int NOT NULL, + id_generator_mode smallint NOT NULL DEFAULT 1, + init_scene smallint NOT NULL DEFAULT 0, + bucket_index int NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_group_config.id IS '主键'; +COMMENT ON COLUMN sj_group_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_group_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_group_config.description IS '组描述'; +COMMENT ON COLUMN sj_group_config.token IS 'token'; +COMMENT ON COLUMN sj_group_config.group_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_group_config.version IS '版本号'; +COMMENT ON COLUMN sj_group_config.group_partition IS '分区'; +COMMENT ON COLUMN sj_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式'; +COMMENT ON COLUMN sj_group_config.init_scene IS '是否初始化场景 0:否 1:是'; +COMMENT ON COLUMN sj_group_config.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_group_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_group_config IS '组配置'; + +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()); + +-- sj_notify_config +CREATE TABLE sj_notify_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + notify_name varchar(64) NOT NULL DEFAULT '', + system_task_type smallint NOT NULL DEFAULT 3, + notify_status smallint NOT NULL DEFAULT 0, + recipient_ids varchar(128) NOT NULL, + notify_threshold int NOT NULL DEFAULT 0, + notify_scene smallint NOT NULL DEFAULT 0, + rate_limiter_status smallint NOT NULL DEFAULT 0, + rate_limiter_threshold int NOT NULL DEFAULT 0, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name); + +COMMENT ON COLUMN sj_notify_config.id IS '主键'; +COMMENT ON COLUMN sj_notify_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_notify_config.notify_name IS '通知名称'; +COMMENT ON COLUMN sj_notify_config.system_task_type IS '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_notify_config.notify_status IS '通知状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.recipient_ids IS '接收人id列表'; +COMMENT ON COLUMN sj_notify_config.notify_threshold IS '通知阈值'; +COMMENT ON COLUMN sj_notify_config.notify_scene IS '通知场景'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '每秒限流阈值'; +COMMENT ON COLUMN sj_notify_config.description IS '描述'; +COMMENT ON COLUMN sj_notify_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_config IS '通知配置'; + +-- sj_notify_recipient +CREATE TABLE sj_notify_recipient +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + recipient_name varchar(64) NOT NULL, + notify_type smallint NOT NULL DEFAULT 0, + notify_attribute varchar(512) NOT NULL, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id); + +COMMENT ON COLUMN sj_notify_recipient.id IS '主键'; +COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称'; +COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook'; +COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性'; +COMMENT ON COLUMN sj_notify_recipient.description IS '描述'; +COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_notify_recipient.update_dt IS '修改时间'; +COMMENT ON TABLE sj_notify_recipient IS '告警通知接收人'; + +-- sj_retry_dead_letter_0 +CREATE TABLE sj_retry_dead_letter_0 +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_name varchar(64) NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + args_str text NOT NULL, + ext_attrs text NOT NULL, + task_type smallint NOT NULL DEFAULT 1, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_dead_letter_0_01 ON sj_retry_dead_letter_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_dead_letter_0_02 ON sj_retry_dead_letter_0 (idempotent_id); +CREATE INDEX idx_sj_retry_dead_letter_0_03 ON sj_retry_dead_letter_0 (biz_no); +CREATE INDEX idx_sj_retry_dead_letter_0_04 ON sj_retry_dead_letter_0 (create_dt); + +COMMENT ON COLUMN sj_retry_dead_letter_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_dead_letter_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_dead_letter_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_dead_letter_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_dead_letter_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_dead_letter_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_dead_letter_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_dead_letter_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_dead_letter_0.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_dead_letter_0 IS '死信队列表'; + +-- sj_retry_task_0 +CREATE TABLE sj_retry_task_0 +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_name varchar(64) NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + args_str text NOT NULL, + ext_attrs text NOT NULL, + next_trigger_at timestamp NOT NULL, + retry_count int NOT NULL DEFAULT 0, + retry_status smallint NOT NULL DEFAULT 0, + task_type smallint NOT NULL DEFAULT 1, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, unique_id); + +CREATE INDEX idx_sj_retry_task_0_01 ON sj_retry_task_0 (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_0_02 ON sj_retry_task_0 (namespace_id, group_name, task_type); +CREATE INDEX idx_sj_retry_task_0_03 ON sj_retry_task_0 (namespace_id, group_name, retry_status); +CREATE INDEX idx_sj_retry_task_0_04 ON sj_retry_task_0 (idempotent_id); +CREATE INDEX idx_sj_retry_task_0_05 ON sj_retry_task_0 (biz_no); +CREATE INDEX idx_sj_retry_task_0_06 ON sj_retry_task_0 (create_dt); + +COMMENT ON COLUMN sj_retry_task_0.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_0.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_0.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_0.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_0.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_0.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_0.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_0.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_0.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_0.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_0.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_retry_task_0.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_retry_task_0.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数'; +COMMENT ON COLUMN sj_retry_task_0.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_0.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_0.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_0 IS '任务表'; + +-- sj_retry_task_log +CREATE TABLE sj_retry_task_log +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + unique_id varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_name varchar(64) NOT NULL, + idempotent_id varchar(64) NOT NULL, + biz_no varchar(64) NOT NULL DEFAULT '', + executor_name varchar(512) NOT NULL DEFAULT '', + args_str text NOT NULL, + ext_attrs text NOT NULL, + retry_status smallint NOT NULL DEFAULT 0, + task_type smallint NOT NULL DEFAULT 1, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_retry_task_log_01 ON sj_retry_task_log (namespace_id, group_name, scene_name); +CREATE INDEX idx_sj_retry_task_log_02 ON sj_retry_task_log (retry_status); +CREATE INDEX idx_sj_retry_task_log_03 ON sj_retry_task_log (idempotent_id); +CREATE INDEX idx_sj_retry_task_log_04 ON sj_retry_task_log (unique_id); +CREATE INDEX idx_sj_retry_task_log_05 ON sj_retry_task_log (biz_no); +CREATE INDEX idx_sj_retry_task_log_06 ON sj_retry_task_log (create_dt); + +COMMENT ON COLUMN sj_retry_task_log.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_task_log.idempotent_id IS '幂等id'; +COMMENT ON COLUMN sj_retry_task_log.biz_no IS '业务编号'; +COMMENT ON COLUMN sj_retry_task_log.executor_name IS '执行器名称'; +COMMENT ON COLUMN sj_retry_task_log.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_retry_task_log.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_retry_task_log.retry_status IS '重试状态 0、重试中 1、成功 2、最大次数'; +COMMENT ON COLUMN sj_retry_task_log.task_type IS '任务类型 1、重试数据 2、回调数据'; +COMMENT ON COLUMN sj_retry_task_log.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_task_log.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_task_log IS '任务日志基础信息表'; + +-- sj_retry_task_log_message +CREATE TABLE sj_retry_task_log_message +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + unique_id varchar(64) NOT NULL, + message text NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, unique_id); +CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt); + +COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键'; +COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_task_log_message.unique_id IS '同组下id唯一'; +COMMENT ON COLUMN sj_retry_task_log_message.message IS '异常信息'; +COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_retry_task_log_message IS '任务调度日志信息记录表'; + +-- sj_retry_scene_config +CREATE TABLE sj_retry_scene_config +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + scene_name varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + scene_status smallint NOT NULL DEFAULT 0, + max_retry_count int NOT NULL DEFAULT 5, + back_off smallint NOT NULL DEFAULT 1, + trigger_interval varchar(16) NOT NULL DEFAULT '', + notify_ids varchar(128) NOT NULL DEFAULT '', + deadline_request bigint NOT NULL DEFAULT 60000, + executor_timeout int NOT NULL DEFAULT 5, + route_key smallint NOT NULL DEFAULT 4, + description varchar(256) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name); + +COMMENT ON COLUMN sj_retry_scene_config.id IS '主键'; +COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_scene_config.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '组状态 0、未启用 1、启用'; +COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '最大重试次数'; +COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式'; +COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒'; +COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_retry_scene_config.route_key IS '路由策略'; +COMMENT ON COLUMN sj_retry_scene_config.description IS '描述'; +COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_scene_config IS '场景配置'; + +-- sj_server_node +CREATE TABLE sj_server_node +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + host_id varchar(64) NOT NULL, + host_ip varchar(64) NOT NULL, + host_port int NOT NULL, + expire_at timestamp NOT NULL, + node_type smallint NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip); + +CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name); +CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type); + +COMMENT ON COLUMN sj_server_node.id IS '主键'; +COMMENT ON COLUMN sj_server_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_server_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_server_node.host_id IS '主机id'; +COMMENT ON COLUMN sj_server_node.host_ip IS '机器ip'; +COMMENT ON COLUMN sj_server_node.host_port IS '机器端口'; +COMMENT ON COLUMN sj_server_node.expire_at IS '过期时间'; +COMMENT ON COLUMN sj_server_node.node_type IS '节点类型 1、客户端 2、是服务端'; +COMMENT ON COLUMN sj_server_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_server_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_server_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_server_node IS '服务器节点'; + +-- sj_distributed_lock +CREATE TABLE sj_distributed_lock +( + name varchar(64) PRIMARY KEY, + lock_until timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + locked_at timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + locked_by varchar(255) NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称'; +COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长'; +COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间'; +COMMENT ON COLUMN sj_distributed_lock.locked_by IS '锁定者'; +COMMENT ON COLUMN sj_distributed_lock.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_distributed_lock.update_dt IS '修改时间'; +COMMENT ON TABLE sj_distributed_lock IS '锁定表'; + +-- sj_system_user +CREATE TABLE sj_system_user +( + id bigserial PRIMARY KEY, + username varchar(64) NOT NULL, + password varchar(128) NOT NULL, + role smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +COMMENT ON COLUMN sj_system_user.id IS '主键'; +COMMENT ON COLUMN sj_system_user.username IS '账号'; +COMMENT ON COLUMN sj_system_user.password IS '密码'; +COMMENT ON COLUMN sj_system_user.role IS '角色:1-普通用户、2-管理员'; +COMMENT ON COLUMN sj_system_user.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user IS '系统用户表'; + +-- pwd: admin +INSERT INTO sj_system_user VALUES (1, 'admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2, now(), now()); + +-- sj_system_user_permission +CREATE TABLE sj_system_user_permission +( + id bigserial PRIMARY KEY, + group_name varchar(64) NOT NULL, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + system_user_id bigint NOT NULL, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id); + +COMMENT ON COLUMN sj_system_user_permission.id IS '主键'; +COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称'; +COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '系统用户id'; +COMMENT ON COLUMN sj_system_user_permission.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_system_user_permission.update_dt IS '修改时间'; +COMMENT ON TABLE sj_system_user_permission IS '系统用户权限表'; + +-- sj_sequence_alloc +CREATE TABLE sj_sequence_alloc +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + max_id bigint NOT NULL DEFAULT 1, + step int NOT NULL DEFAULT 100, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name); + +COMMENT ON COLUMN sj_sequence_alloc.id IS '主键'; +COMMENT ON COLUMN sj_sequence_alloc.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_sequence_alloc.group_name IS '组名称'; +COMMENT ON COLUMN sj_sequence_alloc.max_id IS '最大id'; +COMMENT ON COLUMN sj_sequence_alloc.step IS '步长'; +COMMENT ON COLUMN sj_sequence_alloc.update_dt IS '更新时间'; +COMMENT ON TABLE sj_sequence_alloc IS '号段模式序号ID分配表'; + +-- sj_job +CREATE TABLE sj_job +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_name varchar(64) NOT NULL, + args_str text NULL DEFAULT NULL, + args_type smallint NOT NULL DEFAULT 1, + next_trigger_at bigint NOT NULL, + job_status smallint NOT NULL DEFAULT 1, + task_type smallint NOT NULL DEFAULT 1, + route_key smallint NOT NULL DEFAULT 4, + executor_type smallint NOT NULL DEFAULT 1, + executor_info varchar(255) NULL DEFAULT NULL, + trigger_type smallint NOT NULL, + trigger_interval varchar(255) NOT NULL, + block_strategy smallint 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 smallint NOT NULL DEFAULT 0, + notify_ids varchar(128) NOT NULL DEFAULT '', + owner_id bigint NULL, + description varchar(256) NOT NULL DEFAULT '', + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name); +CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index); +CREATE INDEX idx_sj_job_03 ON sj_job (create_dt); + +COMMENT ON COLUMN sj_job.id IS '主键'; +COMMENT ON COLUMN sj_job.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job.group_name IS '组名称'; +COMMENT ON COLUMN sj_job.job_name IS '名称'; +COMMENT ON COLUMN sj_job.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_job.job_status IS '任务状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_job.task_type IS '任务类型 1、集群 2、广播 3、切片'; +COMMENT ON COLUMN sj_job.route_key IS '路由策略'; +COMMENT ON COLUMN sj_job.executor_type IS '执行器类型'; +COMMENT ON COLUMN sj_job.executor_info IS '执行器名称'; +COMMENT ON COLUMN sj_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_job.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_job.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_job.max_retry_times IS '最大重试次数'; +COMMENT ON COLUMN sj_job.parallel_num IS '并行数'; +COMMENT ON COLUMN sj_job.retry_interval IS '重试间隔 ( s ) '; +COMMENT ON COLUMN sj_job.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_job.resident IS '是否是常驻任务'; +COMMENT ON COLUMN sj_job.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_job.owner_id IS '负责人id'; +COMMENT ON COLUMN sj_job.description IS '描述'; +COMMENT ON COLUMN sj_job.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job IS '任务信息'; + +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()); + +-- sj_job_log_message +CREATE TABLE sj_job_log_message +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + task_id bigint NOT NULL, + message text NOT NULL, + log_num int NOT NULL DEFAULT 1, + real_time bigint NOT NULL DEFAULT 0, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id); +CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt); +CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_log_message.id IS '主键'; +COMMENT ON COLUMN sj_job_log_message.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_log_message.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_log_message.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '任务批次id'; +COMMENT ON COLUMN sj_job_log_message.task_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_log_message.message IS '调度信息'; +COMMENT ON COLUMN sj_job_log_message.log_num IS '日志数量'; +COMMENT ON COLUMN sj_job_log_message.real_time IS '上报时间'; +COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_log_message.create_dt IS '创建时间'; +COMMENT ON TABLE sj_job_log_message IS '调度日志'; + +-- sj_job_task +CREATE TABLE sj_job_task +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + task_batch_id bigint NOT NULL, + parent_id bigint NOT NULL DEFAULT 0, + task_status smallint NOT NULL DEFAULT 0, + retry_count int NOT NULL DEFAULT 0, + mr_stage smallint NULL DEFAULT NULL, + leaf smallint NOT NULL DEFAULT '1', + task_name varchar(255) NOT NULL DEFAULT '', + client_info varchar(128) NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + result_message text NOT NULL, + args_str text NULL DEFAULT NULL, + args_type smallint NOT NULL DEFAULT 1, + ext_attrs varchar(256) NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status); +CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt); +CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name); + +COMMENT ON COLUMN sj_job_task.id IS '主键'; +COMMENT ON COLUMN sj_job_task.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id'; +COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id'; +COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数'; +COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce'; +COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点'; +COMMENT ON COLUMN sj_job_task.task_name IS '任务名称'; +COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port'; +COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文'; +COMMENT ON COLUMN sj_job_task.result_message IS '执行结果'; +COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数'; +COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 '; +COMMENT ON COLUMN sj_job_task.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task IS '任务实例'; + +-- sj_job_task_batch +CREATE TABLE sj_job_task_batch +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(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 smallint NOT NULL DEFAULT 0, + operation_reason smallint NOT NULL DEFAULT 0, + execution_at bigint NOT NULL DEFAULT 0, + system_task_type smallint NOT NULL DEFAULT 3, + parent_id varchar(64) NOT NULL DEFAULT '', + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status); +CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt); +CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name); +CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id); + +COMMENT ON COLUMN sj_job_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_task_batch.job_id IS '任务id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '工作流节点id'; +COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '工作流任务父批次id'; +COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '工作流任务批次id'; +COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_job_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_task_batch.parent_id IS '父节点'; +COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_job_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_job_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_task_batch IS '任务批次'; + +-- sj_job_summary +CREATE TABLE sj_job_summary +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + business_id bigint NOT NULL, + system_task_type smallint NOT NULL DEFAULT 3, + trigger_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + success_num int NOT NULL DEFAULT 0, + fail_num int NOT NULL DEFAULT 0, + fail_reason varchar(512) NOT NULL DEFAULT '', + stop_num int NOT NULL DEFAULT 0, + stop_reason varchar(512) NOT NULL DEFAULT '', + cancel_num int NOT NULL DEFAULT 0, + cancel_reason varchar(512) NOT NULL DEFAULT '', + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id); + +CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id); + +COMMENT ON COLUMN sj_job_summary.id IS '主键'; +COMMENT ON COLUMN sj_job_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_job_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_job_summary.business_id IS '业务id ( job_id或workflow_id ) '; +COMMENT ON COLUMN sj_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务'; +COMMENT ON COLUMN sj_job_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_job_summary.success_num IS '执行成功-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.fail_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.stop_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.stop_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.cancel_num IS '执行失败-日志数量'; +COMMENT ON COLUMN sj_job_summary.cancel_reason IS '失败原因'; +COMMENT ON COLUMN sj_job_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_job_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job'; + +-- sj_retry_summary +CREATE TABLE sj_retry_summary +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL DEFAULT '', + scene_name varchar(50) NOT NULL DEFAULT '', + trigger_at timestamp 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 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at); + +CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at); + +COMMENT ON COLUMN sj_retry_summary.id IS '主键'; +COMMENT ON COLUMN sj_retry_summary.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_retry_summary.group_name IS '组名称'; +COMMENT ON COLUMN sj_retry_summary.scene_name IS '场景名称'; +COMMENT ON COLUMN sj_retry_summary.trigger_at IS '统计时间'; +COMMENT ON COLUMN sj_retry_summary.running_num IS '重试中-日志数量'; +COMMENT ON COLUMN sj_retry_summary.finish_num IS '重试完成-日志数量'; +COMMENT ON COLUMN sj_retry_summary.max_count_num IS '重试到达最大次数-日志数量'; +COMMENT ON COLUMN sj_retry_summary.suspend_num IS '暂停重试-日志数量'; +COMMENT ON COLUMN sj_retry_summary.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_retry_summary.update_dt IS '修改时间'; +COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry'; + +-- sj_workflow +CREATE TABLE sj_workflow +( + id bigserial PRIMARY KEY, + workflow_name varchar(64) NOT NULL, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + workflow_status smallint NOT NULL DEFAULT 1, + trigger_type smallint NOT NULL, + trigger_interval varchar(255) NOT NULL, + next_trigger_at bigint NOT NULL, + block_strategy smallint NOT NULL DEFAULT 1, + executor_timeout int NOT NULL DEFAULT 0, + description varchar(256) NOT NULL DEFAULT '', + flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + notify_ids varchar(128) NOT NULL DEFAULT '', + bucket_index int NOT NULL DEFAULT 0, + version int NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt); +CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow.id IS '主键'; +COMMENT ON COLUMN sj_workflow.workflow_name IS '工作流名称'; +COMMENT ON COLUMN sj_workflow.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow.workflow_status IS '工作流状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间'; +COMMENT ON COLUMN sj_workflow.trigger_interval IS '间隔时长'; +COMMENT ON COLUMN sj_workflow.next_trigger_at IS '下次触发时间'; +COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行'; +COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒'; +COMMENT ON COLUMN sj_workflow.description IS '描述'; +COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow.wf_context IS '上下文'; +COMMENT ON COLUMN sj_workflow.notify_ids IS '通知告警场景配置id列表'; +COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket'; +COMMENT ON COLUMN sj_workflow.version IS '版本号'; +COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow IS '工作流'; + +-- sj_workflow_node +CREATE TABLE sj_workflow_node +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + node_name varchar(64) NOT NULL, + group_name varchar(64) NOT NULL, + job_id bigint NOT NULL, + workflow_id bigint NOT NULL, + node_type smallint NOT NULL DEFAULT 1, + expression_type smallint NOT NULL DEFAULT 0, + fail_strategy smallint NOT NULL DEFAULT 1, + workflow_node_status smallint NOT NULL DEFAULT 1, + priority_level int NOT NULL DEFAULT 1, + node_info text NULL DEFAULT NULL, + version int NOT NULL, + ext_attrs varchar(256) NULL DEFAULT '', + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt); +CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_node.id IS '主键'; +COMMENT ON COLUMN sj_workflow_node.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_node.node_name IS '节点名称'; +COMMENT ON COLUMN sj_workflow_node.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_node.job_id IS '任务信息id'; +COMMENT ON COLUMN sj_workflow_node.workflow_id IS '工作流ID'; +COMMENT ON COLUMN sj_workflow_node.node_type IS '1、任务节点 2、条件节点'; +COMMENT ON COLUMN sj_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL'; +COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞'; +COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启'; +COMMENT ON COLUMN sj_workflow_node.priority_level IS '优先级'; +COMMENT ON COLUMN sj_workflow_node.node_info IS '节点信息 '; +COMMENT ON COLUMN sj_workflow_node.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_node.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_node.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_node.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_node IS '工作流节点'; + +-- sj_workflow_task_batch +CREATE TABLE sj_workflow_task_batch +( + id bigserial PRIMARY KEY, + namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a', + group_name varchar(64) NOT NULL, + workflow_id bigint NOT NULL, + task_batch_status smallint NOT NULL DEFAULT 0, + operation_reason smallint NOT NULL DEFAULT 0, + flow_info text NULL DEFAULT NULL, + wf_context text NULL DEFAULT NULL, + execution_at bigint NOT NULL DEFAULT 0, + ext_attrs varchar(256) NULL DEFAULT '', + version int NOT NULL DEFAULT 1, + deleted smallint NOT NULL DEFAULT 0, + create_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + update_dt timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status); +CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt); +CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name); + +COMMENT ON COLUMN sj_workflow_task_batch.id IS '主键'; +COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '命名空间id'; +COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '组名称'; +COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id'; +COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功'; +COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因'; +COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息'; +COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文'; +COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间'; +COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段'; +COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号'; +COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除'; +COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间'; +COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间'; +COMMENT ON TABLE sj_workflow_task_batch IS '工作流批次'; diff --git a/script/sql/postgres/postgres_ry_vue_5.X.sql b/script/sql/postgres/postgres_ry_vue_5.X.sql new file mode 100644 index 0000000..d18cfeb --- /dev/null +++ b/script/sql/postgres/postgres_ry_vue_5.X.sql @@ -0,0 +1,1383 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id int8 not null, + user_id int8 not null, + tenant_id varchar(20) default '000000'::varchar, + auth_id varchar(255) not null, + source varchar(255) not null, + open_id varchar(255) default null::varchar, + user_name varchar(30) not null, + nick_name varchar(30) default ''::varchar, + email varchar(255) default ''::varchar, + avatar varchar(500) default ''::varchar, + access_token varchar(255) not null, + expire_in int8 default null, + refresh_token varchar(255) default null::varchar, + access_code varchar(255) default null::varchar, + union_id varchar(255) default null::varchar, + scope varchar(255) default null::varchar, + token_type varchar(255) default null::varchar, + id_token varchar(2000) default null::varchar, + mac_algorithm varchar(255) default null::varchar, + mac_key varchar(255) default null::varchar, + code varchar(255) default null::varchar, + oauth_token varchar(255) default null::varchar, + oauth_token_secret varchar(255) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + del_flag char default '0'::bpchar, + constraint "pk_sys_social" primary key (id) +); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 1代表删除)'; + +-- ---------------------------- +-- 租户表 +-- ---------------------------- +create table if not exists sys_tenant +( + id int8, + tenant_id varchar(20) not null, + contact_user_name varchar(20) default null::varchar, + contact_phone varchar(20) default null::varchar, + company_name varchar(50) default null::varchar, + license_number varchar(30) default null::varchar, + address varchar(200) default null::varchar, + intro varchar(200) default null::varchar, + domain varchar(200) default null::varchar, + remark varchar(200) default null::varchar, + package_id int8, + expire_time timestamp, + account_count int4 default -1, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint "pk_sys_tenant" primary key (id) +); + + +comment on table sys_tenant is '租户表'; +comment on column sys_tenant.tenant_id is '租户编号'; +comment on column sys_tenant.contact_phone is '联系电话'; +comment on column sys_tenant.company_name is '企业名称'; +comment on column sys_tenant.company_name is '联系人'; +comment on column sys_tenant.license_number is '统一社会信用代码'; +comment on column sys_tenant.address is '地址'; +comment on column sys_tenant.intro is '企业简介'; +comment on column sys_tenant.domain is '域名'; +comment on column sys_tenant.remark is '备注'; +comment on column sys_tenant.package_id is '租户套餐编号'; +comment on column sys_tenant.expire_time is '过期时间'; +comment on column sys_tenant.account_count is '用户数量(-1不限制)'; +comment on column sys_tenant.status is '租户状态(0正常 1停用)'; +comment on column sys_tenant.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant.create_dept is '创建部门'; +comment on column sys_tenant.create_by is '创建者'; +comment on column sys_tenant.create_time is '创建时间'; +comment on column sys_tenant.update_by is '更新者'; +comment on column sys_tenant.update_time is '更新时间'; + + +-- ---------------------------- +-- 初始化-租户表数据 +-- ---------------------------- + +insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有限公司', null, null, '多租户通用后台管理管理系统', null, null, null, null, -1, '0', '0', 103, 1, now(), null, null); + + +-- ---------------------------- +-- 租户套餐表 +-- ---------------------------- +create table if not exists sys_tenant_package +( + package_id int8, + package_name varchar(20) default ''::varchar, + menu_ids varchar(3000) default ''::varchar, + remark varchar(200) default ''::varchar, + menu_check_strictly bool default true, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint "pk_sys_tenant_package" primary key (package_id) +); + + +comment on table sys_tenant_package is '租户套餐表'; +comment on column sys_tenant_package.package_id is '租户套餐id'; +comment on column sys_tenant_package.package_name is '套餐名称'; +comment on column sys_tenant_package.menu_ids is '关联菜单id'; +comment on column sys_tenant_package.remark is '备注'; +comment on column sys_tenant_package.status is '状态(0正常 1停用)'; +comment on column sys_tenant_package.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_tenant_package.create_dept is '创建部门'; +comment on column sys_tenant_package.create_by is '创建者'; +comment on column sys_tenant_package.create_time is '创建时间'; +comment on column sys_tenant_package.update_by is '更新者'; +comment on column sys_tenant_package.update_time is '更新时间'; + + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table if not exists sys_dept +( + dept_id int8, + tenant_id varchar(20) default '000000'::varchar, + parent_id int8 default 0, + ancestors varchar(500)default ''::varchar, + dept_name varchar(30) default ''::varchar, + dept_category varchar(100) default null::varchar, + order_num int4 default 0, + leader int8 default null, + phone varchar(11) default null::varchar, + email varchar(50) default null::varchar, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint "sys_dept_pk" primary key (dept_id) +); + +comment on table sys_dept is '部门表'; +comment on column sys_dept.dept_id is '部门ID'; +comment on column sys_dept.tenant_id is '租户编号'; +comment on column sys_dept.parent_id is '父部门ID'; +comment on column sys_dept.ancestors is '祖级列表'; +comment on column sys_dept.dept_name is '部门名称'; +comment on column sys_dept.dept_category is '部门类别编码'; +comment on column sys_dept.order_num is '显示顺序'; +comment on column sys_dept.leader is '负责人'; +comment on column sys_dept.phone is '联系电话'; +comment on column sys_dept.email is '邮箱'; +comment on column sys_dept.status is '部门状态(0正常 1停用)'; +comment on column sys_dept.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_dept.create_dept is '创建部门'; +comment on column sys_dept.create_by is '创建者'; +comment on column sys_dept.create_time is '创建时间'; +comment on column sys_dept.update_by is '更新者'; +comment on column sys_dept.update_time is '更新时间'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- +insert into sys_dept values(100, '000000', 0, '0', 'XXX科技', null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(101, '000000', 100, '0,100', '深圳总公司', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(102, '000000', 100, '0,100', '长沙分公司', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(103, '000000', 101, '0,100,101', '研发部门', null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(104, '000000', 101, '0,100,101', '市场部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(105, '000000', 101, '0,100,101', '测试部门', null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(106, '000000', 101, '0,100,101', '财务部门', null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(107, '000000', 101, '0,100,101', '运维部门', null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(108, '000000', 102, '0,100,102', '市场部门', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); +insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, now(), null, null); + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table if not exists sys_user +( + user_id int8, + tenant_id varchar(20) default '000000'::varchar, + dept_id int8, + user_name varchar(30) not null, + nick_name varchar(30) not null, + user_type varchar(10) default 'sys_user'::varchar, + email varchar(50) default ''::varchar, + phonenumber varchar(11) default ''::varchar, + sex char default '0'::bpchar, + avatar int8, + password varchar(100) default ''::varchar, + status char default '0'::bpchar, + del_flag char default '0'::bpchar, + login_ip varchar(128) default ''::varchar, + login_date timestamp, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_user_pk" primary key (user_id) +); + +comment on table sys_user is '用户信息表'; +comment on column sys_user.user_id is '用户ID'; +comment on column sys_user.tenant_id is '租户编号'; +comment on column sys_user.dept_id is '部门ID'; +comment on column sys_user.user_name is '用户账号'; +comment on column sys_user.nick_name is '用户昵称'; +comment on column sys_user.user_type is '用户类型(sys_user系统用户)'; +comment on column sys_user.email is '用户邮箱'; +comment on column sys_user.phonenumber is '手机号码'; +comment on column sys_user.sex is '用户性别(0男 1女 2未知)'; +comment on column sys_user.avatar is '头像地址'; +comment on column sys_user.password is '密码'; +comment on column sys_user.status is '帐号状态(0正常 1停用)'; +comment on column sys_user.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_user.login_ip is '最后登陆IP'; +comment on column sys_user.login_date is '最后登陆时间'; +comment on column sys_user.create_dept is '创建部门'; +comment on column sys_user.create_by is '创建者'; +comment on column sys_user.create_time is '创建时间'; +comment on column sys_user.update_by is '更新者'; +comment on column sys_user.update_time is '更新时间'; +comment on column sys_user.remark is '备注'; + +-- ---------------------------- + +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', now(), 103, 1, now(), null, null, '管理员'); +insert into sys_user VALUES(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 3, now(), NULL); +insert into sys_user VALUES(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', now(), 103, 1, now(), 4, now(), NULL); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table if not exists sys_post +( + post_id int8, + tenant_id varchar(20) default '000000'::varchar, + dept_id int8, + post_code varchar(64) not null, + post_category varchar(100) default null, + post_name varchar(50) not null, + post_sort int4 not null, + status char not null, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_post_pk" primary key (post_id) +); + +comment on table sys_post is '岗位信息表'; +comment on column sys_post.post_id is '岗位ID'; +comment on column sys_post.tenant_id is '租户编号'; +comment on column sys_post.dept_id is '部门id'; +comment on column sys_post.post_code is '岗位编码'; +comment on column sys_post.post_category is '岗位类别编码'; +comment on column sys_post.post_name is '岗位名称'; +comment on column sys_post.post_sort is '显示顺序'; +comment on column sys_post.status is '状态(0正常 1停用)'; +comment on column sys_post.create_dept is '创建部门'; +comment on column sys_post.create_by is '创建者'; +comment on column sys_post.create_time is '创建时间'; +comment on column sys_post.update_by is '更新者'; +comment on column sys_post.update_time is '更新时间'; +comment on column sys_post.remark is '备注'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, '000000', 103, 'ceo', null, '董事长', 1, '0', 103, 1, now(), null, null, ''); +insert into sys_post values(2, '000000', 100, 'se', null, '项目经理', 2, '0', 103, 1, now(), null, null, ''); +insert into sys_post values(3, '000000', 100, 'hr', null, '人力资源', 3, '0', 103, 1, now(), null, null, ''); +insert into sys_post values(4, '000000', 100, 'user', null, '普通员工', 4, '0', 103, 1, now(), null, null, ''); + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table if not exists sys_role +( + role_id int8, + tenant_id varchar(20) default '000000'::varchar, + role_name varchar(30) not null, + role_key varchar(100) not null, + role_sort int4 not null, + data_scope char default '1'::bpchar, + menu_check_strictly bool default true, + dept_check_strictly bool default true, + status char not null, + del_flag char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint "sys_role_pk" primary key (role_id) +); + +comment on table sys_role is '角色信息表'; +comment on column sys_role.role_id is '角色ID'; +comment on column sys_role.tenant_id is '租户编号'; +comment on column sys_role.role_name is '角色名称'; +comment on column sys_role.role_key is '角色权限字符串'; +comment on column sys_role.role_sort is '显示顺序'; +comment on column sys_role.data_scope is '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)'; +comment on column sys_role.menu_check_strictly is '菜单树选择项是否关联显示'; +comment on column sys_role.dept_check_strictly is '部门树选择项是否关联显示'; +comment on column sys_role.status is '角色状态(0正常 1停用)'; +comment on column sys_role.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_role.create_dept is '创建部门'; +comment on column sys_role.create_by is '创建者'; +comment on column sys_role.create_time is '创建时间'; +comment on column sys_role.update_by is '更新者'; +comment on column sys_role.update_time is '更新时间'; +comment on column sys_role.remark is '备注'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values('1', '000000', '超级管理员', 'superadmin', 1, '1', 't', 't', '0', '0', 103, 1, now(), null, null, '超级管理员'); +insert into sys_role values('3', '000000', '本部门及以下', 'test1', 3, '4', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, ''); +insert into sys_role values('4', '000000', '仅本人', 'test2', 4, '5', 't', 't', '0', '0', 103, 1, now(), NULL, NULL, ''); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table if not exists sys_menu +( + menu_id int8, + menu_name varchar(50) not null, + parent_id int8 default 0, + order_num int4 default 0, + path varchar(200) default ''::varchar, + component varchar(255) default null::varchar, + query_param varchar(255) default null::varchar, + is_frame char default '1'::bpchar, + is_cache char default '0'::bpchar, + menu_type char default ''::bpchar, + visible char default '0'::bpchar, + status char default '0'::bpchar, + perms varchar(100) default null::varchar, + icon varchar(100) default '#'::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default ''::varchar, + constraint "sys_menu_pk" primary key (menu_id) +); + +comment on table sys_menu is '菜单权限表'; +comment on column sys_menu.menu_id is '菜单ID'; +comment on column sys_menu.menu_name is '菜单名称'; +comment on column sys_menu.parent_id is '父菜单ID'; +comment on column sys_menu.order_num is '显示顺序'; +comment on column sys_menu.path is '路由地址'; +comment on column sys_menu.component is '组件路径'; +comment on column sys_menu.query_param is '路由参数'; +comment on column sys_menu.is_frame is '是否为外链(0是 1否)'; +comment on column sys_menu.is_cache is '是否缓存(0缓存 1不缓存)'; +comment on column sys_menu.menu_type is '菜单类型(M目录 C菜单 F按钮)'; +comment on column sys_menu.visible is '显示状态(0显示 1隐藏)'; +comment on column sys_menu.status is '菜单状态(0正常 1停用)'; +comment on column sys_menu.perms is '权限标识'; +comment on column sys_menu.icon is '菜单图标'; +comment on column sys_menu.create_dept is '创建部门'; +comment on column sys_menu.create_by is '创建者'; +comment on column sys_menu.create_time is '创建时间'; +comment on column sys_menu.update_by is '更新者'; +comment on column sys_menu.update_time is '更新时间'; +comment on column sys_menu.remark is '备注'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '1', '0', 'M', '0', '0', '', 'system', 103, 1, now(), null, null, '系统管理目录'); +insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', null, '', '1', '0', 'M', '0', '0', '', 'chart', 103, 1, now(), null, null, '租户管理目录'); +insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), null, null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', '1', '0', 'M', '0', '0', '', 'tool', 103, 1, now(), null, null, '系统工具目录'); +insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', '0', '0', 'M', '0', '0', '', 'guide', 103, 1, now(), null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu VALUES('5', '测试菜单', '0', '5', 'demo', null, '', '1', '0', 'M', '0', '0', null, 'star', 103, 1, now(), null, null, '测试菜单'); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '1', '0', 'C', '0', '0', 'system:user:list', 'user', 103, 1, now(), null, null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '1', '0', 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, now(), null, null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', '1', '0', 'C', '0', '0', 'system:menu:list', 'tree-table', 103, 1, now(), null, null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', '1', '0', 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, now(), null, null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', '1', '0', 'C', '0', '0', 'system:post:list', 'post', 103, 1, now(), null, null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', '1', '0', 'C', '0', '0', 'system:dict:list', 'dict', 103, 1, now(), null, null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', '1', '0', 'C', '0', '0', 'system:config:list', 'edit', 103, 1, now(), null, null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', '1', '0', 'C', '0', '0', 'system:notice:list', 'message', 103, 1, now(), null, null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', '1', '0', 'M', '0', '0', '', 'log', 103, 1, now(), null, null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', '1', '0', 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, now(), null, null, '在线用户菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', '1', '0', 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, now(), null, null, '缓存监控菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', '1', '0', 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, now(), null, null, '代码生成菜单'); +insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', '1', '0', 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, now(), null, null, '租户管理菜单'); +insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', '1', '0', 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, now(), null, null, '租户套餐管理菜单'); +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', '1', '0', 'C', '0', '0', 'system:client:list', 'international', 103, 1, now(), null, null, '客户端管理菜单'); + +-- springboot-admin监控 +insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', 'monitor/admin/index', '', '1', '0', 'C', '0', '0', 'monitor:admin:list', 'dashboard', 103, 1, now(), null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', '1', '0', 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, now(), null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values('120', '任务调度中心', '2', '6', 'snailjob', 'monitor/snailjob/index', '', '1', '0', 'C', '0', '0', 'monitor:snailjob:list', 'job', 103, 1, now(), null, null, 'SnailJob控制台菜单'); + +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', '1', '0', 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, now(), null, null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', '1', '0', 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 103, 1, now(), null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1001', '用户查询', '100', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:user:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1002', '用户新增', '100', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:user:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1003', '用户修改', '100', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:user:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1004', '用户删除', '100', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:user:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1005', '用户导出', '100', '5', '', '', '', '1', '0', 'F', '0', '0', 'system:user:export', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1006', '用户导入', '100', '6', '', '', '', '1', '0', 'F', '0', '0', 'system:user:import', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1007', '重置密码', '100', '7', '', '', '', '1', '0', 'F', '0', '0', 'system:user:resetPwd', '#', 103, 1, now(), null, null, ''); +-- 角色管理按钮 +insert into sys_menu values('1008', '角色查询', '101', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:role:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1009', '角色新增', '101', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:role:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1010', '角色修改', '101', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:role:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1011', '角色删除', '101', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:role:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1012', '角色导出', '101', '5', '', '', '', '1', '0', 'F', '0', '0', 'system:role:export', '#', 103, 1, now(), null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:menu:remove', '#', 103, 1, now(), null, null, ''); +-- 部门管理按钮 +insert into sys_menu values('1017', '部门查询', '103', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1018', '部门新增', '103', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1019', '部门修改', '103', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1020', '部门删除', '103', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:dept:remove', '#', 103, 1, now(), null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', '', '1', '0', 'F', '0', '0', 'system:post:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', '', '1', '0', 'F', '0', '0', 'system:post:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', '', '1', '0', 'F', '0', '0', 'system:post:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', '', '1', '0', 'F', '0', '0', 'system:post:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', '', '1', '0', 'F', '0', '0', 'system:post:export', '#', 103, 1, now(), null, null, ''); +-- 字典管理按钮 +insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:dict:export', '#', 103, 1, now(), null, null, ''); +-- 参数设置按钮 +insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:config:export', '#', 103, 1, now(), null, null, ''); +-- 通知公告按钮 +insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:notice:remove', '#', 103, 1, now(), null, null, ''); +-- 操作日志按钮 +insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:operlog:export', '#', 103, 1, now(), null, null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, now(), null, null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, now(), null, null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:import', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:preview', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', '', '1', '0', 'F', '0', '0', 'tool:gen:code', '#', 103, 1, now(), null, null, ''); +-- oss相关按钮 +insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:upload', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:download', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:oss:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1620', '配置列表', '118', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:list', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, now(), null, null, ''); +-- 租户管理相关按钮 +insert into sys_menu values('1606', '租户查询', '121', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1607', '租户新增', '121', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1608', '租户修改', '121', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1609', '租户删除', '121', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1610', '租户导出', '121', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenant:export', '#', 103, 1, now(), null, null, ''); +-- 租户套餐管理相关按钮 +insert into sys_menu values('1611', '租户套餐查询', '122', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1612', '租户套餐新增', '122', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1613', '租户套餐修改', '122', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1614', '租户套餐删除', '122', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1615', '租户套餐导出', '122', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:tenantPackage:export', '#', 103, 1, now(), null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:export', '#', 103, 1, now(), null, null, ''); +-- 测试菜单 +INSERT INTO sys_menu VALUES('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', '1', '0', 'C', '0', '0', 'demo:demo:list', '#', 103, 1, now(), NULL, NULL, '测试单表菜单'); +INSERT INTO sys_menu VALUES('1501', '测试单表查询', '1500', '1', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1502', '测试单表新增', '1500', '2', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1503', '测试单表修改', '1500', '3', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1504', '测试单表删除', '1500', '4', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1505', '测试单表导出', '1500', '5', '#', '', '', '1', '0', 'F', '0', '0', 'demo:demo:export', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', '1', '0', 'C', '0', '0', 'demo:tree:list', '#', 103, 1, now(), NULL, NULL, '测试树表菜单'); +INSERT INTO sys_menu VALUES('1507', '测试树表查询', '1506', '1', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1508', '测试树表新增', '1506', '2', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1509', '测试树表修改', '1506', '3', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1510', '测试树表删除', '1506', '4', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES('1511', '测试树表导出', '1506', '5', '#', '', '', '1', '0', 'F', '0', '0', 'demo:tree:export', '#', 103, 1, now(), NULL, NULL, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table if not exists sys_user_role +( + user_id int8 not null, + role_id int8 not null, + constraint sys_user_role_pk primary key (user_id, role_id) +); + +comment on table sys_user_role is '用户和角色关联表'; +comment on column sys_user_role.user_id is '用户ID'; +comment on column sys_user_role.role_id is '角色ID'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table if not exists sys_role_menu +( + role_id int8 not null, + menu_id int8 not null, + constraint sys_role_menu_pk primary key (role_id, menu_id) +); + +comment on table sys_role_menu is '角色和菜单关联表'; +comment on column sys_role_menu.role_id is '角色ID'; +comment on column sys_role_menu.menu_id is '菜单ID'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '118'); +insert into sys_role_menu values ('3', '123'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1050'); +insert into sys_role_menu values ('3', '1061'); +insert into sys_role_menu values ('3', '1062'); +insert into sys_role_menu values ('3', '1063'); +insert into sys_role_menu values ('3', '1064'); +insert into sys_role_menu values ('3', '1065'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('3', '1600'); +insert into sys_role_menu values ('3', '1601'); +insert into sys_role_menu values ('3', '1602'); +insert into sys_role_menu values ('3', '1603'); +insert into sys_role_menu values ('3', '1620'); +insert into sys_role_menu values ('3', '1621'); +insert into sys_role_menu values ('3', '1622'); +insert into sys_role_menu values ('3', '1623'); +insert into sys_role_menu values ('3', '11618'); +insert into sys_role_menu values ('3', '11619'); +insert into sys_role_menu values ('3', '11629'); +insert into sys_role_menu values ('3', '11632'); +insert into sys_role_menu values ('3', '11633'); +insert into sys_role_menu values ('3', '11638'); +insert into sys_role_menu values ('3', '11639'); +insert into sys_role_menu values ('3', '11640'); +insert into sys_role_menu values ('3', '11641'); +insert into sys_role_menu values ('3', '11642'); +insert into sys_role_menu values ('3', '11643'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table if not exists sys_role_dept +( + role_id int8 not null, + dept_id int8 not null, + constraint sys_role_dept_pk primary key (role_id, dept_id) +); + +comment on table sys_role_dept is '角色和部门关联表'; +comment on column sys_role_dept.role_id is '角色ID'; +comment on column sys_role_dept.dept_id is '部门ID'; + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table if not exists sys_user_post +( + user_id int8 not null, + post_id int8 not null, + constraint sys_user_post_pk primary key (user_id, post_id) +); + +comment on table sys_user_post is '用户与岗位关联表'; +comment on column sys_user_post.user_id is '用户ID'; +comment on column sys_user_post.post_id is '岗位ID'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table if not exists sys_oper_log +( + oper_id int8, + tenant_id varchar(20) default '000000'::varchar, + title varchar(50) default ''::varchar, + business_type int4 default 0, + method varchar(100) default ''::varchar, + request_method varchar(10) default ''::varchar, + operator_type int4 default 0, + oper_name varchar(50) default ''::varchar, + dept_name varchar(50) default ''::varchar, + oper_url varchar(255) default ''::varchar, + oper_ip varchar(128) default ''::varchar, + oper_location varchar(255) default ''::varchar, + oper_param varchar(4000) default ''::varchar, + json_result varchar(4000) default ''::varchar, + status int4 default 0, + error_msg varchar(4000) default ''::varchar, + oper_time timestamp, + cost_time int8 default 0, + constraint sys_oper_log_pk primary key (oper_id) +); + +create index idx_sys_oper_log_bt ON sys_oper_log (business_type); +create index idx_sys_oper_log_s ON sys_oper_log (status); +create index idx_sys_oper_log_ot ON sys_oper_log (oper_time); + +comment on table sys_oper_log is '操作日志记录'; +comment on column sys_oper_log.oper_id is '日志主键'; +comment on column sys_oper_log.tenant_id is '租户编号'; +comment on column sys_oper_log.title is '模块标题'; +comment on column sys_oper_log.business_type is '业务类型(0其它 1新增 2修改 3删除)'; +comment on column sys_oper_log.method is '方法名称'; +comment on column sys_oper_log.request_method is '请求方式'; +comment on column sys_oper_log.operator_type is '操作类别(0其它 1后台用户 2手机端用户)'; +comment on column sys_oper_log.oper_name is '操作人员'; +comment on column sys_oper_log.dept_name is '部门名称'; +comment on column sys_oper_log.oper_url is '请求URL'; +comment on column sys_oper_log.oper_ip is '主机地址'; +comment on column sys_oper_log.oper_location is '操作地点'; +comment on column sys_oper_log.oper_param is '请求参数'; +comment on column sys_oper_log.json_result is '返回参数'; +comment on column sys_oper_log.status is '操作状态(0正常 1异常)'; +comment on column sys_oper_log.error_msg is '错误消息'; +comment on column sys_oper_log.oper_time is '操作时间'; +comment on column sys_oper_log.cost_time is '消耗时间'; + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table if not exists sys_dict_type +( + dict_id int8, + tenant_id varchar(20) default '000000'::varchar, + dict_name varchar(100) default ''::varchar, + dict_type varchar(100) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_dict_type_pk primary key (dict_id) +); + +create unique index sys_dict_type_index1 ON sys_dict_type (tenant_id, dict_type); + +comment on table sys_dict_type is '字典类型表'; +comment on column sys_dict_type.dict_id is '字典主键'; +comment on column sys_dict_type.tenant_id is '租户编号'; +comment on column sys_dict_type.dict_name is '字典名称'; +comment on column sys_dict_type.dict_type is '字典类型'; +comment on column sys_dict_type.create_dept is '创建部门'; +comment on column sys_dict_type.create_by is '创建者'; +comment on column sys_dict_type.create_time is '创建时间'; +comment on column sys_dict_type.update_by is '更新者'; +comment on column sys_dict_type.update_time is '更新时间'; +comment on column sys_dict_type.remark is '备注'; + +insert into sys_dict_type values(1, '000000', '用户性别', 'sys_user_sex', 103, 1, now(), null, null, '用户性别列表'); +insert into sys_dict_type values(2, '000000', '菜单状态', 'sys_show_hide', 103, 1, now(), null, null, '菜单状态列表'); +insert into sys_dict_type values(3, '000000', '系统开关', 'sys_normal_disable', 103, 1, now(), null, null, '系统开关列表'); +insert into sys_dict_type values(6, '000000', '系统是否', 'sys_yes_no', 103, 1, now(), null, null, '系统是否列表'); +insert into sys_dict_type values(7, '000000', '通知类型', 'sys_notice_type', 103, 1, now(), null, null, '通知类型列表'); +insert into sys_dict_type values(8, '000000', '通知状态', 'sys_notice_status', 103, 1, now(), null, null, '通知状态列表'); +insert into sys_dict_type values(9, '000000', '操作类型', 'sys_oper_type', 103, 1, now(), null, null, '操作类型列表'); +insert into sys_dict_type values(10, '000000', '系统状态', 'sys_common_status', 103, 1, now(), null, null, '登录状态列表'); +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, now(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, now(), null, null, '客户端设备类型'); + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table if not exists sys_dict_data +( + dict_code int8, + tenant_id varchar(20) default '000000'::varchar, + dict_sort int4 default 0, + dict_label varchar(100) default ''::varchar, + dict_value varchar(100) default ''::varchar, + dict_type varchar(100) default ''::varchar, + css_class varchar(100) default null::varchar, + list_class varchar(100) default null::varchar, + is_default char default 'N'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_dict_data_pk primary key (dict_code) +); + +comment on table sys_dict_data is '字典数据表'; +comment on column sys_dict_data.dict_code is '字典编码'; +comment on column sys_dict_type.tenant_id is '租户编号'; +comment on column sys_dict_data.dict_sort is '字典排序'; +comment on column sys_dict_data.dict_label is '字典标签'; +comment on column sys_dict_data.dict_value is '字典键值'; +comment on column sys_dict_data.dict_type is '字典类型'; +comment on column sys_dict_data.css_class is '样式属性(其他样式扩展)'; +comment on column sys_dict_data.list_class is '表格回显样式'; +comment on column sys_dict_data.is_default is '是否默认(Y是 N否)'; +comment on column sys_dict_data.create_dept is '创建部门'; +comment on column sys_dict_data.create_by is '创建者'; +comment on column sys_dict_data.create_time is '创建时间'; +comment on column sys_dict_data.update_by is '更新者'; +comment on column sys_dict_data.update_time is '更新时间'; +comment on column sys_dict_data.remark is '备注'; + +insert into sys_dict_data values(1, '000000', 1, '男', '0', 'sys_user_sex', '', '', 'Y', 103, 1, now(), null, null, '性别男'); +insert into sys_dict_data values(2, '000000', 2, '女', '1', 'sys_user_sex', '', '', 'N', 103, 1, now(), null, null, '性别女'); +insert into sys_dict_data values(3, '000000', 3, '未知', '2', 'sys_user_sex', '', '', 'N', 103, 1, now(), null, null, '性别未知'); +insert into sys_dict_data values(4, '000000', 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 103, 1, now(), null, null, '显示菜单'); +insert into sys_dict_data values(5, '000000', 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 103, 1, now(), null, null, '隐藏菜单'); +insert into sys_dict_data values(6, '000000', 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 103, 1, now(), null, null, '正常状态'); +insert into sys_dict_data values(7, '000000', 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 103, 1, now(), null, null, '停用状态'); +insert into sys_dict_data values(12, '000000', 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 103, 1, now(), null, null, '系统默认是'); +insert into sys_dict_data values(13, '000000', 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 103, 1, now(), null, null, '系统默认否'); +insert into sys_dict_data values(14, '000000', 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 103, 1, now(), null, null, '通知'); +insert into sys_dict_data values(15, '000000', 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 103, 1, now(), null, null, '公告'); +insert into sys_dict_data values(16, '000000', 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 103, 1, now(), null, null, '正常状态'); +insert into sys_dict_data values(17, '000000', 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 103, 1, now(), null, null, '关闭状态'); +insert into sys_dict_data values(29, '000000', 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 103, 1, now(), null, null, '其他操作'); +insert into sys_dict_data values(18, '000000', 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 103, 1, now(), null, null, '新增操作'); +insert into sys_dict_data values(19, '000000', 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 103, 1, now(), null, null, '修改操作'); +insert into sys_dict_data values(20, '000000', 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 103, 1, now(), null, null, '删除操作'); +insert into sys_dict_data values(21, '000000', 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 103, 1, now(), null, null, '授权操作'); +insert into sys_dict_data values(22, '000000', 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 103, 1, now(), null, null, '导出操作'); +insert into sys_dict_data values(23, '000000', 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 103, 1, now(), null, null, '导入操作'); +insert into sys_dict_data values(24, '000000', 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 103, 1, now(), null, null, '强退操作'); +insert into sys_dict_data values(25, '000000', 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 103, 1, now(), null, null, '生成操作'); +insert into sys_dict_data values(26, '000000', 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 103, 1, now(), null, null, '清空操作'); +insert into sys_dict_data values(27, '000000', 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 103, 1, now(), null, null, '正常状态'); +insert into sys_dict_data values(28, '000000', 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 103, 1, now(), null, null, '停用状态'); +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 103, 1, now(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, now(), null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table if not exists sys_config +( + config_id int8, + tenant_id varchar(20) default '000000'::varchar, + config_name varchar(100) default ''::varchar, + config_key varchar(100) default ''::varchar, + config_value varchar(500) default ''::varchar, + config_type char default 'N'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint sys_config_pk primary key (config_id) +); + +comment on table sys_config is '参数配置表'; +comment on column sys_config.config_id is '参数主键'; +comment on column sys_config.tenant_id is '租户编号'; +comment on column sys_config.config_name is '参数名称'; +comment on column sys_config.config_key is '参数键名'; +comment on column sys_config.config_value is '参数键值'; +comment on column sys_config.config_type is '系统内置(Y是 N否)'; +comment on column sys_config.create_dept is '创建部门'; +comment on column sys_config.create_by is '创建者'; +comment on column sys_config.create_time is '创建时间'; +comment on column sys_config.update_by is '更新者'; +comment on column sys_config.update_time is '更新时间'; +comment on column sys_config.remark is '备注'; + +insert into sys_config values(1, '000000', '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 103, 1, now(), null, null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '000000', '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 103, 1, now(), null, null, '初始化密码 123456' ); +insert into sys_config values(3, '000000', '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 103, 1, now(), null, null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(5, '000000', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 103, 1, now(), null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(11, '000000', 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 103, 1, now(), null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table if not exists sys_logininfor +( + info_id int8, + tenant_id varchar(20) default '000000'::varchar, + user_name varchar(50) default ''::varchar, + client_key varchar(32) default ''::varchar, + device_type varchar(32) default ''::varchar, + ipaddr varchar(128) default ''::varchar, + login_location varchar(255) default ''::varchar, + browser varchar(50) default ''::varchar, + os varchar(50) default ''::varchar, + status char default '0'::bpchar, + msg varchar(255) default ''::varchar, + login_time timestamp, + constraint sys_logininfor_pk primary key (info_id) +); + +create index idx_sys_logininfor_s ON sys_logininfor (status); +create index idx_sys_logininfor_lt ON sys_logininfor (login_time); + +comment on table sys_logininfor is '系统访问记录'; +comment on column sys_logininfor.info_id is '访问ID'; +comment on column sys_logininfor.tenant_id is '租户编号'; +comment on column sys_logininfor.user_name is '用户账号'; +comment on column sys_logininfor.client_key is '客户端'; +comment on column sys_logininfor.device_type is '设备类型'; +comment on column sys_logininfor.ipaddr is '登录IP地址'; +comment on column sys_logininfor.login_location is '登录地点'; +comment on column sys_logininfor.browser is '浏览器类型'; +comment on column sys_logininfor.os is '操作系统'; +comment on column sys_logininfor.status is '登录状态(0成功 1失败)'; +comment on column sys_logininfor.msg is '提示消息'; +comment on column sys_logininfor.login_time is '访问时间'; + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table if not exists sys_notice +( + notice_id int8, + tenant_id varchar(20) default '000000'::varchar, + notice_title varchar(50) not null, + notice_type char not null, + notice_content text, + status char default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(255) default null::varchar, + constraint sys_notice_pk primary key (notice_id) +); + +comment on table sys_notice is '通知公告表'; +comment on column sys_notice.notice_id is '公告ID'; +comment on column sys_notice.tenant_id is '租户编号'; +comment on column sys_notice.notice_title is '公告标题'; +comment on column sys_notice.notice_type is '公告类型(1通知 2公告)'; +comment on column sys_notice.notice_content is '公告内容'; +comment on column sys_notice.status is '公告状态(0正常 1关闭)'; +comment on column sys_notice.create_dept is '创建部门'; +comment on column sys_notice.create_by is '创建者'; +comment on column sys_notice.create_time is '创建时间'; +comment on column sys_notice.update_by is '更新者'; +comment on column sys_notice.update_time is '更新时间'; +comment on column sys_notice.remark is '备注'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '000000', '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 103, 1, now(), null, null, '管理员'); +insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 103, 1, now(), null, null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +create table if not exists gen_table +( + table_id int8, + data_name varchar(200) default ''::varchar, + table_name varchar(200) default ''::varchar, + table_comment varchar(500) default ''::varchar, + sub_table_name varchar(64) default ''::varchar, + sub_table_fk_name varchar(64) default ''::varchar, + class_name varchar(100) default ''::varchar, + tpl_category varchar(200) default 'crud'::varchar, + package_name varchar(100) default null::varchar, + module_name varchar(30) default null::varchar, + business_name varchar(30) default null::varchar, + function_name varchar(50) default null::varchar, + function_author varchar(50) default null::varchar, + gen_type char default '0'::bpchar not null, + gen_path varchar(200) default '/'::varchar, + options varchar(1000) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default null::varchar, + constraint gen_table_pk primary key (table_id) +); + +comment on table gen_table is '代码生成业务表'; +comment on column gen_table.table_id is '编号'; +comment on column gen_table.data_name is '数据源名称'; +comment on column gen_table.table_name is '表名称'; +comment on column gen_table.table_comment is '表描述'; +comment on column gen_table.sub_table_name is '关联子表的表名'; +comment on column gen_table.sub_table_fk_name is '子表关联的外键名'; +comment on column gen_table.class_name is '实体类名称'; +comment on column gen_table.tpl_category is '使用的模板(CRUD单表操作 TREE树表操作)'; +comment on column gen_table.package_name is '生成包路径'; +comment on column gen_table.module_name is '生成模块名'; +comment on column gen_table.business_name is '生成业务名'; +comment on column gen_table.function_name is '生成功能名'; +comment on column gen_table.function_author is '生成功能作者'; +comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)'; +comment on column gen_table.gen_path is '生成路径(不填默认项目路径)'; +comment on column gen_table.options is '其它生成选项'; +comment on column gen_table.create_dept is '创建部门'; +comment on column gen_table.create_by is '创建者'; +comment on column gen_table.create_time is '创建时间'; +comment on column gen_table.update_by is '更新者'; +comment on column gen_table.update_time is '更新时间'; +comment on column gen_table.remark is '备注'; + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +create table if not exists gen_table_column +( + column_id int8, + table_id int8, + column_name varchar(200) default null::varchar, + column_comment varchar(500) default null::varchar, + column_type varchar(100) default null::varchar, + java_type varchar(500) default null::varchar, + java_field varchar(200) default null::varchar, + is_pk char default null::bpchar, + is_increment char default null::bpchar, + is_required char default null::bpchar, + is_insert char default null::bpchar, + is_edit char default null::bpchar, + is_list char default null::bpchar, + is_query char default null::bpchar, + query_type varchar(200) default 'EQ'::varchar, + html_type varchar(200) default null::varchar, + dict_type varchar(200) default ''::varchar, + sort int4, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint gen_table_column_pk primary key (column_id) +); + +comment on table gen_table_column is '代码生成业务表字段'; +comment on column gen_table_column.column_id is '编号'; +comment on column gen_table_column.table_id is '归属表编号'; +comment on column gen_table_column.column_name is '列名称'; +comment on column gen_table_column.column_comment is '列描述'; +comment on column gen_table_column.column_type is '列类型'; +comment on column gen_table_column.java_type is 'JAVA类型'; +comment on column gen_table_column.java_field is 'JAVA字段名'; +comment on column gen_table_column.is_pk is '是否主键(1是)'; +comment on column gen_table_column.is_increment is '是否自增(1是)'; +comment on column gen_table_column.is_required is '是否必填(1是)'; +comment on column gen_table_column.is_insert is '是否为插入字段(1是)'; +comment on column gen_table_column.is_edit is '是否编辑字段(1是)'; +comment on column gen_table_column.is_list is '是否列表字段(1是)'; +comment on column gen_table_column.is_query is '是否查询字段(1是)'; +comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)'; +comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)'; +comment on column gen_table_column.dict_type is '字典类型'; +comment on column gen_table_column.sort is '排序'; +comment on column gen_table_column.create_dept is '创建部门'; +comment on column gen_table_column.create_by is '创建者'; +comment on column gen_table_column.create_time is '创建时间'; +comment on column gen_table_column.update_by is '更新者'; +comment on column gen_table_column.update_time is '更新时间'; + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table if not exists sys_oss +( + oss_id int8, + tenant_id varchar(20) default '000000'::varchar, + file_name varchar(255) default ''::varchar not null, + original_name varchar(255) default ''::varchar not null, + file_suffix varchar(10) default ''::varchar not null, + url varchar(500) default ''::varchar not null, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + service varchar(20) default 'minio'::varchar, + constraint sys_oss_pk primary key (oss_id) +); + +comment on table sys_oss is 'OSS对象存储表'; +comment on column sys_oss.oss_id is '对象存储主键'; +comment on column sys_oss.tenant_id is '租户编码'; +comment on column sys_oss.file_name is '文件名'; +comment on column sys_oss.original_name is '原名'; +comment on column sys_oss.file_suffix is '文件后缀名'; +comment on column sys_oss.url is 'URL地址'; +comment on column sys_oss.create_by is '上传人'; +comment on column sys_oss.create_dept is '创建部门'; +comment on column sys_oss.create_time is '创建时间'; +comment on column sys_oss.update_by is '更新者'; +comment on column sys_oss.update_time is '更新时间'; +comment on column sys_oss.service is '服务商'; + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table if not exists sys_oss_config +( + oss_config_id int8, + tenant_id varchar(20) default '000000'::varchar, + config_key varchar(20) default ''::varchar not null, + access_key varchar(255) default ''::varchar, + secret_key varchar(255) default ''::varchar, + bucket_name varchar(255) default ''::varchar, + prefix varchar(255) default ''::varchar, + endpoint varchar(255) default ''::varchar, + domain varchar(255) default ''::varchar, + is_https char default 'N'::bpchar, + region varchar(255) default ''::varchar, + access_policy char(1) default '1'::bpchar not null, + status char default '1'::bpchar, + ext1 varchar(255) default ''::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + remark varchar(500) default ''::varchar, + constraint sys_oss_config_pk primary key (oss_config_id) +); + +comment on table sys_oss_config is '对象存储配置表'; +comment on column sys_oss_config.oss_config_id is '主键'; +comment on column sys_oss_config.tenant_id is '租户编码'; +comment on column sys_oss_config.config_key is '配置key'; +comment on column sys_oss_config.access_key is 'accessKey'; +comment on column sys_oss_config.secret_key is '秘钥'; +comment on column sys_oss_config.bucket_name is '桶名称'; +comment on column sys_oss_config.prefix is '前缀'; +comment on column sys_oss_config.endpoint is '访问站点'; +comment on column sys_oss_config.domain is '自定义域名'; +comment on column sys_oss_config.is_https is '是否https(Y=是,N=否)'; +comment on column sys_oss_config.region is '域'; +comment on column sys_oss_config.access_policy is '桶权限类型(0=private 1=public 2=custom)'; +comment on column sys_oss_config.status is '是否默认(0=是,1=否)'; +comment on column sys_oss_config.ext1 is '扩展字段'; +comment on column sys_oss_config.create_dept is '创建部门'; +comment on column sys_oss_config.create_by is '创建者'; +comment on column sys_oss_config.create_time is '创建时间'; +comment on column sys_oss_config.update_by is '更新者'; +comment on column sys_oss_config.update_time is '更新时间'; +comment on column sys_oss_config.remark is '备注'; + +insert into sys_oss_config values (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '','N', '', '1', '0', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1', '1', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1', '1', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1240000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1', '1', '', 103, 1, now(), 1, now(), null); +insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '','N', '', '1', '1', '', 103, 1, now(), 1, now(), NULL); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id int8, + client_id varchar(64) default ''::varchar, + client_key varchar(32) default ''::varchar, + client_secret varchar(255) default ''::varchar, + grant_type varchar(255) default ''::varchar, + device_type varchar(32) default ''::varchar, + active_timeout int4 default 1800, + timeout int4 default 604800, + status char(1) default '0'::bpchar, + del_flag char(1) default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint sys_client_pk primary key (id) +); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 1代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); + +create table if not exists test_demo +( + id int8, + tenant_id varchar(20) default '000000', + dept_id int8, + user_id int8, + order_num int4 default 0, + test_key varchar(255), + value varchar(255), + version int4 default 0, + create_dept int8, + create_time timestamp, + create_by int8, + update_time timestamp, + update_by int8, + del_flag int4 default 0 +); + +comment on table test_demo is '测试单表'; +comment on column test_demo.id is '主键'; +comment on column test_demo.tenant_id is '租户编号'; +comment on column test_demo.dept_id is '部门id'; +comment on column test_demo.user_id is '用户id'; +comment on column test_demo.order_num is '排序号'; +comment on column test_demo.test_key is 'key键'; +comment on column test_demo.value is '值'; +comment on column test_demo.version is '版本'; +comment on column test_demo.create_dept is '创建部门'; +comment on column test_demo.create_time is '创建时间'; +comment on column test_demo.create_by is '创建人'; +comment on column test_demo.update_time is '更新时间'; +comment on column test_demo.update_by is '更新人'; +comment on column test_demo.del_flag is '删除标志'; + +create table if not exists test_tree +( + id int8, + tenant_id varchar(20) default '000000', + parent_id int8 default 0, + dept_id int8, + user_id int8, + tree_name varchar(255), + version int4 default 0, + create_dept int8, + create_time timestamp, + create_by int8, + update_time timestamp, + update_by int8, + del_flag integer default 0 +); + +comment on table test_tree is '测试树表'; +comment on column test_tree.id is '主键'; +comment on column test_tree.tenant_id is '租户编号'; +comment on column test_tree.parent_id is '父id'; +comment on column test_tree.dept_id is '部门id'; +comment on column test_tree.user_id is '用户id'; +comment on column test_tree.tree_name is '值'; +comment on column test_tree.version is '版本'; +comment on column test_tree.create_dept is '创建部门'; +comment on column test_tree.create_time is '创建时间'; +comment on column test_tree.create_by is '创建人'; +comment on column test_tree.update_time is '更新时间'; +comment on column test_tree.update_by is '更新人'; +comment on column test_tree.del_flag is '删除标志'; + +INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, now(), 1, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, now(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, now(), 1, NULL, NULL, 0); + +-- 字符串自动转时间 避免框架时间查询报错问题 +create or replace function cast_varchar_to_timestamp(varchar) returns timestamptz as $$ +select to_timestamp($1, 'yyyy-mm-dd hh24:mi:ss'); +$$ language sql strict ; + +create cast (varchar as timestamptz) with function cast_varchar_to_timestamp as IMPLICIT; diff --git a/script/sql/postgres/postgres_ry_workflow.sql b/script/sql/postgres/postgres_ry_workflow.sql new file mode 100644 index 0000000..80cd414 --- /dev/null +++ b/script/sql/postgres/postgres_ry_workflow.sql @@ -0,0 +1,405 @@ +-- ---------------------------- +-- 0、warm-flow-all.sql,地址:https://gitee.com/dromara/warm-flow/blob/master/sql/postgresql/postgresql-warm-flow-all.sql +-- ---------------------------- +CREATE TABLE flow_definition +( + id int8 NOT NULL, -- 主键id + flow_code varchar(40) NOT NULL, -- 流程编码 + flow_name varchar(100) NOT NULL, -- 流程名称 + category varchar(100) NULL, -- 流程类别 + "version" varchar(20) NOT NULL, -- 流程版本 + is_publish int2 NOT NULL DEFAULT 0, -- 是否发布(0未发布 1已发布 9失效) + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + activity_status int2 NOT NULL DEFAULT 1, -- 流程激活状态(0挂起 1激活) + listener_type varchar(100) NULL, -- 监听器类型 + listener_path varchar(400) NULL, -- 监听器路径 + ext varchar(500) NULL, -- 扩展字段,预留给业务系统使用 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_definition_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_definition IS '流程定义表'; + +COMMENT ON COLUMN flow_definition.id IS '主键id'; +COMMENT ON COLUMN flow_definition.flow_code IS '流程编码'; +COMMENT ON COLUMN flow_definition.flow_name IS '流程名称'; +COMMENT ON COLUMN flow_definition.category IS '流程类别'; +COMMENT ON COLUMN flow_definition."version" IS '流程版本'; +COMMENT ON COLUMN flow_definition.is_publish IS '是否发布(0未发布 1已发布 9失效)'; +COMMENT ON COLUMN flow_definition.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_definition.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_definition.activity_status IS '流程激活状态(0挂起 1激活)'; +COMMENT ON COLUMN flow_definition.listener_type IS '监听器类型'; +COMMENT ON COLUMN flow_definition.listener_path IS '监听器路径'; +COMMENT ON COLUMN flow_definition.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_definition.create_time IS '创建时间'; +COMMENT ON COLUMN flow_definition.update_time IS '更新时间'; +COMMENT ON COLUMN flow_definition.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_definition.tenant_id IS '租户id'; + +CREATE TABLE flow_node +( + id int8 NOT NULL, -- 主键id + node_type int2 NOT NULL, -- 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + definition_id int8 NOT NULL, -- 流程定义id + node_code varchar(100) NOT NULL, -- 流程节点编码 + node_name varchar(100) NULL, -- 流程节点名称 + permission_flag varchar(200) NULL, -- 权限标识(权限类型:权限标识,可以多个,用逗号隔开) + node_ratio numeric(6, 3) NULL, -- 流程签署比例值 + coordinate varchar(100) NULL, -- 坐标 + skip_any_node varchar(100) NULL DEFAULT 'N':: character varying, -- 是否可以退回任意节点(Y是 N否)即将删除 + any_node_skip varchar(100) NULL, -- 任意结点跳转 + listener_type varchar(100) NULL, -- 监听器类型 + listener_path varchar(400) NULL, -- 监听器路径 + handler_type varchar(100) NULL, -- 处理器类型 + handler_path varchar(400) NULL, -- 处理器路径 + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + "version" varchar(20) NOT NULL, -- 版本 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_node_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_node IS '流程节点表'; + +COMMENT ON COLUMN flow_node.id IS '主键id'; +COMMENT ON COLUMN flow_node.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_node.definition_id IS '流程定义id'; +COMMENT ON COLUMN flow_node.node_code IS '流程节点编码'; +COMMENT ON COLUMN flow_node.node_name IS '流程节点名称'; +COMMENT ON COLUMN flow_node.permission_flag IS '权限标识(权限类型:权限标识,可以多个,用逗号隔开)'; +COMMENT ON COLUMN flow_node.node_ratio IS '流程签署比例值'; +COMMENT ON COLUMN flow_node.coordinate IS '坐标'; +COMMENT ON COLUMN flow_node.skip_any_node IS '是否可以退回任意节点(Y是 N否)即将删除'; +COMMENT ON COLUMN flow_node.any_node_skip IS '任意结点跳转'; +COMMENT ON COLUMN flow_node.listener_type IS '监听器类型'; +COMMENT ON COLUMN flow_node.listener_path IS '监听器路径'; +COMMENT ON COLUMN flow_node.handler_type IS '处理器类型'; +COMMENT ON COLUMN flow_node.handler_path IS '处理器路径'; +COMMENT ON COLUMN flow_node.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_node.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_node."version" IS '版本'; +COMMENT ON COLUMN flow_node.create_time IS '创建时间'; +COMMENT ON COLUMN flow_node.update_time IS '更新时间'; +COMMENT ON COLUMN flow_node.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_node.tenant_id IS '租户id'; + + +CREATE TABLE flow_skip +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 流程定义id + now_node_code varchar(100) NOT NULL, -- 当前流程节点的编码 + now_node_type int2 NULL, -- 当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + next_node_code varchar(100) NOT NULL, -- 下一个流程节点的编码 + next_node_type int2 NULL, -- 下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + skip_name varchar(100) NULL, -- 跳转名称 + skip_type varchar(40) NULL, -- 跳转类型(PASS审批通过 REJECT退回) + skip_condition varchar(200) NULL, -- 跳转条件 + coordinate varchar(100) NULL, -- 坐标 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_skip_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_skip IS '节点跳转关联表'; + +COMMENT ON COLUMN flow_skip.id IS '主键id'; +COMMENT ON COLUMN flow_skip.definition_id IS '流程定义id'; +COMMENT ON COLUMN flow_skip.now_node_code IS '当前流程节点的编码'; +COMMENT ON COLUMN flow_skip.now_node_type IS '当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_skip.next_node_code IS '下一个流程节点的编码'; +COMMENT ON COLUMN flow_skip.next_node_type IS '下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_skip.skip_name IS '跳转名称'; +COMMENT ON COLUMN flow_skip.skip_type IS '跳转类型(PASS审批通过 REJECT退回)'; +COMMENT ON COLUMN flow_skip.skip_condition IS '跳转条件'; +COMMENT ON COLUMN flow_skip.coordinate IS '坐标'; +COMMENT ON COLUMN flow_skip.create_time IS '创建时间'; +COMMENT ON COLUMN flow_skip.update_time IS '更新时间'; +COMMENT ON COLUMN flow_skip.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_skip.tenant_id IS '租户id'; + +CREATE TABLE flow_instance +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 对应flow_definition表的id + business_id varchar(40) NOT NULL, -- 业务id + node_type int2 NOT NULL, -- 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + node_code varchar(40) NOT NULL, -- 流程节点编码 + node_name varchar(100) NULL, -- 流程节点名称 + variable text NULL, -- 任务变量 + flow_status varchar(20) NOT NULL, -- 流程状态(0待提交 1审批中 2 审批通过 8已完成 9已退回 10失效) + activity_status int2 NOT NULL DEFAULT 1, -- 流程激活状态(0挂起 1激活) + def_json text NULL, -- 流程定义json + create_by varchar(64) NULL DEFAULT '':: character varying, -- 创建者 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + ext varchar(500) NULL, -- 扩展字段,预留给业务系统使用 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_instance_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_instance IS '流程实例表'; + +COMMENT ON COLUMN flow_instance.id IS '主键id'; +COMMENT ON COLUMN flow_instance.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_instance.business_id IS '业务id'; +COMMENT ON COLUMN flow_instance.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_instance.node_code IS '流程节点编码'; +COMMENT ON COLUMN flow_instance.node_name IS '流程节点名称'; +COMMENT ON COLUMN flow_instance.variable IS '任务变量'; +COMMENT ON COLUMN flow_instance.flow_status IS '流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回 8已完成 9已退回 10失效)'; +COMMENT ON COLUMN flow_instance.activity_status IS '流程激活状态(0挂起 1激活)'; +COMMENT ON COLUMN flow_instance.def_json IS '流程定义json'; +COMMENT ON COLUMN flow_instance.create_by IS '创建者'; +COMMENT ON COLUMN flow_instance.create_time IS '创建时间'; +COMMENT ON COLUMN flow_instance.update_time IS '更新时间'; +COMMENT ON COLUMN flow_instance.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_instance.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_instance.tenant_id IS '租户id'; + +CREATE TABLE flow_task +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 对应flow_definition表的id + instance_id int8 NOT NULL, -- 对应flow_instance表的id + node_code varchar(100) NOT NULL, -- 节点编码 + node_name varchar(100) NULL, -- 节点名称 + node_type int2 NOT NULL, -- 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_task_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_task IS '待办任务表'; + +COMMENT ON COLUMN flow_task.id IS '主键id'; +COMMENT ON COLUMN flow_task.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_task.instance_id IS '对应flow_instance表的id'; +COMMENT ON COLUMN flow_task.node_code IS '节点编码'; +COMMENT ON COLUMN flow_task.node_name IS '节点名称'; +COMMENT ON COLUMN flow_task.node_type IS '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_task.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_task.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_task.create_time IS '创建时间'; +COMMENT ON COLUMN flow_task.update_time IS '更新时间'; +COMMENT ON COLUMN flow_task.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_task.tenant_id IS '租户id'; + +CREATE TABLE flow_his_task +( + id int8 NOT NULL, -- 主键id + definition_id int8 NOT NULL, -- 对应flow_definition表的id + instance_id int8 NOT NULL, -- 对应flow_instance表的id + task_id int8 NOT NULL, -- 对应flow_task表的id + node_code varchar(200) NULL, -- 开始节点编码 + node_name varchar(200) NULL, -- 开始节点名称 + node_type int2 NULL, -- 开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) + target_node_code varchar(200) NULL, -- 目标节点编码 + target_node_name varchar(200) NULL, -- 结束节点名称 + approver varchar(40) NULL, -- 审批者 + cooperate_type int2 NOT NULL DEFAULT 0, -- 协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签) + collaborator varchar(40) NULL, -- 协作人(只有转办、会签、票签、委派) + skip_type varchar(10) NULL, -- 流转类型(PASS通过 REJECT退回 NONE无动作) + flow_status varchar(20) NOT NULL, -- 流程状态(0待提交 1审批中 2 审批通过 8已完成 9已退回 10失效) + form_custom bpchar(1) NULL DEFAULT 'N':: character varying, -- 审批表单是否自定义(Y是 N否) + form_path varchar(100) NULL, -- 审批表单路径 + ext varchar(500) NULL, -- 扩展字段,预留给业务系统使用 + message varchar(500) NULL, -- 审批意见 + variable text NULL, -- 任务变量 + create_time timestamp NULL, -- 创建时间 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_his_task_pkey PRIMARY KEY (id) +); +COMMENT ON TABLE flow_his_task IS '历史任务记录表'; + +COMMENT ON COLUMN flow_his_task.id IS '主键id'; +COMMENT ON COLUMN flow_his_task.definition_id IS '对应flow_definition表的id'; +COMMENT ON COLUMN flow_his_task.instance_id IS '对应flow_instance表的id'; +COMMENT ON COLUMN flow_his_task.task_id IS '对应flow_task表的id'; +COMMENT ON COLUMN flow_his_task.node_code IS '开始节点编码'; +COMMENT ON COLUMN flow_his_task.node_name IS '开始节点名称'; +COMMENT ON COLUMN flow_his_task.node_type IS '开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)'; +COMMENT ON COLUMN flow_his_task.target_node_code IS '目标节点编码'; +COMMENT ON COLUMN flow_his_task.target_node_name IS '结束节点名称'; +COMMENT ON COLUMN flow_his_task.approver IS '审批者'; +COMMENT ON COLUMN flow_his_task.cooperate_type IS '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)'; +COMMENT ON COLUMN flow_his_task.collaborator IS '协作人'; +COMMENT ON COLUMN flow_his_task.skip_type IS '流转类型(PASS通过 REJECT退回 NONE无动作)'; +COMMENT ON COLUMN flow_his_task.flow_status IS '流程状态(1审批中 2 审批通过 9已退回 10失效)'; +COMMENT ON COLUMN flow_his_task.form_custom IS '审批表单是否自定义(Y是 N否)'; +COMMENT ON COLUMN flow_his_task.form_path IS '审批表单路径'; +COMMENT ON COLUMN flow_his_task.message IS '审批意见'; +COMMENT ON COLUMN flow_his_task.variable IS '任务变量'; +COMMENT ON COLUMN flow_his_task.ext IS '扩展字段,预留给业务系统使用'; +COMMENT ON COLUMN flow_his_task.create_time IS '任务开始时间'; +COMMENT ON COLUMN flow_his_task.update_time IS '审批完成时间'; +COMMENT ON COLUMN flow_his_task.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_his_task.tenant_id IS '租户id'; + +CREATE TABLE flow_user +( + id int8 NOT NULL, -- 主键id + "type" bpchar(1) NOT NULL, -- 人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3流程实例的抄送人权限 4待办任务的委托人权限) + processed_by varchar(80) NULL, -- 权限人 + associated int8 NOT NULL, -- 任务表id + create_time timestamp NULL, -- 创建时间 + create_by varchar(80) NULL, -- 创建人 + update_time timestamp NULL, -- 更新时间 + del_flag bpchar(1) NULL DEFAULT '0':: character varying, -- 删除标志 + tenant_id varchar(40) NULL, -- 租户id + CONSTRAINT flow_user_pk PRIMARY KEY (id) +); +CREATE INDEX user_processed_type ON flow_user USING btree (processed_by, type); +COMMENT ON TABLE flow_user IS '流程用户表'; + +COMMENT ON COLUMN flow_user.id IS '主键id'; +COMMENT ON COLUMN flow_user."type" IS '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)'; +COMMENT ON COLUMN flow_user.processed_by IS '权限人'; +COMMENT ON COLUMN flow_user.associated IS '任务表id'; +COMMENT ON COLUMN flow_user.create_time IS '创建时间'; +COMMENT ON COLUMN flow_user.create_by IS '创建人'; +COMMENT ON COLUMN flow_user.update_time IS '更新时间'; +COMMENT ON COLUMN flow_user.del_flag IS '删除标志'; +COMMENT ON COLUMN flow_user.tenant_id IS '租户id'; + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +CREATE TABLE flow_category +( + category_id int8 NOT NULL, + tenant_id VARCHAR(20) DEFAULT '000000'::varchar, + parent_id int8 DEFAULT 0, + ancestors VARCHAR(500) DEFAULT ''::varchar, + category_name VARCHAR(30) NOT NULL, + order_num INT DEFAULT 0, + del_flag CHAR DEFAULT '0'::bpchar, + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + PRIMARY KEY (category_id) +); + +COMMENT ON TABLE flow_category IS '流程分类'; +COMMENT ON COLUMN flow_category.category_id IS '流程分类ID'; +COMMENT ON COLUMN flow_category.tenant_id IS '租户编号'; +COMMENT ON COLUMN flow_category.parent_id IS '父流程分类id'; +COMMENT ON COLUMN flow_category.ancestors IS '祖级列表'; +COMMENT ON COLUMN flow_category.category_name IS '流程分类名称'; +COMMENT ON COLUMN flow_category.order_num IS '显示顺序'; +COMMENT ON COLUMN flow_category.del_flag IS '删除标志(0代表存在 1代表删除)'; +COMMENT ON COLUMN flow_category.create_dept IS '创建部门'; +COMMENT ON COLUMN flow_category.create_by IS '创建者'; +COMMENT ON COLUMN flow_category.create_time IS '创建时间'; +COMMENT ON COLUMN flow_category.update_by IS '更新者'; +COMMENT ON COLUMN flow_category.update_time IS '更新时间'; + +INSERT INTO flow_category VALUES (100, '000000', 0, '0', 'OA审批', 0, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (101, '000000', 100, '0,100', '假勤管理', 0, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (102, '000000', 100, '0,100', '人事管理', 1, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (103, '000000', 101, '0,100,101', '请假', 0, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (104, '000000', 101, '0,100,101', '出差', 1, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (105, '000000', 101, '0,100,101', '加班', 2, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (106, '000000', 101, '0,100,101', '换班', 3, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (107, '000000', 101, '0,100,101', '外出', 4, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (108, '000000', 102, '0,100,102', '转正', 1, '0', 103, 1, now(), NULL, NULL); +INSERT INTO flow_category VALUES (109, '000000', 102, '0,100,102', '离职', 2, '0', 103, 1, now(), NULL, NULL); + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +CREATE TABLE test_leave +( + id int8 NOT NULL, + tenant_id VARCHAR(20) DEFAULT '000000'::varchar, + leave_type VARCHAR(255) NOT NULL, + start_date TIMESTAMP NOT NULL, + end_date TIMESTAMP NOT NULL, + leave_days int2 NOT NULL, + remark VARCHAR(255), + status VARCHAR(255), + create_dept int8, + create_by int8, + create_time TIMESTAMP, + update_by int8, + update_time TIMESTAMP, + PRIMARY KEY (id) +); + +COMMENT ON TABLE test_leave IS '请假申请表'; +COMMENT ON COLUMN test_leave.id IS 'id'; +COMMENT ON COLUMN test_leave.tenant_id IS '租户编号'; +COMMENT ON COLUMN test_leave.leave_type IS '请假类型'; +COMMENT ON COLUMN test_leave.start_date IS '开始时间'; +COMMENT ON COLUMN test_leave.end_date IS '结束时间'; +COMMENT ON COLUMN test_leave.leave_days IS '请假天数'; +COMMENT ON COLUMN test_leave.remark IS '请假原因'; +COMMENT ON COLUMN test_leave.status IS '状态'; +COMMENT ON COLUMN test_leave.create_dept IS '创建部门'; +COMMENT ON COLUMN test_leave.create_by IS '创建者'; +COMMENT ON COLUMN test_leave.create_time IS '创建时间'; +COMMENT ON COLUMN test_leave.update_by IS '更新者'; +COMMENT ON COLUMN test_leave.update_time IS '更新时间'; + +INSERT INTO sys_menu VALUES ('11616', '工作流', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11623', '流程分类查询', '11622', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11624', '流程分类新增', '11622', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11625', '流程分类修改', '11622', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11626', '流程分类删除', '11622', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11627', '流程分类导出', '11622', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:category:export', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11638', '请假申请', '5', '1', 'leave', 'workflow/leave/index', '', '1', '0', 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, now(), NULL, NULL, '请假申请菜单'); +INSERT INTO sys_menu VALUES ('11639', '请假申请查询', '11638', '1', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11640', '请假申请新增', '11638', '2', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11641', '请假申请修改', '11638', '3', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11642', '请假申请删除', '11638', '4', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, now(), NULL, NULL, ''); +INSERT INTO sys_menu VALUES ('11643', '请假申请导出', '11638', '5', '#', '', '', '1', '0', 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, now(), NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, now(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, now(), NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (15, '000000', '任务状态', 'wf_task_status', 103, 1, now(), NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已撤销'); +INSERT INTO sys_dict_data VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, now(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '已完成'); +INSERT INTO sys_dict_data VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已作废'); +INSERT INTO sys_dict_data VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已退回'); +INSERT INTO sys_dict_data VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, now(), NULL, NULL, '自定义表单'); +INSERT INTO sys_dict_data VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '动态表单'); +INSERT INTO sys_dict_data VALUES (48, '000000', 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (49, '000000', 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, now(), NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (50, '000000', 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (51, '000000', 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (52, '000000', 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (53, '000000', 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (54, '000000', 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (55, '000000', 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (56, '000000', 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (57, '000000', 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, now(), NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (58, '000000', 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (59, '000000', 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, now(), NULL, NULL, '超时'); + diff --git a/script/sql/ry_vue_5.X.sql b/script/sql/ry_vue_5.X.sql new file mode 100644 index 0000000..48e5f35 --- /dev/null +++ b/script/sql/ry_vue_5.X.sql @@ -0,0 +1,962 @@ +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id bigint not null comment '主键', + user_id bigint not null comment '用户ID', + tenant_id varchar(20) default '000000' comment '租户id', + auth_id varchar(255) not null comment '平台+平台唯一id', + source varchar(255) not null comment '用户来源', + open_id varchar(255) default null comment '平台编号唯一id', + user_name varchar(30) not null comment '登录账号', + nick_name varchar(30) default '' comment '用户昵称', + email varchar(255) default '' comment '用户邮箱', + avatar varchar(500) default '' comment '头像地址', + access_token varchar(255) not null comment '用户的授权令牌', + expire_in int default null comment '用户的授权令牌的有效期,部分平台可能没有', + refresh_token varchar(255) default null comment '刷新令牌,部分平台可能没有', + access_code varchar(255) default null comment '平台的授权信息,部分平台可能没有', + union_id varchar(255) default null comment '用户的 unionid', + scope varchar(255) default null comment '授予的权限,部分平台可能没有', + token_type varchar(255) default null comment '个别平台的授权信息,部分平台可能没有', + id_token varchar(2000) default null comment 'id token,部分平台可能没有', + mac_algorithm varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + mac_key varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + code varchar(255) default null comment '用户的授权code,部分平台可能没有', + oauth_token varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + oauth_token_secret varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + PRIMARY KEY (id) +) engine=innodb comment = '社会化关系表'; + + +-- ---------------------------- +-- 租户表 +-- ---------------------------- +create table sys_tenant +( + id bigint(20) not null comment 'id', + tenant_id varchar(20) not null comment '租户编号', + contact_user_name varchar(20) comment '联系人', + contact_phone varchar(20) comment '联系电话', + company_name varchar(50) comment '企业名称', + license_number varchar(30) comment '统一社会信用代码', + address varchar(200) comment '地址', + intro varchar(200) comment '企业简介', + domain varchar(200) comment '域名', + remark varchar(200) comment '备注', + package_id bigint(20) comment '租户套餐编号', + expire_time datetime comment '过期时间', + account_count int default -1 comment '用户数量(-1不限制)', + status char(1) default '0' comment '租户状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + primary key (id) +) engine=innodb comment = '租户表'; + + +-- ---------------------------- +-- 初始化-租户表数据 +-- ---------------------------- + +insert into sys_tenant values(1, '000000', '管理组', '15888888888', 'XXX有限公司', null, null, '多租户通用后台管理管理系统', null, null, null, null, -1, '0', '0', 103, 1, sysdate(), null, null); + + +-- ---------------------------- +-- 租户套餐表 +-- ---------------------------- +create table sys_tenant_package ( + package_id bigint(20) not null comment '租户套餐id', + package_name varchar(20) comment '套餐名称', + menu_ids varchar(3000) comment '关联菜单id', + remark varchar(200) comment '备注', + menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示', + status char(1) default '0' comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + primary key (package_id) +) engine=innodb comment = '租户套餐表'; + + +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +create table sys_dept ( + dept_id bigint(20) not null comment '部门id', + tenant_id varchar(20) default '000000' comment '租户编号', + parent_id bigint(20) default 0 comment '父部门id', + ancestors varchar(500) default '' comment '祖级列表', + dept_name varchar(30) default '' comment '部门名称', + dept_category varchar(100) default null comment '部门类别编码', + order_num int(4) default 0 comment '显示顺序', + leader bigint(20) default null comment '负责人', + phone varchar(11) default null comment '联系电话', + email varchar(50) default null comment '邮箱', + status char(1) default '0' comment '部门状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (dept_id) +) engine=innodb comment = '部门表'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- + + +insert into sys_dept values(100, '000000', 0, '0', 'XXX科技', null,0, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(101, '000000', 100, '0,100', '深圳总公司', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(102, '000000', 100, '0,100', '长沙分公司', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(103, '000000', 101, '0,100,101', '研发部门', null,1, 1, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(104, '000000', 101, '0,100,101', '市场部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(105, '000000', 101, '0,100,101', '测试部门', null,3, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(106, '000000', 101, '0,100,101', '财务部门', null,4, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(107, '000000', 101, '0,100,101', '运维部门', null,5, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(108, '000000', 102, '0,100,102', '市场部门', null,1, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); +insert into sys_dept values(109, '000000', 102, '0,100,102', '财务部门', null,2, null, '15888888888', 'xxx@qq.com', '0', '0', 103, 1, sysdate(), null, null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +create table sys_user ( + user_id bigint(20) not null comment '用户ID', + tenant_id varchar(20) default '000000' comment '租户编号', + dept_id bigint(20) default null comment '部门ID', + user_name varchar(30) not null comment '用户账号', + nick_name varchar(30) not null comment '用户昵称', + user_type varchar(10) default 'sys_user' comment '用户类型(sys_user系统用户)', + email varchar(50) default '' comment '用户邮箱', + phonenumber varchar(11) default '' comment '手机号码', + sex char(1) default '0' comment '用户性别(0男 1女 2未知)', + avatar bigint(20) comment '头像地址', + password varchar(100) default '' comment '密码', + status char(1) default '0' comment '帐号状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + login_ip varchar(128) default '' comment '最后登录IP', + login_date datetime comment '最后登录时间', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (user_id) +) engine=innodb comment = '用户信息表'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, '000000', 103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', null, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), null, null, '管理员'); +insert into sys_user values(3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 3, sysdate(), null); +insert into sys_user values(4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', null, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', sysdate(), 103, 1, sysdate(), 4, sysdate(), null); + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +create table sys_post +( + post_id bigint(20) not null comment '岗位ID', + tenant_id varchar(20) default '000000' comment '租户编号', + dept_id bigint(20) not null comment '部门id', + post_code varchar(64) not null comment '岗位编码', + post_category varchar(100) default null comment '岗位类别编码', + post_name varchar(50) not null comment '岗位名称', + post_sort int(4) not null comment '显示顺序', + status char(1) not null comment '状态(0正常 1停用)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (post_id) +) engine=innodb comment = '岗位信息表'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, '000000', 103, 'ceo', null, '董事长', 1, '0', 103, 1, sysdate(), null, null, ''); +insert into sys_post values(2, '000000', 100, 'se', null, '项目经理', 2, '0', 103, 1, sysdate(), null, null, ''); +insert into sys_post values(3, '000000', 100, 'hr', null, '人力资源', 3, '0', 103, 1, sysdate(), null, null, ''); +insert into sys_post values(4, '000000', 100, 'user', null, '普通员工', 4, '0', 103, 1, sysdate(), null, null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +create table sys_role ( + role_id bigint(20) not null comment '角色ID', + tenant_id varchar(20) default '000000' comment '租户编号', + role_name varchar(30) not null comment '角色名称', + role_key varchar(100) not null comment '角色权限字符串', + role_sort int(4) not null comment '显示顺序', + data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示', + dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示', + status char(1) not null comment '角色状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (role_id) +) engine=innodb comment = '角色信息表'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values(1, '000000', '超级管理员', 'superadmin', 1, 1, 1, 1, '0', '0', 103, 1, sysdate(), null, null, '超级管理员'); +insert into sys_role values(3, '000000', '本部门及以下', 'test1', 3, 4, 1, 1, '0', '0', 103, 1, sysdate(), null, null, ''); +insert into sys_role values(4, '000000', '仅本人', 'test2', 4, 5, 1, 1, '0', '0', 103, 1, sysdate(), null, null, ''); + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +create table sys_menu ( + menu_id bigint(20) not null comment '菜单ID', + menu_name varchar(50) not null comment '菜单名称', + parent_id bigint(20) default 0 comment '父菜单ID', + order_num int(4) default 0 comment '显示顺序', + path varchar(200) default '' comment '路由地址', + component varchar(255) default null comment '组件路径', + query_param varchar(255) default null comment '路由参数', + is_frame int(1) default 1 comment '是否为外链(0是 1否)', + is_cache int(1) default 0 comment '是否缓存(0缓存 1不缓存)', + menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)', + visible char(1) default 0 comment '显示状态(0显示 1隐藏)', + status char(1) default 0 comment '菜单状态(0正常 1停用)', + perms varchar(100) default null comment '权限标识', + icon varchar(100) default '#' comment '菜单图标', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注', + primary key (menu_id) +) engine=innodb comment = '菜单权限表'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', 1, 0, 'M', '0', '0', '', 'system', 103, 1, sysdate(), null, null, '系统管理目录'); +insert into sys_menu values('6', '租户管理', '0', '2', 'tenant', null, '', 1, 0, 'M', '0', '0', '', 'chart', 103, 1, sysdate(), null, null, '租户管理目录'); +insert into sys_menu values('2', '系统监控', '0', '3', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), null, null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '4', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 103, 1, sysdate(), null, null, '系统工具目录'); +insert into sys_menu values('4', 'PLUS官网', '0', '5', 'https://gitee.com/dromara/RuoYi-Vue-Plus', null, '', 0, 0, 'M', '0', '0', '', 'guide', 103, 1, sysdate(), null, null, 'RuoYi-Vue-Plus官网地址'); +insert into sys_menu values('5', '测试菜单', '0', '5', 'demo', null, '', 1, 0, 'M', '0', '0', '', 'star', 103, 1, sysdate(), null, null, '测试菜单'); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 103, 1, sysdate(), null, null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 103, 1, sysdate(), null, null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 103, 1, sysdate(), null, null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 103, 1, sysdate(), null, null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 103, 1, sysdate(), null, null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 103, 1, sysdate(), null, null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 103, 1, sysdate(), null, null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 103, 1, sysdate(), null, null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 103, 1, sysdate(), null, null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 103, 1, sysdate(), null, null, '在线用户菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 103, 1, sysdate(), null, null, '缓存监控菜单'); +insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 103, 1, sysdate(), null, null, '代码生成菜单'); +insert into sys_menu values('121', '租户管理', '6', '1', 'tenant', 'system/tenant/index', '', 1, 0, 'C', '0', '0', 'system:tenant:list', 'list', 103, 1, sysdate(), null, null, '租户管理菜单'); +insert into sys_menu values('122', '租户套餐管理', '6', '2', 'tenantPackage', 'system/tenantPackage/index', '', 1, 0, 'C', '0', '0', 'system:tenantPackage:list', 'form', 103, 1, sysdate(), null, null, '租户套餐管理菜单'); +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate(), null, null, '客户端管理菜单'); + +-- springboot-admin监控 +insert into sys_menu values('117', 'Admin监控', '2', '5', 'Admin', 'monitor/admin/index', '', 1, 0, 'C', '0', '0', 'monitor:admin:list', 'dashboard', 103, 1, sysdate(), null, null, 'Admin监控菜单'); +-- oss菜单 +insert into sys_menu values('118', '文件管理', '1', '10', 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 103, 1, sysdate(), null, null, '文件管理菜单'); +-- snail-job server控制台 +insert into sys_menu values('120', '任务调度中心', '2', '6', 'snailjob', 'monitor/snailjob/index', '', 1, 0, 'C', '0', '0', 'monitor:snailjob:list', 'job', 103, 1, sysdate(), null, null, 'SnailJob控制台菜单'); + +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 103, 1, sysdate(), null, null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 103, 1, sysdate(), null, null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1001', '用户查询', '100', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1002', '用户新增', '100', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1003', '用户修改', '100', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1004', '用户删除', '100', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1005', '用户导出', '100', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1006', '用户导入', '100', '6', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1007', '重置密码', '100', '7', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 103, 1, sysdate(), null, null, ''); +-- 角色管理按钮 +insert into sys_menu values('1008', '角色查询', '101', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1009', '角色新增', '101', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1010', '角色修改', '101', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1011', '角色删除', '101', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1012', '角色导出', '101', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 103, 1, sysdate(), null, null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 103, 1, sysdate(), null, null, ''); +-- 部门管理按钮 +insert into sys_menu values('1017', '部门查询', '103', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1018', '部门新增', '103', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1019', '部门修改', '103', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1020', '部门删除', '103', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 103, 1, sysdate(), null, null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 103, 1, sysdate(), null, null, ''); +-- 字典管理按钮 +insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 103, 1, sysdate(), null, null, ''); +-- 参数设置按钮 +insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 103, 1, sysdate(), null, null, ''); +-- 通知公告按钮 +insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 103, 1, sysdate(), null, null, ''); +-- 操作日志按钮 +insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 103, 1, sysdate(), null, null, ''); +-- 登录日志按钮 +insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate(), null, null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 103, 1, sysdate(), null, null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 103, 1, sysdate(), null, null, ''); +-- oss相关按钮 +insert into sys_menu values('1600', '文件查询', '118', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1601', '文件上传', '118', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1602', '文件下载', '118', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1603', '文件删除', '118', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove', '#', 103, 1, sysdate(), null, null, ''); +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, ''); + +-- 租户管理相关按钮 +insert into sys_menu values ('1606', '租户查询', '121', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1607', '租户新增', '121', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1608', '租户修改', '121', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1609', '租户删除', '121', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1610', '租户导出', '121', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenant:export', '#', 103, 1, sysdate(), null, null, ''); +-- 租户套餐管理相关按钮 +insert into sys_menu values ('1611', '租户套餐查询', '122', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1612', '租户套餐新增', '122', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1613', '租户套餐修改', '122', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1614', '租户套餐删除', '122', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values ('1615', '租户套餐导出', '122', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:tenantPackage:export', '#', 103, 1, sysdate(), null, null, ''); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate(), null, null, ''); +-- 测试菜单 +insert into sys_menu values('1500', '测试单表', '5', '1', 'demo', 'demo/demo/index', '', 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 103, 1, sysdate(), null, null, '测试单表菜单'); +insert into sys_menu values('1501', '测试单表查询', '1500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1502', '测试单表新增', '1500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1503', '测试单表修改', '1500', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1504', '测试单表删除', '1500', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1505', '测试单表导出', '1500', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1506', '测试树表', '5', '1', 'tree', 'demo/tree/index', '', 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 103, 1, sysdate(), null, null, '测试树表菜单'); +insert into sys_menu values('1507', '测试树表查询', '1506', '1', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1508', '测试树表新增', '1506', '2', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1509', '测试树表修改', '1506', '3', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1510', '测试树表删除', '1506', '4', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1511', '测试树表导出', '1506', '5', '#', '', '', 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 103, 1, sysdate(), null, null, ''); + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +create table sys_user_role ( + user_id bigint(20) not null comment '用户ID', + role_id bigint(20) not null comment '角色ID', + primary key(user_id, role_id) +) engine=innodb comment = '用户和角色关联表'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('3', '3'); +insert into sys_user_role values ('4', '4'); + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +create table sys_role_menu ( + role_id bigint(20) not null comment '角色ID', + menu_id bigint(20) not null comment '菜单ID', + primary key(role_id, menu_id) +) engine=innodb comment = '角色和菜单关联表'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('3', '1'); +insert into sys_role_menu values ('3', '5'); +insert into sys_role_menu values ('3', '100'); +insert into sys_role_menu values ('3', '101'); +insert into sys_role_menu values ('3', '102'); +insert into sys_role_menu values ('3', '103'); +insert into sys_role_menu values ('3', '104'); +insert into sys_role_menu values ('3', '105'); +insert into sys_role_menu values ('3', '106'); +insert into sys_role_menu values ('3', '107'); +insert into sys_role_menu values ('3', '108'); +insert into sys_role_menu values ('3', '118'); +insert into sys_role_menu values ('3', '123'); +insert into sys_role_menu values ('3', '500'); +insert into sys_role_menu values ('3', '501'); +insert into sys_role_menu values ('3', '1001'); +insert into sys_role_menu values ('3', '1002'); +insert into sys_role_menu values ('3', '1003'); +insert into sys_role_menu values ('3', '1004'); +insert into sys_role_menu values ('3', '1005'); +insert into sys_role_menu values ('3', '1006'); +insert into sys_role_menu values ('3', '1007'); +insert into sys_role_menu values ('3', '1008'); +insert into sys_role_menu values ('3', '1009'); +insert into sys_role_menu values ('3', '1010'); +insert into sys_role_menu values ('3', '1011'); +insert into sys_role_menu values ('3', '1012'); +insert into sys_role_menu values ('3', '1013'); +insert into sys_role_menu values ('3', '1014'); +insert into sys_role_menu values ('3', '1015'); +insert into sys_role_menu values ('3', '1016'); +insert into sys_role_menu values ('3', '1017'); +insert into sys_role_menu values ('3', '1018'); +insert into sys_role_menu values ('3', '1019'); +insert into sys_role_menu values ('3', '1020'); +insert into sys_role_menu values ('3', '1021'); +insert into sys_role_menu values ('3', '1022'); +insert into sys_role_menu values ('3', '1023'); +insert into sys_role_menu values ('3', '1024'); +insert into sys_role_menu values ('3', '1025'); +insert into sys_role_menu values ('3', '1026'); +insert into sys_role_menu values ('3', '1027'); +insert into sys_role_menu values ('3', '1028'); +insert into sys_role_menu values ('3', '1029'); +insert into sys_role_menu values ('3', '1030'); +insert into sys_role_menu values ('3', '1031'); +insert into sys_role_menu values ('3', '1032'); +insert into sys_role_menu values ('3', '1033'); +insert into sys_role_menu values ('3', '1034'); +insert into sys_role_menu values ('3', '1035'); +insert into sys_role_menu values ('3', '1036'); +insert into sys_role_menu values ('3', '1037'); +insert into sys_role_menu values ('3', '1038'); +insert into sys_role_menu values ('3', '1039'); +insert into sys_role_menu values ('3', '1040'); +insert into sys_role_menu values ('3', '1041'); +insert into sys_role_menu values ('3', '1042'); +insert into sys_role_menu values ('3', '1043'); +insert into sys_role_menu values ('3', '1044'); +insert into sys_role_menu values ('3', '1045'); +insert into sys_role_menu values ('3', '1050'); +insert into sys_role_menu values ('3', '1061'); +insert into sys_role_menu values ('3', '1062'); +insert into sys_role_menu values ('3', '1063'); +insert into sys_role_menu values ('3', '1064'); +insert into sys_role_menu values ('3', '1065'); +insert into sys_role_menu values ('3', '1500'); +insert into sys_role_menu values ('3', '1501'); +insert into sys_role_menu values ('3', '1502'); +insert into sys_role_menu values ('3', '1503'); +insert into sys_role_menu values ('3', '1504'); +insert into sys_role_menu values ('3', '1505'); +insert into sys_role_menu values ('3', '1506'); +insert into sys_role_menu values ('3', '1507'); +insert into sys_role_menu values ('3', '1508'); +insert into sys_role_menu values ('3', '1509'); +insert into sys_role_menu values ('3', '1510'); +insert into sys_role_menu values ('3', '1511'); +insert into sys_role_menu values ('3', '1600'); +insert into sys_role_menu values ('3', '1601'); +insert into sys_role_menu values ('3', '1602'); +insert into sys_role_menu values ('3', '1603'); +insert into sys_role_menu values ('3', '1620'); +insert into sys_role_menu values ('3', '1621'); +insert into sys_role_menu values ('3', '1622'); +insert into sys_role_menu values ('3', '1623'); +insert into sys_role_menu values ('3', '11618'); +insert into sys_role_menu values ('3', '11619'); +insert into sys_role_menu values ('3', '11629'); +insert into sys_role_menu values ('3', '11632'); +insert into sys_role_menu values ('3', '11633'); +insert into sys_role_menu values ('3', '11638'); +insert into sys_role_menu values ('3', '11639'); +insert into sys_role_menu values ('3', '11640'); +insert into sys_role_menu values ('3', '11641'); +insert into sys_role_menu values ('3', '11642'); +insert into sys_role_menu values ('3', '11643'); +insert into sys_role_menu values ('4', '5'); +insert into sys_role_menu values ('4', '1500'); +insert into sys_role_menu values ('4', '1501'); +insert into sys_role_menu values ('4', '1502'); +insert into sys_role_menu values ('4', '1503'); +insert into sys_role_menu values ('4', '1504'); +insert into sys_role_menu values ('4', '1505'); +insert into sys_role_menu values ('4', '1506'); +insert into sys_role_menu values ('4', '1507'); +insert into sys_role_menu values ('4', '1508'); +insert into sys_role_menu values ('4', '1509'); +insert into sys_role_menu values ('4', '1510'); +insert into sys_role_menu values ('4', '1511'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +create table sys_role_dept ( + role_id bigint(20) not null comment '角色ID', + dept_id bigint(20) not null comment '部门ID', + primary key(role_id, dept_id) +) engine=innodb comment = '角色和部门关联表'; + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +create table sys_user_post +( + user_id bigint(20) not null comment '用户ID', + post_id bigint(20) not null comment '岗位ID', + primary key (user_id, post_id) +) engine=innodb comment = '用户与岗位关联表'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +create table sys_oper_log ( + oper_id bigint(20) not null comment '日志主键', + tenant_id varchar(20) default '000000' comment '租户编号', + title varchar(50) default '' comment '模块标题', + business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)', + method varchar(100) default '' comment '方法名称', + request_method varchar(10) default '' comment '请求方式', + operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)', + oper_name varchar(50) default '' comment '操作人员', + dept_name varchar(50) default '' comment '部门名称', + oper_url varchar(255) default '' comment '请求URL', + oper_ip varchar(128) default '' comment '主机地址', + oper_location varchar(255) default '' comment '操作地点', + oper_param varchar(4000) default '' comment '请求参数', + json_result varchar(4000) default '' comment '返回参数', + status int(1) default 0 comment '操作状态(0正常 1异常)', + error_msg varchar(4000) default '' comment '错误消息', + oper_time datetime comment '操作时间', + cost_time bigint(20) default 0 comment '消耗时间', + primary key (oper_id), + key idx_sys_oper_log_bt (business_type), + key idx_sys_oper_log_s (status), + key idx_sys_oper_log_ot (oper_time) +) engine=innodb comment = '操作日志记录'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +create table sys_dict_type +( + dict_id bigint(20) not null comment '字典主键', + tenant_id varchar(20) default '000000' comment '租户编号', + dict_name varchar(100) default '' comment '字典名称', + dict_type varchar(100) default '' comment '字典类型', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_id), + unique (tenant_id, dict_type) +) engine=innodb comment = '字典类型表'; + +insert into sys_dict_type values(1, '000000', '用户性别', 'sys_user_sex', 103, 1, sysdate(), null, null, '用户性别列表'); +insert into sys_dict_type values(2, '000000', '菜单状态', 'sys_show_hide', 103, 1, sysdate(), null, null, '菜单状态列表'); +insert into sys_dict_type values(3, '000000', '系统开关', 'sys_normal_disable', 103, 1, sysdate(), null, null, '系统开关列表'); +insert into sys_dict_type values(6, '000000', '系统是否', 'sys_yes_no', 103, 1, sysdate(), null, null, '系统是否列表'); +insert into sys_dict_type values(7, '000000', '通知类型', 'sys_notice_type', 103, 1, sysdate(), null, null, '通知类型列表'); +insert into sys_dict_type values(8, '000000', '通知状态', 'sys_notice_status', 103, 1, sysdate(), null, null, '通知状态列表'); +insert into sys_dict_type values(9, '000000', '操作类型', 'sys_oper_type', 103, 1, sysdate(), null, null, '操作类型列表'); +insert into sys_dict_type values(10, '000000', '系统状态', 'sys_common_status', 103, 1, sysdate(), null, null, '登录状态列表'); +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, sysdate(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, sysdate(), null, null, '客户端设备类型'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +create table sys_dict_data +( + dict_code bigint(20) not null comment '字典编码', + tenant_id varchar(20) default '000000' comment '租户编号', + dict_sort int(4) default 0 comment '字典排序', + dict_label varchar(100) default '' comment '字典标签', + dict_value varchar(100) default '' comment '字典键值', + dict_type varchar(100) default '' comment '字典类型', + css_class varchar(100) default null comment '样式属性(其他样式扩展)', + list_class varchar(100) default null comment '表格回显样式', + is_default char(1) default 'N' comment '是否默认(Y是 N否)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_code) +) engine=innodb comment = '字典数据表'; + +insert into sys_dict_data values(1, '000000', 1, '男', '0', 'sys_user_sex', '', '', 'Y', 103, 1, sysdate(), null, null, '性别男'); +insert into sys_dict_data values(2, '000000', 2, '女', '1', 'sys_user_sex', '', '', 'N', 103, 1, sysdate(), null, null, '性别女'); +insert into sys_dict_data values(3, '000000', 3, '未知', '2', 'sys_user_sex', '', '', 'N', 103, 1, sysdate(), null, null, '性别未知'); +insert into sys_dict_data values(4, '000000', 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '显示菜单'); +insert into sys_dict_data values(5, '000000', 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', 103, 1, sysdate(), null, null, '隐藏菜单'); +insert into sys_dict_data values(6, '000000', 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(7, '000000', 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', 103, 1, sysdate(), null, null, '停用状态'); +insert into sys_dict_data values(12, '000000', 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '系统默认是'); +insert into sys_dict_data values(13, '000000', 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', 103, 1, sysdate(), null, null, '系统默认否'); +insert into sys_dict_data values(14, '000000', 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', 103, 1, sysdate(), null, null, '通知'); +insert into sys_dict_data values(15, '000000', 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', 103, 1, sysdate(), null, null, '公告'); +insert into sys_dict_data values(16, '000000', 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', 103, 1, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(17, '000000', 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', 103, 1, sysdate(), null, null, '关闭状态'); +insert into sys_dict_data values(29, '000000', 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate(), null, null, '其他操作'); +insert into sys_dict_data values(18, '000000', 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate(), null, null, '新增操作'); +insert into sys_dict_data values(19, '000000', 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', 103, 1, sysdate(), null, null, '修改操作'); +insert into sys_dict_data values(20, '000000', 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate(), null, null, '删除操作'); +insert into sys_dict_data values(21, '000000', 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', 103, 1, sysdate(), null, null, '授权操作'); +insert into sys_dict_data values(22, '000000', 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate(), null, null, '导出操作'); +insert into sys_dict_data values(23, '000000', 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate(), null, null, '导入操作'); +insert into sys_dict_data values(24, '000000', 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate(), null, null, '强退操作'); +insert into sys_dict_data values(25, '000000', 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', 103, 1, sysdate(), null, null, '生成操作'); +insert into sys_dict_data values(26, '000000', 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', 103, 1, sysdate(), null, null, '清空操作'); +insert into sys_dict_data values(27, '000000', 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', 103, 1, sysdate(), null, null, '正常状态'); +insert into sys_dict_data values(28, '000000', 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', 103, 1, sysdate(), null, null, '停用状态'); +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', 'el-check-tag', 'default', 'N', 103, 1, sysdate(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '小程序'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +create table sys_config ( + config_id bigint(20) not null comment '参数主键', + tenant_id varchar(20) default '000000' comment '租户编号', + config_name varchar(100) default '' comment '参数名称', + config_key varchar(100) default '' comment '参数键名', + config_value varchar(500) default '' comment '参数键值', + config_type char(1) default 'N' comment '系统内置(Y是 N否)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (config_id) +) engine=innodb comment = '参数配置表'; + +insert into sys_config values(1, '000000', '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 103, 1, sysdate(), null, null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '000000', '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 103, 1, sysdate(), null, null, '初始化密码 123456' ); +insert into sys_config values(3, '000000', '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 103, 1, sysdate(), null, null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(5, '000000', '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 103, 1, sysdate(), null, null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(11, '000000', 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 103, 1, sysdate(), null, null, 'true:开启, false:关闭'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +create table sys_logininfor ( + info_id bigint(20) not null comment '访问ID', + tenant_id varchar(20) default '000000' comment '租户编号', + user_name varchar(50) default '' comment '用户账号', + client_key varchar(32) default '' comment '客户端', + device_type varchar(32) default '' comment '设备类型', + ipaddr varchar(128) default '' comment '登录IP地址', + login_location varchar(255) default '' comment '登录地点', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status char(1) default '0' comment '登录状态(0成功 1失败)', + msg varchar(255) default '' comment '提示消息', + login_time datetime comment '访问时间', + primary key (info_id), + key idx_sys_logininfor_s (status), + key idx_sys_logininfor_lt (login_time) +) engine=innodb comment = '系统访问记录'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +create table sys_notice ( + notice_id bigint(20) not null comment '公告ID', + tenant_id varchar(20) default '000000' comment '租户编号', + notice_title varchar(50) not null comment '公告标题', + notice_type char(1) not null comment '公告类型(1通知 2公告)', + notice_content longblob default null comment '公告内容', + status char(1) default '0' comment '公告状态(0正常 1关闭)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(255) default null comment '备注', + primary key (notice_id) +) engine=innodb comment = '通知公告表'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '000000', '温馨提醒:2018-07-01 新版本发布啦', '2', '新版本内容', '0', 103, 1, sysdate(), null, null, '管理员'); +insert into sys_notice values('2', '000000', '维护通知:2018-07-01 系统凌晨维护', '1', '维护内容', '0', 103, 1, sysdate(), null, null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +create table gen_table ( + table_id bigint(20) not null comment '编号', + data_name varchar(200) default '' comment '数据源名称', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + sub_table_name varchar(64) default null comment '关联子表的表名', + sub_table_fk_name varchar(64) default null comment '子表关联的外键名', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (table_id) +) engine=innodb comment = '代码生成业务表'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +create table gen_table_column ( + column_id bigint(20) not null comment '编号', + table_id bigint(20) comment '归属表编号', + column_name varchar(200) comment '列名称', + column_comment varchar(500) comment '列描述', + column_type varchar(100) comment '列类型', + java_type varchar(500) comment 'JAVA类型', + java_field varchar(200) comment 'JAVA字段名', + is_pk char(1) comment '是否主键(1是)', + is_increment char(1) comment '是否自增(1是)', + is_required char(1) comment '是否必填(1是)', + is_insert char(1) comment '是否为插入字段(1是)', + is_edit char(1) comment '是否编辑字段(1是)', + is_list char(1) comment '是否列表字段(1是)', + is_query char(1) comment '是否查询字段(1是)', + query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)', + html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + dict_type varchar(200) default '' comment '字典类型', + sort int comment '排序', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime comment '更新时间', + primary key (column_id) +) engine=innodb comment = '代码生成业务表字段'; + +-- ---------------------------- +-- OSS对象存储表 +-- ---------------------------- +create table sys_oss ( + oss_id bigint(20) not null comment '对象存储主键', + tenant_id varchar(20) default '000000' comment '租户编号', + file_name varchar(255) not null default '' comment '文件名', + original_name varchar(255) not null default '' comment '原名', + file_suffix varchar(10) not null default '' comment '文件后缀名', + url varchar(500) not null comment 'URL地址', + create_dept bigint(20) default null comment '创建部门', + create_time datetime default null comment '创建时间', + create_by bigint(20) default null comment '上传人', + update_time datetime default null comment '更新时间', + update_by bigint(20) default null comment '更新人', + service varchar(20) not null default 'minio' comment '服务商', + primary key (oss_id) +) engine=innodb comment ='OSS对象存储表'; + +-- ---------------------------- +-- OSS对象存储动态配置表 +-- ---------------------------- +create table sys_oss_config ( + oss_config_id bigint(20) not null comment '主键', + tenant_id varchar(20) default '000000'comment '租户编号', + config_key varchar(20) not null default '' comment '配置key', + access_key varchar(255) default '' comment 'accessKey', + secret_key varchar(255) default '' comment '秘钥', + bucket_name varchar(255) default '' comment '桶名称', + prefix varchar(255) default '' comment '前缀', + endpoint varchar(255) default '' comment '访问站点', + domain varchar(255) default '' comment '自定义域名', + is_https char(1) default 'N' comment '是否https(Y=是,N=否)', + region varchar(255) default '' comment '域', + access_policy char(1) not null default '1' comment '桶权限类型(0=private 1=public 2=custom)', + status char(1) default '1' comment '是否默认(0=是,1=否)', + ext1 varchar(255) default '' comment '扩展字段', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (oss_config_id) +) engine=innodb comment='对象存储配置表'; + +insert into sys_oss_config values (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '','N', '', '1' ,'0', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (4, '000000', 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1240000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); +insert into sys_oss_config values (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '','N', '', '1' ,'1', '', 103, 1, sysdate(), 1, sysdate(), null); + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id bigint(20) not null comment 'id', + client_id varchar(64) default null comment '客户端id', + client_key varchar(32) default null comment '客户端key', + client_secret varchar(255) default null comment '客户端秘钥', + grant_type varchar(255) default null comment '授权类型', + device_type varchar(32) default null comment '设备类型', + active_timeout int(11) default 1800 comment 'token活跃超时时间', + timeout int(11) default 604800 comment 'token固定超时', + status char(1) default '0' comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + primary key (id) +) engine=innodb comment='系统授权表'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); + + +CREATE TABLE test_demo +( + id bigint(0) NOT NULL COMMENT '主键', + tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + order_num int(0) NULL DEFAULT 0 COMMENT '排序号', + test_key varchar(255) NULL DEFAULT NULL COMMENT 'key键', + value varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试单表'; + +CREATE TABLE test_tree +( + id bigint(0) NOT NULL COMMENT '主键', + tenant_id varchar(20) NULL DEFAULT '000000' COMMENT '租户编号', + parent_id bigint(0) NULL DEFAULT 0 COMMENT '父id', + dept_id bigint(0) NULL DEFAULT NULL COMMENT '部门id', + user_id bigint(0) NULL DEFAULT NULL COMMENT '用户id', + tree_name varchar(255) NULL DEFAULT NULL COMMENT '值', + version int(0) NULL DEFAULT 0 COMMENT '版本', + create_dept bigint(0) NULL DEFAULT NULL COMMENT '创建部门', + create_time datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + create_by bigint(0) NULL DEFAULT NULL COMMENT '创建人', + update_time datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + update_by bigint(0) NULL DEFAULT NULL COMMENT '更新人', + del_flag int(0) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '测试树表'; + +INSERT INTO test_demo VALUES (1, '000000', 102, 4, 1, '测试数据权限', '测试', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (2, '000000', 102, 3, 2, '子节点1', '111', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (3, '000000', 102, 3, 3, '子节点2', '222', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (4, '000000', 108, 4, 4, '测试数据', 'demo', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (5, '000000', 108, 3, 13, '子节点11', '1111', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (6, '000000', 108, 3, 12, '子节点22', '2222', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (7, '000000', 108, 3, 11, '子节点33', '3333', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (8, '000000', 108, 3, 10, '子节点44', '4444', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (9, '000000', 108, 3, 9, '子节点55', '5555', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (10, '000000', 108, 3, 8, '子节点66', '6666', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (11, '000000', 108, 3, 7, '子节点77', '7777', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (12, '000000', 108, 3, 6, '子节点88', '8888', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_demo VALUES (13, '000000', 108, 3, 5, '子节点99', '9999', 0, 103, sysdate(), 1, NULL, NULL, 0); + +INSERT INTO test_tree VALUES (1, '000000', 0, 102, 4, '测试数据权限', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (2, '000000', 1, 102, 3, '子节点1', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (3, '000000', 2, 102, 3, '子节点2', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (4, '000000', 0, 108, 4, '测试树1', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (5, '000000', 4, 108, 3, '子节点11', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (6, '000000', 4, 108, 3, '子节点22', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (7, '000000', 4, 108, 3, '子节点33', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (8, '000000', 5, 108, 3, '子节点44', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (9, '000000', 6, 108, 3, '子节点55', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (10, '000000', 7, 108, 3, '子节点66', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (11, '000000', 7, 108, 3, '子节点77', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (12, '000000', 10, 108, 3, '子节点88', 0, 103, sysdate(), 1, NULL, NULL, 0); +INSERT INTO test_tree VALUES (13, '000000', 10, 108, 3, '子节点99', 0, 103, sysdate(), 1, NULL, NULL, 0); diff --git a/script/sql/ry_workflow.sql b/script/sql/ry_workflow.sql new file mode 100644 index 0000000..9455636 --- /dev/null +++ b/script/sql/ry_workflow.sql @@ -0,0 +1,253 @@ +-- ---------------------------- +-- 0、warm-flow-all.sql,地址:https://gitee.com/dromara/warm-flow/blob/master/sql/mysql/warm-flow-all.sql +-- ---------------------------- +CREATE TABLE `flow_definition` +( + `id` bigint unsigned NOT NULL COMMENT '主键id', + `flow_code` varchar(40) NOT NULL COMMENT '流程编码', + `flow_name` varchar(100) NOT NULL COMMENT '流程名称', + `category` varchar(100) DEFAULT NULL COMMENT '流程类别', + `version` varchar(20) NOT NULL COMMENT '流程版本', + `is_publish` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否发布(0未发布 1已发布 9失效)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)', + `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型', + `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径', + `ext` varchar(500) DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程定义表'; + +CREATE TABLE `flow_node` +( + `id` bigint unsigned NOT NULL COMMENT '主键id', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `definition_id` bigint NOT NULL COMMENT '流程定义id', + `node_code` varchar(100) NOT NULL COMMENT '流程节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称', + `permission_flag` varchar(200) DEFAULT NULL COMMENT '权限标识(权限类型:权限标识,可以多个,用逗号隔开)', + `node_ratio` decimal(6, 3) DEFAULT NULL COMMENT '流程签署比例值', + `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标', + `skip_any_node` varchar(100) DEFAULT 'N' COMMENT '是否可以退回任意节点(Y是 N否)即将删除', + `any_node_skip` varchar(100) DEFAULT NULL COMMENT '任意结点跳转', + `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型', + `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径', + `handler_type` varchar(100) DEFAULT NULL COMMENT '处理器类型', + `handler_path` varchar(400) DEFAULT NULL COMMENT '处理器路径', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `version` varchar(20) NOT NULL COMMENT '版本', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程节点表'; + +CREATE TABLE `flow_skip` +( + `id` bigint unsigned NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '流程定义id', + `now_node_code` varchar(100) NOT NULL COMMENT '当前流程节点的编码', + `now_node_type` tinyint(1) DEFAULT NULL COMMENT '当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `next_node_code` varchar(100) NOT NULL COMMENT '下一个流程节点的编码', + `next_node_type` tinyint(1) DEFAULT NULL COMMENT '下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `skip_name` varchar(100) DEFAULT NULL COMMENT '跳转名称', + `skip_type` varchar(40) DEFAULT NULL COMMENT '跳转类型(PASS审批通过 REJECT退回)', + `skip_condition` varchar(200) DEFAULT NULL COMMENT '跳转条件', + `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='节点跳转关联表'; + +CREATE TABLE `flow_instance` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id', + `business_id` varchar(40) NOT NULL COMMENT '业务id', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `node_code` varchar(40) NOT NULL COMMENT '流程节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称', + `variable` text COMMENT '任务变量', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回 8已完成 9已退回 10失效)', + `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)', + `def_json` text COMMENT '流程定义json', + `create_by` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `ext` varchar(500) DEFAULT NULL COMMENT '扩展字段,预留给业务系统使用', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='流程实例表'; + +CREATE TABLE `flow_task` +( + `id` bigint NOT NULL COMMENT '主键id', + `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id', + `instance_id` bigint NOT NULL COMMENT '对应flow_instance表的id', + `node_code` varchar(100) NOT NULL COMMENT '节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '节点名称', + `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='待办任务表'; + +CREATE TABLE `flow_his_task` +( + `id` bigint(20) unsigned NOT NULL COMMENT '主键id', + `definition_id` bigint(20) NOT NULL COMMENT '对应flow_definition表的id', + `instance_id` bigint(20) NOT NULL COMMENT '对应flow_instance表的id', + `task_id` bigint(20) NOT NULL COMMENT '对应flow_task表的id', + `node_code` varchar(100) DEFAULT NULL COMMENT '开始节点编码', + `node_name` varchar(100) DEFAULT NULL COMMENT '开始节点名称', + `node_type` tinyint(1) DEFAULT NULL COMMENT '开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', + `target_node_code` varchar(200) DEFAULT NULL COMMENT '目标节点编码', + `target_node_name` varchar(200) DEFAULT NULL COMMENT '结束节点名称', + `approver` varchar(40) DEFAULT NULL COMMENT '审批者', + `cooperate_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)', + `collaborator` varchar(40) DEFAULT NULL COMMENT '协作人', + `skip_type` varchar(10) NOT NULL COMMENT '流转类型(PASS通过 REJECT退回 NONE无动作)', + `flow_status` varchar(20) NOT NULL COMMENT '流程状态(1审批中 2 审批通过 9已退回 10失效)', + `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)', + `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径', + `message` varchar(500) DEFAULT NULL COMMENT '审批意见', + `variable` TEXT DEFAULT NULL COMMENT '任务变量', + `ext` varchar(500) DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串', + `create_time` datetime DEFAULT NULL COMMENT '任务开始时间', + `update_time` datetime DEFAULT NULL COMMENT '审批完成时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB COMMENT ='历史任务记录表'; + + +CREATE TABLE `flow_user` +( + `id` bigint unsigned NOT NULL COMMENT '主键id', + `type` char(1) NOT NULL COMMENT '人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)', + `processed_by` varchar(80) DEFAULT NULL COMMENT '权限人', + `associated` bigint NOT NULL COMMENT '任务表id', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(80) DEFAULT NULL COMMENT '创建人', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志', + `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id', + PRIMARY KEY (`id`) USING BTREE, + KEY `user_processed_type` (`processed_by`, `type`) +) ENGINE = InnoDB COMMENT ='流程用户表'; + +-- ---------------------------- +-- 流程分类表 +-- ---------------------------- +create table flow_category +( + category_id bigint(20) not null comment '流程分类ID', + tenant_id varchar(20) default '000000' comment '租户编号', + parent_id bigint(20) default 0 comment '父流程分类id', + ancestors varchar(500) default '' comment '祖级列表', + category_name varchar(30) not null comment '流程分类名称', + order_num int(4) default 0 comment '显示顺序', + del_flag char(1) default '0' comment '删除标志(0代表存在 1代表删除)', + create_dept bigint(20) null comment '创建部门', + create_by bigint(20) null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint(20) null comment '更新者', + update_time datetime null comment '更新时间', + primary key (category_id) +) engine = innodb comment = '流程分类'; + +INSERT INTO flow_category values (100, '000000', 0, '0', 'OA审批', 0, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (101, '000000', 100, '0,100', '假勤管理', 0, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (102, '000000', 100, '0,100', '人事管理', 1, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (103, '000000', 101, '0,100,101', '请假', 0, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (104, '000000', 101, '0,100,101', '出差', 1, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (105, '000000', 101, '0,100,101', '加班', 2, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (106, '000000', 101, '0,100,101', '换班', 3, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (107, '000000', 101, '0,100,101', '外出', 4, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (108, '000000', 102, '0,100,102', '转正', 1, '0', 103, 1, sysdate(), null, null); +INSERT INTO flow_category values (109, '000000', 102, '0,100,102', '离职', 2, '0', 103, 1, sysdate(), null, null); + +-- ---------------------------- +-- 请假单信息 +-- ---------------------------- +create table test_leave +( + id bigint(20) not null comment 'id', + tenant_id varchar(20) default '000000' comment '租户编号', + leave_type varchar(255) not null comment '请假类型', + start_date datetime not null comment '开始时间', + end_date datetime not null comment '结束时间', + leave_days int(10) not null comment '请假天数', + remark varchar(255) null comment '请假原因', + status varchar(255) null comment '状态', + create_dept bigint null comment '创建部门', + create_by bigint null comment '创建者', + create_time datetime null comment '创建时间', + update_by bigint null comment '更新者', + update_time datetime null comment '更新时间', + PRIMARY KEY (id) USING BTREE +) ENGINE = InnoDB COMMENT = '请假申请表'; + +insert into sys_menu values ('11616', '工作流', '0', '6', 'workflow', '', '', '1', '0', 'M', '0', '0', '', 'workflow', 103, 1, sysdate(),NULL, NULL, ''); +insert into sys_menu values ('11618', '我的任务', '0', '7', 'task', '', '', '1', '0', 'M', '0', '0', '', 'my-task', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11619', '我的待办', '11618', '2', 'taskWaiting', 'workflow/task/taskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11632', '我的已办', '11618', '3', 'taskFinish', 'workflow/task/taskFinish', '', '1', '1', 'C', '0', '0', '', 'finish', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11633', '我的抄送', '11618', '4', 'taskCopyList', 'workflow/task/taskCopyList', '', '1', '1', 'C', '0', '0', '', 'my-copy', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11620', '流程定义', '11616', '3', 'processDefinition', 'workflow/processDefinition/index', '', '1', '1', 'C', '0', '0', '', 'process-definition', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11621', '流程实例', '11630', '1', 'processInstance', 'workflow/processInstance/index', '', '1', '1', 'C', '0', '0', '', 'tree-table', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11622', '流程分类', '11616', '1', 'category', 'workflow/category/index', '', '1', '0', 'C', '0', '0', 'workflow:category:list', 'category', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11629', '我发起的', '11618', '1', 'myDocument', 'workflow/task/myDocument', '', '1', '1', 'C', '0', '0', '', 'guide', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11630', '流程监控', '11616', '4', 'monitor', '', '', '1', '0', 'M', '0', '0', '', 'monitor', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu values ('11631', '待办任务', '11630', '2', 'allTaskWaiting', 'workflow/task/allTaskWaiting', '', '1', '1', 'C', '0', '0', '', 'waiting', 103, 1, sysdate(), NULL, NULL, ''); +-- 流程分类管理相关按钮 +insert into sys_menu values ('11623', '流程分类查询', '11622', '1', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:query', '#', 103, 1,sysdate(), null, null, ''); +insert into sys_menu values ('11624', '流程分类新增', '11622', '2', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:add', '#', 103, 1,sysdate(), null, null, ''); +insert into sys_menu values ('11625', '流程分类修改', '11622', '3', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:edit', '#', 103, 1,sysdate(), null, null, ''); +insert into sys_menu values ('11626', '流程分类删除', '11622', '4', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:remove', '#', 103,1, sysdate(), null, null, ''); +insert into sys_menu values ('11627', '流程分类导出', '11622', '5', '#', '', '', 1, 0, 'F', '0', '0', 'workflow:category:export', '#', 103,1, sysdate(), null, null, ''); +-- 请假测试相关按钮 +insert into sys_menu VALUES (11638, '请假申请', 5, 1, 'leave', 'workflow/leave/index', '', 1, 0, 'C', '0', '0', 'workflow:leave:list', '#', 103, 1, sysdate(), NULL, NULL, '请假申请菜单'); +insert into sys_menu VALUES (11639, '请假申请查询', 11638, 1, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:query', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11640, '请假申请新增', 11638, 2, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:add', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11641, '请假申请修改', 11638, 3, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:edit', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11642, '请假申请删除', 11638, 4, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:remove', '#', 103, 1, sysdate(), NULL, NULL, ''); +insert into sys_menu VALUES (11643, '请假申请导出', 11638, 5, '#', '', '', 1, 0, 'F', '0', '0', 'workflow:leave:export', '#', 103, 1, sysdate(), NULL, NULL, ''); + +INSERT INTO sys_dict_type VALUES (13, '000000', '业务状态', 'wf_business_status', 103, 1, sysdate(), NULL, NULL, '业务状态列表'); +INSERT INTO sys_dict_type VALUES (14, '000000', '表单类型', 'wf_form_type', 103, 1, sysdate(), NULL, NULL, '表单类型列表'); +INSERT INTO sys_dict_type VALUES (15, '000000', '任务状态', 'wf_task_status', 103, 1, sysdate(), NULL, NULL, '任务状态'); +INSERT INTO sys_dict_data VALUES (39, '000000', 1, '已撤销', 'cancel', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'已撤销'); +INSERT INTO sys_dict_data VALUES (40, '000000', 2, '草稿', 'draft', 'wf_business_status', '', 'info', 'N', 103, 1, sysdate(), NULL, NULL, '草稿'); +INSERT INTO sys_dict_data VALUES (41, '000000', 3, '待审核', 'waiting', 'wf_business_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL,'待审核'); +INSERT INTO sys_dict_data VALUES (42, '000000', 4, '已完成', 'finish', 'wf_business_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL,'已完成'); +INSERT INTO sys_dict_data VALUES (43, '000000', 5, '已作废', 'invalid', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'已作废'); +INSERT INTO sys_dict_data VALUES (44, '000000', 6, '已退回', 'back', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL,'已退回'); +INSERT INTO sys_dict_data VALUES (45, '000000', 7, '已终止', 'termination', 'wf_business_status', '', 'danger', 'N', 103, 1, sysdate(), NULL,NULL, '已终止'); +INSERT INTO sys_dict_data VALUES (46, '000000', 1, '自定义表单', 'static', 'wf_form_type', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL,'自定义表单'); +INSERT INTO sys_dict_data VALUES (47, '000000', 2, '动态表单', 'dynamic', 'wf_form_type', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL,'动态表单'); +INSERT INTO sys_dict_data VALUES (48, '000000', 1, '撤销', 'cancel', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '撤销'); +INSERT INTO sys_dict_data VALUES (49, '000000', 2, '通过', 'pass', 'wf_task_status', '', 'success', 'N', 103, 1, sysdate(), NULL, NULL, '通过'); +INSERT INTO sys_dict_data VALUES (50, '000000', 3, '待审核', 'waiting', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '待审核'); +INSERT INTO sys_dict_data VALUES (51, '000000', 4, '作废', 'invalid', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '作废'); +INSERT INTO sys_dict_data VALUES (52, '000000', 5, '退回', 'back', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '退回'); +INSERT INTO sys_dict_data VALUES (53, '000000', 6, '终止', 'termination', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '终止'); +INSERT INTO sys_dict_data VALUES (54, '000000', 7, '转办', 'transfer', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '转办'); +INSERT INTO sys_dict_data VALUES (55, '000000', 8, '委托', 'depute', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '委托'); +INSERT INTO sys_dict_data VALUES (56, '000000', 9, '抄送', 'copy', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '抄送'); +INSERT INTO sys_dict_data VALUES (57, '000000', 10, '加签', 'sign', 'wf_task_status', '', 'primary', 'N', 103, 1, sysdate(), NULL, NULL, '加签'); +INSERT INTO sys_dict_data VALUES (58, '000000', 11, '减签', 'sign_off', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '减签'); +INSERT INTO sys_dict_data VALUES (59, '000000', 11, '超时', 'timeout', 'wf_task_status', '', 'danger', 'N', 103, 1, sysdate(), NULL, NULL, '超时'); + diff --git a/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql new file mode 100644 index 0000000..9f8481a --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_vue_5.X.sql @@ -0,0 +1,3607 @@ +create table sys_social +( + id bigint NOT NULL, + user_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + auth_id nvarchar(255) NOT NULL, + source nvarchar(255) NOT NULL, + open_id nvarchar(255) NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) DEFAULT ('') NULL, + email nvarchar(255) DEFAULT ('') NULL, + avatar nvarchar(500) DEFAULT ('') NULL, + access_token nvarchar(255) NOT NULL, + expire_in bigint NULL, + refresh_token nvarchar(255) NULL, + access_code nvarchar(255) NULL, + union_id nvarchar(255) NULL, + scope nvarchar(255) NULL, + token_type nvarchar(255) NULL, + id_token nvarchar(2000) NULL, + mac_algorithm nvarchar(255) NULL, + mac_key nvarchar(255) NULL, + code nvarchar(255) NULL, + oauth_token nvarchar(255) NULL, + oauth_token_secret nvarchar(255) NULL, + create_dept bigint, + create_by bigint, + create_time datetime2(7), + update_by bigint, + update_time datetime2(7), + del_flag nchar DEFAULT ('0') NULL, + CONSTRAINT PK__sys_social__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台+平台唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'auth_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户来源' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'source' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台编号唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'open_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌的有效期,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'expire_in' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'刷新令牌,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'refresh_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的 unionid' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'union_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'授予的权限,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'个别平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'token_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id token,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_algorithm' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权code,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token_secret' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'社会化关系表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social' +GO + +CREATE TABLE sys_tenant +( + id bigint NOT NULL, + tenant_id nvarchar(20) NOT NULL, + contact_user_name nvarchar(20) NULL, + contact_phone nvarchar(20) NULL, + company_name nvarchar(50) NULL, + license_number nvarchar(30) NULL, + address nvarchar(200) NULL, + intro nvarchar(200) NULL, + domain nvarchar(200) NULL, + remark nvarchar(200) NULL, + package_id bigint NULL, + expire_time datetime2(7) NULL, + account_count int DEFAULT ((-1)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_tenant__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'联系人' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'contact_user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'联系电话' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'contact_phone' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'企业名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'company_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'统一社会信用代码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'license_number' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'address' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'企业简介' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'intro' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'域名' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'domain' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户套餐编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'package_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'过期时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'expire_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户数量(-1不限制)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'account_count' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant' +GO + +INSERT sys_tenant VALUES (1, N'000000', N'管理组', N'15888888888', N'XXX有限公司', NULL, NULL, N'多租户通用后台管理管理系统', NULL, NULL, NULL, NULL, -1, N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO + + +CREATE TABLE sys_tenant_package +( + package_id bigint NOT NULL, + package_name nvarchar(20) NOT NULL, + menu_ids nvarchar(20) NULL, + remark nvarchar(200) NULL, + menu_check_strictly tinyint DEFAULT ((1)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_tenant_package__B21E8F2427725F8A PRIMARY KEY CLUSTERED (package_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户套餐id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'package_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'套餐名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'package_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'关联菜单id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'menu_ids' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户套餐表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_tenant_package' +GO + + +CREATE TABLE gen_table +( + table_id bigint NOT NULL, + data_name nvarchar(200) DEFAULT '' NULL, + table_name nvarchar(200) DEFAULT '' NULL, + table_comment nvarchar(500) DEFAULT '' NULL, + sub_table_name nvarchar(64) NULL, + sub_table_fk_name nvarchar(64) NULL, + class_name nvarchar(100) DEFAULT '' NULL, + tpl_category nvarchar(200) DEFAULT ('crud') NULL, + package_name nvarchar(100) NULL, + module_name nvarchar(30) NULL, + business_name nvarchar(30) NULL, + function_name nvarchar(50) NULL, + function_author nvarchar(50) NULL, + gen_type nchar(1) DEFAULT ('0') NULL, + gen_path nvarchar(200) DEFAULT ('/') NULL, + options nvarchar(1000) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__gen_tabl__B21E8F2427725F8A PRIMARY KEY CLUSTERED (table_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'数据源名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'data_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表描述' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'table_comment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'关联子表的表名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'sub_table_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'子表关联的外键名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'sub_table_fk_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'实体类名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'class_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'使用的模板(crud单表操作 tree树表操作)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'tpl_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成包路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'package_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成模块名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'module_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成业务名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'business_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成功能名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'function_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成功能作者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'function_author' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成代码方式(0zip压缩包 1自定义路径)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'gen_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'生成路径(不填默认项目路径)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'gen_path' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'其它生成选项' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'options' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'代码生成业务表' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table' +GO + +CREATE TABLE gen_table_column +( + column_id bigint NOT NULL, + table_id bigint NULL, + column_name nvarchar(200) NULL, + column_comment nvarchar(500) NULL, + column_type nvarchar(100) NULL, + java_type nvarchar(500) NULL, + java_field nvarchar(200) NULL, + is_pk nchar(1) NULL, + is_increment nchar(1) NULL, + is_required nchar(1) NULL, + is_insert nchar(1) NULL, + is_edit nchar(1) NULL, + is_list nchar(1) NULL, + is_query nchar(1) NULL, + query_type nvarchar(200) DEFAULT ('EQ') NULL, + html_type nvarchar(200) NULL, + dict_type nvarchar(200) DEFAULT '' NULL, + sort int NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__gen_tabl__E301851F2E68B4E8 PRIMARY KEY CLUSTERED (column_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'归属表编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'table_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列描述' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_comment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'列类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'column_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'JAVA类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'java_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'JAVA字段名' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'java_field' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否主键(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_pk' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否自增(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_increment' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否必填(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_required' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否为插入字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_insert' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否编辑字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_edit' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否列表字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_list' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否查询字段(1是)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'is_query' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'查询方式(等于、不等于、大于、小于、范围)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'query_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'html_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'排序' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'代码生成业务表字段' , + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table_column' +GO + +CREATE TABLE sys_config +( + config_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT '000000' NULL, + config_name nvarchar(100) DEFAULT '' NULL, + config_key nvarchar(100) DEFAULT '' NULL, + config_value nvarchar(500) DEFAULT '' NULL, + config_type nchar(1) DEFAULT ('N') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_conf__4AD1BFF182643682 PRIMARY KEY CLUSTERED (config_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数键名' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数键值' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_value' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'系统内置(Y是 N否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'config_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'参数配置表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_config' +GO + +INSERT sys_config VALUES (1, N'000000', N'主框架页-默认皮肤样式名称', N'sys.index.skinName', N'skin-blue', N'Y', 103, 1, getdate(), NULL, NULL, N'蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow') +GO +INSERT sys_config VALUES (2, N'000000', N'用户管理-账号初始密码', N'sys.user.initPassword', N'123456', N'Y', 103, 1, getdate(), NULL, NULL, N'初始化密码 123456') +GO +INSERT sys_config VALUES (3, N'000000', N'主框架页-侧边栏主题', N'sys.index.sideTheme', N'theme-dark', N'Y', 103, 1, getdate(), NULL, NULL, N'深色主题theme-dark,浅色主题theme-light') +GO +INSERT sys_config VALUES (5, N'000000', N'账号自助-是否开启用户注册功能', N'sys.account.registerUser', N'false', N'Y', 103, 1, getdate(), NULL, NULL, N'是否开启注册用户功能(true开启,false关闭)') +GO +INSERT sys_config VALUES (11, N'000000', N'OSS预览列表资源开关', N'sys.oss.previewListResource', N'true', N'Y', 103, 1, getdate(), NULL, NULL, N'true:开启, false:关闭'); +GO + +CREATE TABLE sys_dept +( + dept_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + parent_id bigint DEFAULT ((0)) NULL, + ancestors nvarchar(500)DEFAULT '' NULL, + dept_name nvarchar(30) NULL, + dept_category nvarchar(100) DEFAULT '' NULL, + order_num int DEFAULT ((0)) NULL, + leader bigint NULL, + phone nvarchar(11) NULL, + email nvarchar(50) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__sys_dept__DCA659747DE13804 PRIMARY KEY CLUSTERED (dept_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'父部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'parent_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'祖级列表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'ancestors' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门类别编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'order_num' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'负责人' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'leader' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'联系电话' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'phone' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept' +GO + +INSERT sys_dept VALUES (100, N'000000', 0, N'0', N'XXX科技', NULL, 0, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (101, N'000000', 100, N'0,100', N'深圳总公司', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (102, N'000000', 100, N'0,100', N'长沙分公司', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (103, N'000000', 101, N'0,100,101', N'研发部门', NULL, 1, 1, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (104, N'000000', 101, N'0,100,101', N'市场部门', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (105, N'000000', 101, N'0,100,101', N'测试部门', NULL, 3, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (106, N'000000', 101, N'0,100,101', N'财务部门', NULL, 4, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (107, N'000000', 101, N'0,100,101', N'运维部门', NULL, 5, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (108, N'000000', 102, N'0,100,102', N'市场部门', NULL, 1, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO +INSERT sys_dept VALUES (109, N'000000', 102, N'0,100,102', N'财务部门', NULL, 2, NULL, N'15888888888', N'xxx@qq.com', N'0', N'0', 103, 1, getdate(), NULL, NULL) +GO + +CREATE TABLE sys_dict_data +( + dict_code bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dict_sort int DEFAULT ((0)) NULL, + dict_label nvarchar(100) DEFAULT '' NULL, + dict_value nvarchar(100) DEFAULT '' NULL, + dict_type nvarchar(100) DEFAULT '' NULL, + css_class nvarchar(100) NULL, + list_class nvarchar(100) NULL, + is_default nchar(1) DEFAULT ('N') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_dict__19CBC34B661AF3B3 PRIMARY KEY CLUSTERED (dict_code) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典排序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典标签' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_label' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典键值' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_value' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'样式属性(其他样式扩展)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'css_class' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'表格回显样式' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'list_class' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否默认(Y是 N否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'is_default' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典数据表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_data' +GO + +INSERT sys_dict_data VALUES (1, N'000000', 1, N'男', N'0', N'sys_user_sex', N'', N'', N'Y', 103, 1, getdate(), NULL, NULL, N'性别男') +GO +INSERT sys_dict_data VALUES (2, N'000000', 2, N'女', N'1', N'sys_user_sex', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'性别女') +GO +INSERT sys_dict_data VALUES (3, N'000000', 3, N'未知', N'2', N'sys_user_sex', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'性别未知') +GO +INSERT sys_dict_data VALUES (4, N'000000', 1, N'显示', N'0', N'sys_show_hide', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'显示菜单') +GO +INSERT sys_dict_data VALUES (5, N'000000', 2, N'隐藏', N'1', N'sys_show_hide', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'隐藏菜单') +GO +INSERT sys_dict_data VALUES (6, N'000000', 1, N'正常', N'0', N'sys_normal_disable', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (7, N'000000', 2, N'停用', N'1', N'sys_normal_disable', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (8, N'000000', 1, N'正常', N'0', N'sys_job_status', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (9, N'000000', 2, N'暂停', N'1', N'sys_job_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (10, N'000000', 1, N'默认', N'DEFAULT', N'sys_job_group', N'', N'', N'Y', 103, 1, getdate(), NULL, NULL, N'默认分组') +GO +INSERT sys_dict_data VALUES (11, N'000000', 2, N'系统', N'SYSTEM', N'sys_job_group', N'', N'', N'N', 103, 1, getdate(), NULL, NULL, N'系统分组') +GO +INSERT sys_dict_data VALUES (12, N'000000', 1, N'是', N'Y', N'sys_yes_no', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'系统默认是') +GO +INSERT sys_dict_data VALUES (13, N'000000', 2, N'否', N'N', N'sys_yes_no', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'系统默认否') +GO +INSERT sys_dict_data VALUES (14, N'000000', 1, N'通知', N'1', N'sys_notice_type', N'', N'warning', N'Y', 103, 1, getdate(), NULL, NULL, N'通知') +GO +INSERT sys_dict_data VALUES (15, N'000000', 2, N'公告', N'2', N'sys_notice_type', N'', N'success', N'N', 103, 1, getdate(), NULL, NULL, N'公告') +GO +INSERT sys_dict_data VALUES (16, N'000000', 1, N'正常', N'0', N'sys_notice_status', N'', N'primary', N'Y', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (17, N'000000', 2, N'关闭', N'1', N'sys_notice_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'关闭状态') +GO +INSERT sys_dict_data VALUES (29, N'000000', 99, N'其他', N'0', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'其他操作'); +GO +INSERT sys_dict_data VALUES (18, N'000000', 1, N'新增', N'1', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'新增操作') +GO +INSERT sys_dict_data VALUES (19, N'000000', 2, N'修改', N'2', N'sys_oper_type', N'', N'info', N'N', 103, 1, getdate(), NULL, NULL, N'修改操作') +GO +INSERT sys_dict_data VALUES (20, N'000000', 3, N'删除', N3, N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'删除操作') +GO +INSERT sys_dict_data VALUES (21, N'000000', 4, N'授权', N'4', N'sys_oper_type', N'', N'primary', N'N', 103, 1, getdate(), NULL, NULL, N'授权操作') +GO +INSERT sys_dict_data VALUES (22, N'000000', 5, N'导出', N'5', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'导出操作') +GO +INSERT sys_dict_data VALUES (23, N'000000', 6, N'导入', N'6', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'导入操作') +GO +INSERT sys_dict_data VALUES (24, N'000000', 7, N'强退', N'7', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'强退操作') +GO +INSERT sys_dict_data VALUES (25, N'000000', 8, N'生成代码', N'8', N'sys_oper_type', N'', N'warning', N'N', 103, 1, getdate(), NULL, NULL, N'生成操作') +GO +INSERT sys_dict_data VALUES (26, N'000000', 9, N'清空数据', N'9', N'sys_oper_type', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'清空操作') +GO +INSERT sys_dict_data VALUES (27, N'000000', 1, N'成功', N'0', N'sys_common_status', N'', N'primary', N'N', 103, 1, getdate(), NULL, NULL, N'正常状态') +GO +INSERT sys_dict_data VALUES (28, N'000000', 2, N'失败', N'1', N'sys_common_status', N'', N'danger', N'N', 103, 1, getdate(), NULL, NULL, N'停用状态') +GO +INSERT sys_dict_data VALUES (30, N'000000', 0, N'密码认证', N'password', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'密码认证') +GO +INSERT sys_dict_data VALUES (31, N'000000', 0, N'短信认证', N'sms', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'短信认证') +GO +INSERT sys_dict_data VALUES (32, N'000000', 0, N'邮件认证', N'email', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'邮件认证') +GO +INSERT sys_dict_data VALUES (33, N'000000', 0, N'小程序认证', N'xcx', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'小程序认证') +GO +INSERT sys_dict_data VALUES (34, N'000000', 0, N'三方登录认证', N'`social`', N'sys_grant_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'三方登录认证') +GO +INSERT sys_dict_data VALUES (35, N'000000', 0, N'PC', N'`pc`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'PC') +GO +INSERT sys_dict_data VALUES (36, N'000000', 0, N'安卓', N'`android`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'安卓') +GO +INSERT sys_dict_data VALUES (37, N'000000', 0, N'iOS', N'`ios`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'iOS') +GO +INSERT sys_dict_data VALUES (38, N'000000', 0, N'小程序', N'`xcx`', N'sys_device_type', N'', N'default', N'N', 103, 1, getdate(), NULL, NULL, N'小程序') +GO + +CREATE TABLE sys_dict_type +( + dict_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dict_name nvarchar(100) DEFAULT '' NULL, + dict_type nvarchar(100) DEFAULT '' NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_dict__3BD4186C409C5391 PRIMARY KEY CLUSTERED (dict_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX sys_dict_type_index1 ON sys_dict_type (tenant_id, dict_type) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'dict_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'字典类型表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dict_type' +GO + +INSERT sys_dict_type VALUES (1, N'000000', N'用户性别', N'sys_user_sex', 103, 1, getdate(), NULL, NULL, N'用户性别列表') +GO +INSERT sys_dict_type VALUES (2, N'000000', N'菜单状态', N'sys_show_hide', 103, 1, getdate(), NULL, NULL, N'菜单状态列表') +GO +INSERT sys_dict_type VALUES (3, N'000000', N'系统开关', N'sys_normal_disable', 103, 1, getdate(), NULL, NULL, N'系统开关列表') +GO +INSERT sys_dict_type VALUES (4, N'000000', N'任务状态', N'sys_job_status', 103, 1, getdate(), NULL, NULL, N'任务状态列表') +GO +INSERT sys_dict_type VALUES (5, N'000000', N'任务分组', N'sys_job_group', 103, 1, getdate(), NULL, NULL, N'任务分组列表') +GO +INSERT sys_dict_type VALUES (6, N'000000', N'系统是否', N'sys_yes_no', 103, 1, getdate(), NULL, NULL, N'系统是否列表') +GO +INSERT sys_dict_type VALUES (7, N'000000', N'通知类型', N'sys_notice_type', 103, 1, getdate(), NULL, NULL, N'通知类型列表') +GO +INSERT sys_dict_type VALUES (8, N'000000', N'通知状态', N'sys_notice_status', 103, 1, getdate(), NULL, NULL, N'通知状态列表') +GO +INSERT sys_dict_type VALUES (9, N'000000', N'操作类型', N'sys_oper_type', 103, 1, getdate(), NULL, NULL, N'操作类型列表') +GO +INSERT sys_dict_type VALUES (10, N'000000', N'系统状态', N'sys_common_status', 103, 1, getdate(), NULL, NULL, N'登录状态列表') +GO +INSERT sys_dict_type VALUES (11, N'000000', N'授权类型', N'sys_grant_type', 103, 1, getdate(), NULL, NULL, N'认证授权类型') +GO +INSERT sys_dict_type VALUES (12, N'000000', N'设备类型', N'sys_device_type', 103, 1, getdate(), NULL, NULL, N'客户端设备类型') +GO + +CREATE TABLE sys_logininfor +( + info_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + user_name nvarchar(50) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + ipaddr nvarchar(128) DEFAULT '' NULL, + login_location nvarchar(255) DEFAULT '' NULL, + browser nvarchar(50) DEFAULT '' NULL, + os nvarchar(50) DEFAULT '' NULL, + status nchar(1) DEFAULT ('0') NULL, + msg nvarchar(255) DEFAULT '' NULL, + login_time datetime2(7) NULL, + CONSTRAINT PK__sys_logi__3D8A9C1A1854AE10 PRIMARY KEY CLUSTERED (info_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_logininfor_s ON sys_logininfor (status) +GO +CREATE NONCLUSTERED INDEX idx_sys_logininfor_lt ON sys_logininfor (login_time) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'访问ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'info_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'客户端' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'client_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'设备类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'device_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录IP地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'ipaddr' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录地点' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'login_location' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'浏览器类型' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'browser' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作系统' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'os' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录状态(0成功 1失败)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'提示消息' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'msg' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'访问时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor', + 'COLUMN', N'login_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'系统访问记录' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_logininfor' +GO + +CREATE TABLE sys_menu +( + menu_id bigint NOT NULL, + menu_name nvarchar(50) NOT NULL, + parent_id bigint DEFAULT ((0)) NULL, + order_num int DEFAULT ((0)) NULL, + path nvarchar(200) DEFAULT '' NULL, + component nvarchar(255) NULL, + query_param nvarchar(255) NULL, + is_frame int DEFAULT ((1)) NULL, + is_cache int DEFAULT ((0)) NULL, + menu_type nchar(1) DEFAULT '' NULL, + visible nchar(1) DEFAULT ((0)) NULL, + status nchar(1) DEFAULT ((0)) NULL, + perms nvarchar(100) NULL, + icon nvarchar(100) DEFAULT ('#') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) DEFAULT '' NULL, + CONSTRAINT PK__sys_menu__4CA0FADCF8545C58 PRIMARY KEY CLUSTERED (menu_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'父菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'parent_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'order_num' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'路由地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'path' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'组件路径' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'component' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'路由参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'query_param' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否为外链(0是 1否)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'is_frame' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'是否缓存(0缓存 1不缓存)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'is_cache' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单类型(M目录 C菜单 F按钮)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'menu_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示状态(0显示 1隐藏)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'visible' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'权限标识' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'perms' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单图标' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'icon' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单权限表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_menu' +GO + +INSERT sys_menu VALUES (1, N'系统管理', 0, 1, N'system', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'system', 103, 1, getdate(), NULL, NULL, N'系统管理目录') +GO +INSERT sys_menu VALUES (6, N'租户管理', 0, 2, N'tenant', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'chart', 103, 1, getdate(), NULL, NULL, N'租户管理目录') +GO +INSERT sys_menu VALUES (2, N'系统监控', 0, 3, N'monitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, getdate(), NULL, NULL, N'系统监控目录') +GO +INSERT sys_menu VALUES (3, N'系统工具', 0, 4, N'tool', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'tool', 103, 1, getdate(), NULL, NULL, N'系统工具目录') +GO +INSERT sys_menu VALUES (4, N'PLUS官网', 0, 5, N'https://gitee.com/dromara/RuoYi-Vue-Plus', null, N'', 0, 0, N'M', N'0', N'0', N'', N'guide', 103, 1, getdate(), null, null, N'RuoYi-Vue-Plus官网地址'); +GO +INSERT sys_menu VALUES (5, N'测试菜单', 0, 5, N'demo', NULL, N'', 1, 0, N'M', N'0', N'0', NULL, N'star', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (100, N'用户管理', 1, 1, N'user', N'system/user/index', N'', 1, 0, N'C', N'0', N'0', N'system:user:list', N'user', 103, 1, getdate(), NULL, NULL, N'用户管理菜单') +GO +INSERT sys_menu VALUES (101, N'角色管理', 1, 2, N'role', N'system/role/index', N'', 1, 0, N'C', N'0', N'0', N'system:role:list', N'peoples', 103, 1, getdate(), NULL, NULL, N'角色管理菜单') +GO +INSERT sys_menu VALUES (102, N'菜单管理', 1, 3, N'menu', N'system/menu/index', N'', 1, 0, N'C', N'0', N'0', N'system:menu:list', N'tree-table', 103, 1, getdate(), NULL, NULL, N'菜单管理菜单') +GO +INSERT sys_menu VALUES (103, N'部门管理', 1, 4, N'dept', N'system/dept/index', N'', 1, 0, N'C', N'0', N'0', N'system:dept:list', N'tree', 103, 1, getdate(), NULL, NULL, N'部门管理菜单') +GO +INSERT sys_menu VALUES (104, N'岗位管理', 1, 5, N'post', N'system/post/index', N'', 1, 0, N'C', N'0', N'0', N'system:post:list', N'post', 103, 1, getdate(), NULL, NULL, N'岗位管理菜单') +GO +INSERT sys_menu VALUES (105, N'字典管理', 1, 6, N'dict', N'system/dict/index', N'', 1, 0, N'C', N'0', N'0', N'system:dict:list', N'dict', 103, 1, getdate(), NULL, NULL, N'字典管理菜单') +GO +INSERT sys_menu VALUES (106, N'参数设置', 1, 7, N'config', N'system/config/index', N'', 1, 0, N'C', N'0', N'0', N'system:config:list', N'edit', 103, 1, getdate(), NULL, NULL, N'参数设置菜单') +GO +INSERT sys_menu VALUES (107, N'通知公告', 1, 8, N'notice', N'system/notice/index', N'', 1, 0, N'C', N'0', N'0', N'system:notice:list', N'message', 103, 1, getdate(), NULL, NULL, N'通知公告菜单') +GO +INSERT sys_menu VALUES (108, N'日志管理', 1, 9, N'log', N'', N'', 1, 0, N'M', N'0', N'0', N'', N'log', 103, 1, getdate(), NULL, NULL, N'日志管理菜单') +GO +INSERT sys_menu VALUES (109, N'在线用户', 2, 1, N'online', N'monitor/online/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:online:list', N'online', 103, 1, getdate(), NULL, NULL, N'在线用户菜单') +GO +INSERT sys_menu VALUES (113, N'缓存监控', 2, 5, N'cache', N'monitor/cache/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:cache:list', N'redis', 103, 1, getdate(), NULL, NULL, N'缓存监控菜单') +GO +INSERT sys_menu VALUES (115, N'代码生成', 3, 2, N'gen', N'tool/gen/index', N'', 1, 0, N'C', N'0', N'0', N'tool:gen:list', N'code', 103, 1, getdate(), NULL, NULL, N'代码生成菜单') +GO +INSERT sys_menu VALUES (121, N'租户管理', 6, 1, N'tenant', N'system/tenant/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenant:list', N'code', 103, 1, getdate(), NULL, NULL, N'租户管理菜单') +GO +INSERT sys_menu VALUES (122, N'租户套餐管理', 6, 2, N'tenantPackage', N'system/tenantPackage/index', N'', 1, 0, N'C', N'0', N'0', N'system:tenantPackage:list', N'code', 103, 1, getdate(), NULL, NULL, N'租户套餐管理菜单') +GO +INSERT sys_menu VALUES (123, N'客户端管理', 1, 11, N'client', N'system/client/index', N'', 1, 0, N'C', N'0', N'0', N'system:client:list', N'international', 103, 1, getdate(), NULL, NULL, N'客户端管理菜单') +GO +INSERT sys_menu VALUES (117, N'Admin监控', 2, 5, N'Admin', N'monitor/admin/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:admin:list', N'dashboard', 103, 1, getdate(), NULL, NULL, N'Admin监控菜单'); +GO +INSERT sys_menu VALUES (118, N'文件管理', 1, 10, N'oss', N'system/oss/index', N'', 1, 0, N'C', '0', N'0', N'system:oss:list', N'upload', 103, 1, getdate(), NULL, NULL, N'文件管理菜单'); +GO +INSERT sys_menu VALUES (120, N'任务调度中心', 2, 5, N'snailjob', N'monitor/snailjob/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:snailjob:list', N'job', 103, 1, getdate(), NULL, NULL, N'SnailJob控制台菜单'); +GO +INSERT sys_menu VALUES (500, N'操作日志', 108, 1, N'operlog', N'monitor/operlog/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:operlog:list', N'form', 103, 1, getdate(), NULL, NULL, N'操作日志菜单') +GO +INSERT sys_menu VALUES (501, N'登录日志', 108, 2, N'logininfor', N'monitor/logininfor/index', N'', 1, 0, N'C', N'0', N'0', N'monitor:logininfor:list', N'logininfor', 103, 1, getdate(), NULL, NULL, N'登录日志菜单') +GO +INSERT sys_menu VALUES (1001, N'用户查询', 100, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1002, N'用户新增', 100, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1003, N'用户修改', 100, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1004, N'用户删除', 100, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1005, N'用户导出', 100, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1006, N'用户导入', 100, 6, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:import', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1007, N'重置密码', 100, 7, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:user:resetPwd', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1008, N'角色查询', 101, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1009, N'角色新增', 101, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1010, N'角色修改', 101, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1011, N'角色删除', 101, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1012, N'角色导出', 101, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:role:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1013, N'菜单查询', 102, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1014, N'菜单新增', 102, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1015, N'菜单修改', 102, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1016, N'菜单删除', 102, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:menu:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1017, N'部门查询', 103, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1018, N'部门新增', 103, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1019, N'部门修改', 103, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1020, N'部门删除', 103, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dept:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1021, N'岗位查询', 104, 1, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1022, N'岗位新增', 104, 2, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1023, N'岗位修改', 104, 3, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1024, N'岗位删除', 104, 4, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1025, N'岗位导出', 104, 5, N'', N'', N'', 1, 0, N'F', N'0', N'0', N'system:post:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1026, N'字典查询', 105, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1027, N'字典新增', 105, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1028, N'字典修改', 105, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1029, N'字典删除', 105, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1030, N'字典导出', 105, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:dict:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1031, N'参数查询', 106, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1032, N'参数新增', 106, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1033, N'参数修改', 106, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1034, N'参数删除', 106, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1035, N'参数导出', 106, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:config:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1036, N'公告查询', 107, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1037, N'公告新增', 107, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:add', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1038, N'公告修改', 107, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1039, N'公告删除', 107, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:notice:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1040, N'操作查询', 500, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1041, N'操作删除', 500, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1042, N'日志导出', 500, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:operlog:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1043, N'登录查询', 501, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1044, N'登录删除', 501, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1045, N'日志导出', 501, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:export', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1050, N'账户解锁', 501, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:unlock', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1046, N'在线查询', 109, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1047, N'批量强退', 109, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:batchLogout', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1048, N'单条强退', 109, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:forceLogout', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1055, N'生成查询', 115, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:query', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1056, N'生成修改', 115, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:edit', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1057, N'生成删除', 115, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:remove', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1058, N'导入代码', 115, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:import', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1059, N'预览代码', 115, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:preview', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_menu VALUES (1060, N'生成代码', 115, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'tool:gen:code', N'#', 103, 1, getdate(), NULL, NULL, N'') +GO +-- oss相关按钮 +INSERT sys_menu VALUES (1600, N'文件查询', 118, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1601, N'文件上传', 118, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:upload', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1602, N'文件下载', 118, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:download', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1603, N'文件删除', 118, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:oss:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1620, N'配置列表', 118, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:list', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1621, N'配置添加', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1622, N'配置编辑', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1623, N'配置删除', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 租户管理相关按钮 +INSERT sys_menu VALUES (1606, N'租户查询', 121, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1607, N'租户新增', 121, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1608, N'租户修改', 121, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1609, N'租户删除', 121, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1610, N'租户导出', 121, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenant:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 租户套餐管理相关按钮 +INSERT sys_menu VALUES (1611, N'租户套餐查询', 122, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1612, N'租户套餐新增', 122, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1613, N'租户套餐修改', 122, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1614, N'租户套餐删除', 122, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1615, N'租户套餐导出', 122, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:tenantPackage:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 客户端管理按钮 +INSERT sys_menu VALUES (1061, N'客户端管理查询', 123, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1062, N'客户端管理新增', 123, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1063, N'客户端管理修改', 123, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1064, N'客户端管理删除', 123, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1065, N'客户端管理导出', 123, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +-- 测试菜单 +INSERT sys_menu VALUES (1500, N'测试单表', 5, 1, N'demo', N'demo/demo/index', N'', 1, 0, N'C', N'0', N'0', N'demo:demo:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试单表菜单'); +GO +INSERT sys_menu VALUES (1501, N'测试单表查询', 1500, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1502, N'测试单表新增', 1500, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1503, N'测试单表修改', 1500, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1504, N'测试单表删除', 1500, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1505, N'测试单表导出', 1500, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:demo:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO + +INSERT sys_menu VALUES (1506, N'测试树表', 5, 1, N'tree', N'demo/tree/index', N'', 1, 0, N'C', N'0', N'0', N'demo:tree:list', N'#', 103, 1, getdate(), NULL, NULL, N'测试树表菜单'); +GO +INSERT sys_menu VALUES (1507, N'测试树表查询', 1506, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1508, N'测试树表新增', 1506, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1509, N'测试树表修改', 1506, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1510, N'测试树表删除', 1506, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1511, N'测试树表导出', 1506, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'demo:tree:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO + +CREATE TABLE sys_notice +( + notice_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + notice_title nvarchar(50) NOT NULL, + notice_type nchar(1) NOT NULL, + notice_content nvarchar(max) NULL, + status nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(255) NULL, + CONSTRAINT PK__sys_noti__3E82A5DB0EC94801 PRIMARY KEY CLUSTERED (notice_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +TEXTIMAGE_ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告标题' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_title' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告类型(1通知 2公告)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告内容' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'notice_content' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'公告状态(0正常 1关闭)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'通知公告表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_notice' +GO + +INSERT sys_notice VALUES (1, N'000000', N'温馨提醒:2018-07-01 若依新版本发布啦', N'2', N'新版本内容', N'0', 103, 1, getdate(), NULL, NULL, N'管理员') +GO +INSERT sys_notice VALUES (2, N'000000', N'维护通知:2018-07-01 若依系统凌晨维护', N'1', N'维护内容', N'0', 103, 1, getdate(), NULL, NULL, N'管理员') +GO + +CREATE TABLE sys_oper_log +( + oper_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + title nvarchar(50) DEFAULT '' NULL, + business_type int DEFAULT ((0)) NULL, + method nvarchar(100) DEFAULT '' NULL, + request_method nvarchar(10) DEFAULT '' NULL, + operator_type int DEFAULT ((0)) NULL, + oper_name nvarchar(50) DEFAULT '' NULL, + dept_name nvarchar(50) DEFAULT '' NULL, + oper_url nvarchar(255) DEFAULT '' NULL, + oper_ip nvarchar(128) DEFAULT '' NULL, + oper_location nvarchar(255) DEFAULT '' NULL, + oper_param nvarchar(4000) DEFAULT '' NULL, + json_result nvarchar(4000) DEFAULT '' NULL, + status int DEFAULT ((0)) NULL, + error_msg nvarchar(4000) DEFAULT '' NULL, + oper_time datetime2(7) NULL, + cost_time bigint DEFAULT ((0)) NULL, + CONSTRAINT PK__sys_oper__34723BF9BD954573 PRIMARY KEY CLUSTERED (oper_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX idx_sys_oper_log_bt ON sys_oper_log (business_type) +GO +CREATE NONCLUSTERED INDEX idx_sys_oper_log_s ON sys_oper_log (status) +GO +CREATE NONCLUSTERED INDEX idx_sys_oper_log_ot ON sys_oper_log (oper_time) +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'日志主键' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'模块标题' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'title' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'业务类型(0其它 1新增 2修改 3删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'business_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'方法名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'method' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求方式' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'request_method' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作类别(0其它 1后台用户 2手机端用户)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'operator_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作人员' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'dept_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求URL' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_url' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'主机地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_ip' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作地点' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_location' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'请求参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_param' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'返回参数' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'json_result' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作状态(0正常 1异常)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'错误消息' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'error_msg' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'oper_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'消耗时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log', + 'COLUMN', N'cost_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'操作日志记录' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oper_log' +GO + +CREATE TABLE sys_post +( + post_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dept_id bigint NOT NULL, + post_code nvarchar(64) NOT NULL, + post_category nvarchar(100) NULL, + post_name nvarchar(50) NOT NULL, + post_sort int NOT NULL, + status nchar(1) NOT NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_post__3ED7876668E2D081 PRIMARY KEY CLUSTERED (post_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位类别编码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_category' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post' +GO + +INSERT sys_post VALUES (1, N'000000', 103, N'ceo', NULL, N'董事长', 1, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (2, N'000000', 100, N'se', NULL, N'项目经理', 2, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (3, N'000000', 100, N'hr', NULL, N'人力资源', 3, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO +INSERT sys_post VALUES (4, N'000000', 100, N'user', NULL, N'普通员工', 4, N'0', 103, 1, getdate(), NULL, NULL, N'') +GO + +CREATE TABLE sys_role +( + role_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + role_name nvarchar(30) NOT NULL, + role_key nvarchar(100) NOT NULL, + role_sort int NOT NULL, + data_scope nchar(1) DEFAULT ('1') NULL, + menu_check_strictly tinyint DEFAULT ((1)) NULL, + dept_check_strictly tinyint DEFAULT ((1)) NULL, + status nchar(1) NOT NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_role__760965CCF9383145 PRIMARY KEY CLUSTERED (role_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色名称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色权限字符串' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'显示顺序' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'role_sort' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'data_scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单树选择项是否关联显示' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'menu_check_strictly' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门树选择项是否关联显示' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'dept_check_strictly' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role' +GO + +INSERT sys_role VALUES (1, N'000000', N'超级管理员', N'superadmin', 1, N'1', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N'超级管理员') +GO +INSERT sys_role VALUES (3, N'000000', N'本部门及以下', N'test1', 3, N'4', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_role VALUES (4, N'000000', N'仅本人', N'test2', 4, N'5', 1, 1, N'0', N'0', 103, 1, getdate(), NULL, NULL, N''); +GO + +CREATE TABLE sys_role_dept +( + role_id bigint NOT NULL, + dept_id bigint NOT NULL, + CONSTRAINT PK__sys_role__2BC3005BABBCA08A PRIMARY KEY CLUSTERED (role_id, dept_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色和部门关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_dept' +GO + +CREATE TABLE sys_role_menu +( + role_id bigint NOT NULL, + menu_id bigint NOT NULL, + CONSTRAINT PK__sys_role__A2C36A6187BA4B17 PRIMARY KEY CLUSTERED (role_id, menu_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'菜单ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu', + 'COLUMN', N'menu_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色和菜单关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_role_menu' +GO + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +INSERT sys_role_menu VALUES (3, 1); +GO +INSERT sys_role_menu VALUES (3, 5); +GO +INSERT sys_role_menu VALUES (3, 100); +GO +INSERT sys_role_menu VALUES (3, 101); +GO +INSERT sys_role_menu VALUES (3, 102); +GO +INSERT sys_role_menu VALUES (3, 103); +GO +INSERT sys_role_menu VALUES (3, 104); +GO +INSERT sys_role_menu VALUES (3, 105); +GO +INSERT sys_role_menu VALUES (3, 106); +GO +INSERT sys_role_menu VALUES (3, 107); +GO +INSERT sys_role_menu VALUES (3, 108); +GO +INSERT sys_role_menu VALUES (3, 118); +GO +INSERT sys_role_menu VALUES (3, 123); +GO +INSERT sys_role_menu VALUES (3, 500); +GO +INSERT sys_role_menu VALUES (3, 501); +GO +INSERT sys_role_menu VALUES (3, 1001); +GO +INSERT sys_role_menu VALUES (3, 1002); +GO +INSERT sys_role_menu VALUES (3, 1003); +GO +INSERT sys_role_menu VALUES (3, 1004); +GO +INSERT sys_role_menu VALUES (3, 1005); +GO +INSERT sys_role_menu VALUES (3, 1006); +GO +INSERT sys_role_menu VALUES (3, 1007); +GO +INSERT sys_role_menu VALUES (3, 1008); +GO +INSERT sys_role_menu VALUES (3, 1009); +GO +INSERT sys_role_menu VALUES (3, 1010); +GO +INSERT sys_role_menu VALUES (3, 1011); +GO +INSERT sys_role_menu VALUES (3, 1012); +GO +INSERT sys_role_menu VALUES (3, 1013); +GO +INSERT sys_role_menu VALUES (3, 1014); +GO +INSERT sys_role_menu VALUES (3, 1015); +GO +INSERT sys_role_menu VALUES (3, 1016); +GO +INSERT sys_role_menu VALUES (3, 1017); +GO +INSERT sys_role_menu VALUES (3, 1018); +GO +INSERT sys_role_menu VALUES (3, 1019); +GO +INSERT sys_role_menu VALUES (3, 1020); +GO +INSERT sys_role_menu VALUES (3, 1021); +GO +INSERT sys_role_menu VALUES (3, 1022); +GO +INSERT sys_role_menu VALUES (3, 1023); +GO +INSERT sys_role_menu VALUES (3, 1024); +GO +INSERT sys_role_menu VALUES (3, 1025); +GO +INSERT sys_role_menu VALUES (3, 1026); +GO +INSERT sys_role_menu VALUES (3, 1027); +GO +INSERT sys_role_menu VALUES (3, 1028); +GO +INSERT sys_role_menu VALUES (3, 1029); +GO +INSERT sys_role_menu VALUES (3, 1030); +GO +INSERT sys_role_menu VALUES (3, 1031); +GO +INSERT sys_role_menu VALUES (3, 1032); +GO +INSERT sys_role_menu VALUES (3, 1033); +GO +INSERT sys_role_menu VALUES (3, 1034); +GO +INSERT sys_role_menu VALUES (3, 1035); +GO +INSERT sys_role_menu VALUES (3, 1036); +GO +INSERT sys_role_menu VALUES (3, 1037); +GO +INSERT sys_role_menu VALUES (3, 1038); +GO +INSERT sys_role_menu VALUES (3, 1039); +GO +INSERT sys_role_menu VALUES (3, 1040); +GO +INSERT sys_role_menu VALUES (3, 1041); +GO +INSERT sys_role_menu VALUES (3, 1042); +GO +INSERT sys_role_menu VALUES (3, 1043); +GO +INSERT sys_role_menu VALUES (3, 1044); +GO +INSERT sys_role_menu VALUES (3, 1045); +GO +INSERT sys_role_menu VALUES (3, 1050); +GO +INSERT sys_role_menu VALUES (3, 1061); +GO +INSERT sys_role_menu VALUES (3, 1062); +GO +INSERT sys_role_menu VALUES (3, 1063); +GO +INSERT sys_role_menu VALUES (3, 1064); +GO +INSERT sys_role_menu VALUES (3, 1065); +GO +INSERT sys_role_menu VALUES (3, 1500); +GO +INSERT sys_role_menu VALUES (3, 1501); +GO +INSERT sys_role_menu VALUES (3, 1502); +GO +INSERT sys_role_menu VALUES (3, 1503); +GO +INSERT sys_role_menu VALUES (3, 1504); +GO +INSERT sys_role_menu VALUES (3, 1505); +GO +INSERT sys_role_menu VALUES (3, 1506); +GO +INSERT sys_role_menu VALUES (3, 1507); +GO +INSERT sys_role_menu VALUES (3, 1508); +GO +INSERT sys_role_menu VALUES (3, 1509); +GO +INSERT sys_role_menu VALUES (3, 1510); +GO +INSERT sys_role_menu VALUES (3, 1511); +GO +INSERT sys_role_menu VALUES (3, 1600); +GO +INSERT sys_role_menu VALUES (3, 1601); +GO +INSERT sys_role_menu VALUES (3, 1602); +GO +INSERT sys_role_menu VALUES (3, 1603); +GO +INSERT sys_role_menu VALUES (3, 1620); +GO +INSERT sys_role_menu VALUES (3, 1621); +GO +INSERT sys_role_menu VALUES (3, 1622); +GO +INSERT sys_role_menu VALUES (3, 1623); +GO +INSERT sys_role_menu VALUES (3, 11618); +GO +INSERT sys_role_menu VALUES (3, 11619); +GO +INSERT sys_role_menu VALUES (3, 11629); +GO +INSERT sys_role_menu VALUES (3, 11632); +GO +INSERT sys_role_menu VALUES (3, 11633); +GO +INSERT sys_role_menu VALUES (3, 11638); +GO +INSERT sys_role_menu VALUES (3, 11639); +GO +INSERT sys_role_menu VALUES (3, 11640); +GO +INSERT sys_role_menu VALUES (3, 11641); +GO +INSERT sys_role_menu VALUES (3, 11642); +GO +INSERT sys_role_menu VALUES (3, 11643); +GO +INSERT sys_role_menu VALUES (4, 5); +GO +INSERT sys_role_menu VALUES (4, 1500); +GO +INSERT sys_role_menu VALUES (4, 1501); +GO +INSERT sys_role_menu VALUES (4, 1502); +GO +INSERT sys_role_menu VALUES (4, 1503); +GO +INSERT sys_role_menu VALUES (4, 1504); +GO +INSERT sys_role_menu VALUES (4, 1505); +GO +INSERT sys_role_menu VALUES (4, 1506); +GO +INSERT sys_role_menu VALUES (4, 1507); +GO +INSERT sys_role_menu VALUES (4, 1508); +GO +INSERT sys_role_menu VALUES (4, 1509); +GO +INSERT sys_role_menu VALUES (4, 1510); +GO +INSERT sys_role_menu VALUES (4, 1511); +GO + +CREATE TABLE sys_user +( + user_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dept_id bigint NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) NOT NULL, + user_type nvarchar(10) DEFAULT ('sys_user') NULL, + email nvarchar(50) DEFAULT '' NULL, + phonenumber nvarchar(11) DEFAULT '' NULL, + sex nchar(1) DEFAULT ('0') NULL, + avatar bigint NULL, + password nvarchar(100) DEFAULT '' NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + login_ip nvarchar(128) DEFAULT '' NULL, + login_date datetime2(7) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_user__B9BE370F79170B6A PRIMARY KEY CLUSTERED (user_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'部门ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'dept_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户类型(sys_user系统用户)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'user_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'手机号码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'phonenumber' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户性别(0男 1女 2未知)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'sex' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'密码' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'password' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'帐号状态(0正常 1停用)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'status' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'最后登录IP' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'login_ip' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'最后登录时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'login_date' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'update_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'备注' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user', + 'COLUMN', N'remark' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户信息表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user' +GO + +INSERT sys_user VALUES (1, N'000000', 103, N'admin', N'疯狂的狮子Li', N'sys_user', N'crazyLionLi@163.com', N'15888888888', N'1', NULL, N'$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), NULL, NULL, N'管理员') +GO +INSERT sys_user VALUES (3, N'000000', 108, N'test', N'本部门及以下 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 3, getdate(), NULL); +GO +INSERT sys_user VALUES (4, N'000000', 102, N'test1', N'仅本人 密码666666', N'sys_user', N'', N'', N'0', NULL, N'$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', N'0', N'0', N'127.0.0.1', getdate(), 103, 1, getdate(), 4, getdate(), NULL); +GO + +CREATE TABLE sys_user_post +( + user_id bigint NOT NULL, + post_id bigint NOT NULL, + CONSTRAINT PK__sys_user__CA534F799C04589B PRIMARY KEY CLUSTERED (user_id, post_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'岗位ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post', + 'COLUMN', N'post_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户与岗位关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_post' +GO + +INSERT sys_user_post VALUES (1, 1) +GO + +CREATE TABLE sys_user_role +( + user_id bigint NOT NULL, + role_id bigint NOT NULL, + CONSTRAINT PK__sys_user__6EDEA153FB34D8F0 PRIMARY KEY CLUSTERED (user_id, role_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'角色ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role', + 'COLUMN', N'role_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户和角色关联表' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_user_role' +GO + +INSERT sys_user_role VALUES (1, 1) +GO +INSERT sys_user_role VALUES (3, 3); +GO +INSERT sys_user_role VALUES (4, 4); +GO + +CREATE TABLE sys_oss +( + oss_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + file_name nvarchar(255) DEFAULT '' NOT NULL, + original_name nvarchar(255) DEFAULT '' NOT NULL, + file_suffix nvarchar(10) DEFAULT '' NOT NULL, + url nvarchar(500) NOT NULL, + create_dept bigint NULL, + create_time datetime2(7) NULL, + create_by bigint NULL, + update_time datetime2(7) NULL, + update_by bigint NULL, + service nvarchar(20) DEFAULT ('minio') NOT NULL, + CONSTRAINT PK__sys_oss__91241EA442389F0D PRIMARY KEY CLUSTERED (oss_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'对象存储主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'oss_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'tenant_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'文件名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'file_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'原名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'original_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'文件后缀名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'file_suffix' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'URL地址', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'url' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'上传人', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'服务商', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss', + 'COLUMN', N'service' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'OSS对象存储表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss' +GO + +CREATE TABLE sys_oss_config +( + oss_config_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + config_key nvarchar(20) DEFAULT '' NOT NULL, + access_key nvarchar(255) DEFAULT '' NULL, + secret_key nvarchar(255) DEFAULT '' NULL, + bucket_name nvarchar(255) DEFAULT '' NULL, + prefix nvarchar(255) DEFAULT '' NULL, + endpoint nvarchar(255) DEFAULT '' NULL, + domain nvarchar(255) DEFAULT '' NULL, + is_https nchar(1) DEFAULT ('N') NULL, + region nvarchar(255) DEFAULT '' NULL, + access_policy nchar(1) DEFAULT ('1') NOT NULL, + status nchar(1) DEFAULT ('1') NULL, + ext1 nvarchar(255) DEFAULT '' NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + remark nvarchar(500) NULL, + CONSTRAINT PK__sys_oss___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (oss_config_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'oss_config_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户编号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'tenant_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'配置key', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'config_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'accessKey', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'access_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'secret_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'桶名称', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'bucket_name' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'前缀', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'prefix' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'访问站点', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'endpoint' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'自定义域名', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'domain' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'是否https(Y=是,N=否)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'is_https' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'域', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'region' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'桶权限类型(0=private 1=public 2=custom)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'access_policy' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'是否默认(0=是,1=否)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'status' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'扩展字段', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'ext1' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'备注', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config', + 'COLUMN', N'remark' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'对象存储配置表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_oss_config' +GO + +INSERT INTO sys_oss_config VALUES (N'1', N'000000', N'minio', N'ruoyi', N'ruoyi123', N'ruoyi', N'', N'127.0.0.1:9000', N'',N'N', N'', N'1', N'0', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N'2', N'000000', N'qiniu', N'XXXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi', N'', N's3-cn-north-1.qiniucs.com', N'',N'N', N'', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N3, N'000000', N'aliyun', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi', N'', N'oss-cn-beijing.aliyuncs.com', N'',N'N', N'', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N'4', N'000000', N'qcloud', N'XXXXXXXXXXXXXXX', N'XXXXXXXXXXXXXXX', N'ruoyi-1250000000', N'', N'cos.ap-beijing.myqcloud.com', N'',N'N', N'ap-beijing', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO +INSERT INTO sys_oss_config VALUES (N'5', N'000000', N'image', N'ruoyi', N'ruoyi123', N'ruoyi', N'image', N'127.0.0.1:9000', N'',N'N', N'', N'1', N'1', N'', 103, 1, getdate(), 1, getdate(), NULL) +GO + + +CREATE TABLE sys_client +( + id bigint NOT NULL, + client_id nvarchar(64) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + client_secret nvarchar(255) DEFAULT '' NULL, + grant_type nvarchar(255) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + active_timeout int DEFAULT ((1800)) NULL, + timeout int DEFAULT ((604800)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL + CONSTRAINT PK__sys_client___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'客户端id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'客户端key', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_key' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'客户端秘钥', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'client_secret' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'授权类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'grant_type' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'设备类型', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'device_type' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'token活跃超时时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'active_timeout' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'token固定超时', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'timeout' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'状态(0正常 1停用)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'status' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 1代表删除)', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新者', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client', + 'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'系统授权表', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_client' +GO + +INSERT INTO sys_client VALUES (N'1', N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO +INSERT INTO sys_client VALUES (N'2', N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO + +CREATE TABLE test_demo +( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + dept_id bigint NULL, + user_id bigint NULL, + order_num int DEFAULT ((0)) NULL, + test_key nvarchar(255) NULL, + value nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_dem__3213E83F176051C8 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'排序号', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'order_num' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'key键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'test_key' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'value' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试单表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_demo' +GO + +CREATE TABLE test_tree +( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT ('000000') NULL, + parent_id bigint DEFAULT ((0)) NULL, + dept_id bigint NULL, + user_id bigint NULL, + tree_name nvarchar(255) NULL, + version int DEFAULT ((0)) NULL, + create_dept bigint NULL, + create_time datetime2(0) NULL, + create_by bigint NULL, + update_time datetime2(0) NULL, + update_by bigint NULL, + del_flag int DEFAULT ((0)) NULL, + CONSTRAINT PK__test_tre__3213E83FC75A1B63 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'主键', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'租户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'父id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'dept_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'用户id', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'user_id' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'值', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'tree_name' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'版本', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'version' +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'创建人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新时间', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'更新人', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'删除标志', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree', + 'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'测试树表', + 'SCHEMA', N'dbo', + 'TABLE', N'test_tree' +GO + +INSERT test_demo VALUES (1, N'000000', 102, 4, 1, N'测试数据权限', N'测试', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (2, N'000000', 102, 3, 2, N'子节点1', N'111', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (3, N'000000', 102, 3, 3, N'子节点2', N'222', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (4, N'000000', 108, 4, 4, N'测试数据', N'demo', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (5, N'000000', 108, 3, 13, N'子节点11', N'1111', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (6, N'000000', 108, 3, 12, N'子节点22', N'2222', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (7, N'000000', 108, 3, 11, N'子节点33', N'3333', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (8, N'000000', 108, 3, 10, N'子节点44', N'4444', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (9, N'000000', 108, 3, 9, N'子节点55', N'5555', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (10, N'000000', 108, 3, 8, N'子节点66', N'6666', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (11, N'000000', 108, 3, 7, N'子节点77', N'7777', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (12, N'000000', 108, 3, 6, N'子节点88', N'8888', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_demo VALUES (13, N'000000', 108, 3, 5, N'子节点99', N'9999', 0, 103, getdate(), 1, NULL, NULL, 0); +GO + +INSERT test_tree VALUES (1, N'000000', 0, 102, 4, N'测试数据权限', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (2, N'000000', 1, 102, 3, N'子节点1', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (3, N'000000', 2, 102, 3, N'子节点2', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (4, N'000000', 0, 108, 4, N'测试树1', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (5, N'000000', 4, 108, 3, N'子节点11', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (6, N'000000', 4, 108, 3, N'子节点22', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (7, N'000000', 4, 108, 3, N'子节点33', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (8, N'000000', 5, 108, 3, N'子节点44', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (9, N'000000', 6, 108, 3, N'子节点55', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (10, N'000000', 7, 108, 3, N'子节点66', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (11, N'000000', 7, 108, 3, N'子节点77', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (12, N'000000', 10, 108, 3, N'子节点88', 0, 103, getdate(), 1, NULL, NULL, 0); +GO +INSERT test_tree VALUES (13, N'000000', 10, 108, 3, N'子节点99', 0, 103, getdate(), 1, NULL, NULL, 0); +GO diff --git a/script/sql/sqlserver/sqlserver_ry_workflow.sql b/script/sql/sqlserver/sqlserver_ry_workflow.sql new file mode 100644 index 0000000..ea4b720 --- /dev/null +++ b/script/sql/sqlserver/sqlserver_ry_workflow.sql @@ -0,0 +1,1336 @@ +CREATE TABLE flow_definition ( + id bigint NOT NULL, + flow_code nvarchar(40) NOT NULL, + flow_name nvarchar(100) NOT NULL, + category nvarchar(100) NULL, + version nvarchar(20) NOT NULL, + is_publish tinyint DEFAULT('0') NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + activity_status tinyint DEFAULT('1') NULL, + listener_type nvarchar(100) NULL, + listener_path nvarchar(400) NULL, + ext nvarchar(500) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_def__3213E83FEE39AE33 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'flow_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'flow_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程类别', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'category' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程版本', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'是否发布(0未发布 1已发布 9失效)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'is_publish' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程激活状态(0挂起 1激活)', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'activity_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'listener_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'listener_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务详情 存业务表对象json字符串', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义表', +'SCHEMA', N'dbo', +'TABLE', N'flow_definition' +GO + +CREATE TABLE flow_node ( + id bigint NOT NULL, + node_type tinyint NOT NULL, + definition_id bigint NOT NULL, + node_code nvarchar(100) NOT NULL, + node_name nvarchar(100) NULL, + permission_flag nvarchar(200) NULL, + node_ratio decimal(6,3) NULL, + coordinate nvarchar(100) NULL, + skip_any_node nvarchar(100) DEFAULT('N') NULL, + any_node_skip nvarchar(100) NULL, + listener_type nvarchar(100) NULL, + listener_path nvarchar(400) NULL, + handler_type nvarchar(100) NULL, + handler_path nvarchar(400) NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + version nvarchar(20) NOT NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_nod__3213E83F372470DE PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'权限标识(权限类型:权限标识,可以多个,用逗号隔开)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'permission_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程签署比例值', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'node_ratio' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'坐标', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'coordinate' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'是否可以退回任意节点(Y是 N否)即将删除', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'skip_any_node' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任意结点跳转', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'any_node_skip' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'listener_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'监听器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'listener_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'处理器类型', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'handler_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'处理器路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'handler_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'版本', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'version' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_node', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点表', +'SCHEMA', N'dbo', +'TABLE', N'flow_node' +GO + +CREATE TABLE flow_skip ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + now_node_code nvarchar(100) NOT NULL, + now_node_type tinyint NULL, + next_node_code nvarchar(100) NOT NULL, + next_node_type tinyint NULL, + skip_name nvarchar(100) NULL, + skip_type nvarchar(40) NULL, + skip_condition nvarchar(200) NULL, + coordinate nvarchar(100) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_ski__3213E83F073FEE6E PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'当前流程节点的编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'now_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'当前节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'now_node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'下一个流程节点的编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'next_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'下一个节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'next_node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转类型(PASS审批通过 REJECT退回)', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'跳转条件', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'skip_condition' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'坐标', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'coordinate' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点跳转关联表', +'SCHEMA', N'dbo', +'TABLE', N'flow_skip' +GO + +CREATE TABLE flow_instance ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + business_id nvarchar(40) NOT NULL, + node_type tinyint NOT NULL, + node_code nvarchar(40) NOT NULL, + node_name nvarchar(100) NULL, + variable nvarchar(max) NULL, + flow_status nvarchar(20) NOT NULL, + activity_status tinyint DEFAULT('1') NULL, + def_json nvarchar(max) NULL, + create_by nvarchar(64) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + ext nvarchar(500) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_ins__3213E83F5190FEE1 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +TEXTIMAGE_ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'business_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务变量', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'variable' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程状态(0待提交 1审批中 2 审批通过 3自动通过 4终止 5作废 6撤销 7取回 8已完成 9已退回 10失效)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'flow_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程激活状态(0挂起 1激活)', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'activity_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程定义json', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'def_json' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'扩展字段,预留给业务系统使用', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程实例表', +'SCHEMA', N'dbo', +'TABLE', N'flow_instance' +GO + +CREATE TABLE flow_task ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + instance_id bigint NOT NULL, + node_code nvarchar(100) NOT NULL, + node_name nvarchar(100) NULL, + node_type tinyint NOT NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_tas__3213E83F5AE1F1BA PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_instance表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'instance_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_task', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'待办任务表', +'SCHEMA', N'dbo', +'TABLE', N'flow_task' +GO + +CREATE TABLE flow_his_task ( + id bigint NOT NULL, + definition_id bigint NOT NULL, + instance_id bigint NOT NULL, + task_id bigint NOT NULL, + node_code nvarchar(200) NULL, + node_name nvarchar(200) NULL, + node_type tinyint NULL, + target_node_code nvarchar(100) NULL, + target_node_name nvarchar(100) NULL, + approver nvarchar(40) NULL, + cooperate_type tinyint DEFAULT('0') NULL, + collaborator nvarchar(40) NULL, + skip_type nvarchar(10) NOT NULL, + flow_status nvarchar(20) NOT NULL, + form_custom nchar(1) DEFAULT('N') NULL, + form_path nvarchar(100) NULL, + message nvarchar(500) NULL, + variable nvarchar(max) NULL, + ext nvarchar(500) NULL, + create_time datetime2(7) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_his__3213E83F67951564 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_definition表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'definition_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_instance表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'instance_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'对应flow_task表的id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'task_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'node_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'目标节点编码', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'target_node_code' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'结束节点名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'target_node_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批者', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'approver' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'协作方式(1审批 2转办 3委派 4会签 5票签 6加签 7减签)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'cooperate_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'协作人', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'collaborator' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流转类型(PASS通过 REJECT退回 NONE无动作)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'skip_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程状态(1审批中 2 审批通过 9已退回 10失效)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'flow_status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单是否自定义(Y是 N否)', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'form_custom' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批表单路径', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'form_path' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批意见', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'message' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务变量', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'variable' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'业务详情 存业务表对象json字符串', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'ext' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务开始时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'审批完成时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'历史任务记录表', +'SCHEMA', N'dbo', +'TABLE', N'flow_his_task' +GO + +CREATE TABLE flow_user ( + id bigint NOT NULL, + type nchar(1) NOT NULL, + processed_by nvarchar(80) NULL, + associated bigint NOT NULL, + create_time datetime2(7) NULL, + create_by nvarchar(80) NULL, + update_time datetime2(7) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + tenant_id nvarchar(40) NULL, + CONSTRAINT PK__flow_use__3213E83FFA38CA8B PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +CREATE NONCLUSTERED INDEX user_processed_type ON flow_user (processed_by ASC, type ASC) +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'人员类型(1待办任务的审批人权限 2待办任务的转办人权限 3待办任务的委托人权限)', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'权限人', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'processed_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'任务表id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'associated' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建人', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户id', +'SCHEMA', N'dbo', +'TABLE', N'flow_user', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程用户表', +'SCHEMA', N'dbo', +'TABLE', N'flow_user' +GO + +CREATE TABLE flow_category ( + category_id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT('000000') NULL, + parent_id bigint DEFAULT(0) NULL, + ancestors nvarchar(500) DEFAULT('') NULL, + category_name nvarchar(30) NOT NULL, + order_num int DEFAULT(0) NULL, + del_flag nchar(1) DEFAULT('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__flow_cat__D54EE9B4AE98B9C1 PRIMARY KEY CLUSTERED (category_id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类ID', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'category_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户编号', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'父流程分类id', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'parent_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'祖级列表', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'ancestors' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类名称', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'category_name' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'显示顺序', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'order_num' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'删除标志(0代表存在 1代表删除)', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'del_flag' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建部门', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'flow_category', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'流程分类', +'SCHEMA', N'dbo', +'TABLE', N'flow_category' +GO + +INSERT flow_category VALUES (100, N'000000', 0, N'0', N'OA审批', 0, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (101, N'000000', 100, N'0,100', N'假勤管理', 0, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (102, N'000000', 100, N'0,100', N'人事管理', 1, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (103, N'000000', 101, N'0,100,101', N'请假', 0, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (104, N'000000', 101, N'0,100,101', N'出差', 1, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (105, N'000000', 101, N'0,100,101', N'加班', 2, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (106, N'000000', 101, N'0,100,101', N'换班', 3, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (107, N'000000', 101, N'0,100,101', N'外出', 4, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (108, N'000000', 102, N'0,100,102', N'转正', 1, N'0', 103, 1, getdate(), NULL, NULL); +GO +INSERT flow_category VALUES (109, N'000000', 102, N'0,100,102', N'离职', 2, N'0', 103, 1, getdate(), NULL, NULL); +GO + +CREATE TABLE test_leave ( + id bigint NOT NULL, + tenant_id nvarchar(20) DEFAULT('000000') NULL, + leave_type nvarchar(255) NOT NULL, + start_date datetime2(7) NOT NULL, + end_date datetime2(7) NOT NULL, + leave_days int NOT NULL, + remark nvarchar(255) NULL, + status nvarchar(255) NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL, + CONSTRAINT PK__test_lea__3213E83F348788FA PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'id', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'租户编号', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'tenant_id' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假类型', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'leave_type' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'开始时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'start_date' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'结束时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'end_date' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假天数', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'leave_days' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假原因', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'remark' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'状态', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'status' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建部门', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_dept' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'create_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'update_by' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'test_leave', +'COLUMN', N'update_time' +GO + +EXEC sp_addextendedproperty +'MS_Description', N'请假申请表', +'SCHEMA', N'dbo', +'TABLE', N'test_leave' +GO + +INSERT sys_menu VALUES (11616, N'工作流', 0, 6, N'workflow', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'workflow', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11618, N'我的任务', 0, 7, N'task', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'my-task', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11619, N'我的待办', 11618, 2, N'taskWaiting', N'workflow/task/taskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11632, N'我的已办', 11618, 3, N'taskFinish', N'workflow/task/taskFinish', N'', 1, 1, N'C', N'0', N'0', N'', N'finish', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11633, N'我的抄送', 11618, 4, N'taskCopyList', N'workflow/task/taskCopyList', N'', 1, 1, N'C', N'0', N'0', N'', N'my-copy', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11620, N'流程定义', 11616, 3, N'processDefinition', N'workflow/processDefinition/index', N'', 1, 1, N'C', N'0', N'0', N'', N'process-definition', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11621, N'流程实例', 11630, 1, N'processInstance', N'workflow/processInstance/index', N'', 1, 1, N'C', N'0', N'0', N'', N'tree-table', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11622, N'流程分类', 11616, 1, N'category', N'workflow/category/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:category:list', N'category', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11629, N'我发起的', 11618, 1, N'myDocument', N'workflow/task/myDocument', N'', 1, 1, N'C', N'0', N'0', N'', N'guide', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11630, N'流程监控', 11616, 4, N'monitor', NULL, N'', 1, 0, N'M', N'0', N'0', N'', N'monitor', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11631, N'待办任务', 11630, 2, N'allTaskWaiting', N'workflow/task/allTaskWaiting', N'', 1, 1, N'C', N'0', N'0', N'', N'waiting', 103, 1, GETDATE(), NULL, NULL, N''); +GO + +-- 流程分类管理相关按钮 +INSERT sys_menu VALUES (11623, N'流程分类查询', 11622, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11624, N'流程分类新增', 11622, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11625, N'流程分类修改', 11622, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11626, N'流程分类删除', 11622, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11627, N'流程分类导出', 11622, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:category:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO + +-- 请假测试相关按钮 +INSERT sys_menu VALUES (11638, N'请假申请', 5, 1, N'leave', N'workflow/leave/index', N'', 1, 0, N'C', N'0', N'0', N'workflow:leave:list', N'#', 103, 1, GETDATE(), NULL, NULL, N'请假申请菜单'); +GO +INSERT sys_menu VALUES (11639, N'请假申请查询', 11638, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:query', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11640, N'请假申请新增', 11638, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:add', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11641, N'请假申请修改', 11638, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:edit', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11642, N'请假申请删除', 11638, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:remove', N'#', 103, 1, GETDATE(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (11643, N'请假申请导出', 11638, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'workflow:leave:export', N'#', 103, 1, GETDATE(), NULL, NULL, N''); + +INSERT sys_dict_type VALUES (13, N'000000', N'业务状态', N'wf_business_status', 103, 1, GETDATE(), NULL, NULL, N'业务状态列表'); +GO +INSERT sys_dict_type VALUES (14, N'000000', N'表单类型', N'wf_form_type', 103, 1, GETDATE(), NULL, NULL, N'表单类型列表'); +GO +INSERT sys_dict_type VALUES (15, N'000000', N'任务状态', N'wf_task_status', 103, 1, GETDATE(), NULL, NULL, N'任务状态'); +GO + +INSERT sys_dict_data VALUES (39, N'000000', 1, N'已撤销', N'cancel', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已撤销'); +GO +INSERT sys_dict_data VALUES (40, N'000000', 2, N'草稿', N'draft', N'wf_business_status', N'', N'info', N'N', 103, 1, GETDATE(), NULL, NULL, N'草稿'); +GO +INSERT sys_dict_data VALUES (41, N'000000', 3, N'待审核', N'waiting', N'wf_business_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'待审核'); +GO +INSERT sys_dict_data VALUES (42, N'000000', 4, N'已完成', N'finish', N'wf_business_status', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'已完成'); +GO +INSERT sys_dict_data VALUES (43, N'000000', 5, N'已作废', N'invalid', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已作废'); +GO +INSERT sys_dict_data VALUES (44, N'000000', 6, N'已退回', N'back', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已退回'); +GO +INSERT sys_dict_data VALUES (45, N'000000', 7, N'已终止', N'termination', N'wf_business_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'已终止'); +GO +INSERT sys_dict_data VALUES (46, N'000000', 1, N'自定义表单', N'static', N'wf_form_type', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'自定义表单'); +GO +INSERT sys_dict_data VALUES (47, N'000000', 2, N'动态表单', N'dynamic', N'wf_form_type', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'动态表单'); +GO +INSERT sys_dict_data VALUES (48, N'000000', 1, N'撤销', N'cancel', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'撤销'); +GO +INSERT sys_dict_data VALUES (49, N'000000', 2, N'通过', N'pass', N'wf_task_status', N'', N'success', N'N', 103, 1, GETDATE(), NULL, NULL, N'通过'); +GO +INSERT sys_dict_data VALUES (50, N'000000', 3, N'待审核', N'waiting', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'待审核'); +GO +INSERT sys_dict_data VALUES (51, N'000000', 4, N'作废', N'invalid', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'作废'); +GO +INSERT sys_dict_data VALUES (52, N'000000', 5, N'退回', N'back', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'退回'); +GO +INSERT sys_dict_data VALUES (53, N'000000', 6, N'终止', N'termination', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'终止'); +GO +INSERT sys_dict_data VALUES (54, N'000000', 7, N'转办', N'transfer', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'转办'); +GO +INSERT sys_dict_data VALUES (55, N'000000', 8, N'委托', N'depute', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'委托'); +GO +INSERT sys_dict_data VALUES (56, N'000000', 9, N'抄送', N'copy', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'抄送'); +GO +INSERT sys_dict_data VALUES (57, N'000000', 10, N'加签', N'sign', N'wf_task_status', N'', N'primary', N'N', 103, 1, GETDATE(), NULL, NULL, N'加签'); +GO +INSERT sys_dict_data VALUES (58, N'000000', 11, N'减签', N'sign_off', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'减签'); +GO +INSERT sys_dict_data VALUES (59, N'000000', 11, N'超时', N'timeout', N'wf_task_status', N'', N'danger', N'N', 103, 1, GETDATE(), NULL, NULL, N'超时'); +GO diff --git a/script/sql/update/oracle/update_5.0-5.1.sql b/script/sql/update/oracle/update_5.0-5.1.sql new file mode 100644 index 0000000..09cfae8 --- /dev/null +++ b/script/sql/update/oracle/update_5.0-5.1.sql @@ -0,0 +1,151 @@ +ALTER TABLE gen_table ADD (data_name VARCHAR2(200) DEFAULT ''); + +COMMENT ON COLUMN gen_table.data_name IS '数据源名称'; + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120; + +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id number(20) not null, + user_id number(20) not null, + tenant_id varchar2(20) default null, + auth_id varchar2(255) not null, + source varchar2(255) not null, + open_id varchar2(255) default null, + user_name varchar2(30) not null, + nick_name varchar2(30) default '', + email varchar2(255) default '', + avatar varchar2(500) default '', + access_token varchar2(255) not null, + expire_in number(20) default null, + refresh_token varchar2(255) default null, + access_code varchar2(255) default null, + union_id varchar2(255) default null, + scope varchar2(255) default null, + token_type varchar2(255) default null, + id_token varchar2(255) default null, + mac_algorithm varchar2(255) default null, + mac_key varchar2(255) default null, + code varchar2(255) default null, + oauth_token varchar2(255) default null, + oauth_token_secret varchar2(255) default null, + create_dept number(20), + create_by number(20), + create_time date, + update_by number(20), + update_time date, + del_flag char(1) default '0' +); + +alter table sys_social add constraint pk_sys_social primary key (id); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 2代表删除)'; + + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +create table sys_client ( + id number(20) not null, + client_id varchar2(64) default null, + client_key varchar2(32) default null, + client_secret varchar2(255) default null, + grant_type varchar2(255) default null, + device_type varchar2(32) default null, + active_timeout number(11) default 1800, + timeout number(11) default 604800, + status char(1) default '0', + del_flag char(1) default '0', + create_dept number(20) default null, + create_by number(20) default null, + create_time date, + update_by number(20) default null, + update_time date +); + +alter table sys_client add constraint pk_sys_client primary key (id); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 2代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate, 1, sysdate); + +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', '0', 103, 1, sysdate, null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', '0', 103, 1, sysdate, null, null, '客户端设备类型'); + +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', '0', 103, 1, sysdate, null, null, '小程序'); + +-- 二级菜单 +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate, null, null, '客户端管理菜单'); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate, null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate, null, null, ''); + +-- 角色菜单权限 +insert into sys_role_menu values ('2', '1061'); +insert into sys_role_menu values ('2', '1062'); +insert into sys_role_menu values ('2', '1063'); +insert into sys_role_menu values ('2', '1064'); +insert into sys_role_menu values ('2', '1065'); + + +update sys_dept set leader = null; +ALTER TABLE sys_dept MODIFY (leader NUMBER(20)) diff --git a/script/sql/update/oracle/update_5.1.0-5.1.1.sql b/script/sql/update/oracle/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..979a4bd --- /dev/null +++ b/script/sql/update/oracle/update_5.1.0-5.1.1.sql @@ -0,0 +1,5 @@ +ALTER TABLE sys_logininfor ADD (client_key varchar2(32) DEFAULT ''); +COMMENT ON COLUMN sys_logininfor.client_key IS '客户端'; + +ALTER TABLE sys_logininfor ADD (device_type varchar2(32) DEFAULT ''); +COMMENT ON COLUMN sys_logininfor.device_type IS '设备类型'; diff --git a/script/sql/update/postgres/update_5.0-5.1.sql b/script/sql/update/postgres/update_5.0-5.1.sql new file mode 100644 index 0000000..f5f0a5c --- /dev/null +++ b/script/sql/update/postgres/update_5.0-5.1.sql @@ -0,0 +1,150 @@ +ALTER TABLE gen_table ADD data_name varchar(200) default ''::varchar; + +COMMENT ON COLUMN gen_table.data_name IS '数据源名称'; + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120; + +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +create table sys_social +( + id int8 not null, + user_id int8 not null, + tenant_id varchar(20) default null::varchar, + auth_id varchar(255) not null, + source varchar(255) not null, + open_id varchar(255) default null::varchar, + user_name varchar(30) not null, + nick_name varchar(30) default ''::varchar, + email varchar(255) default ''::varchar, + avatar varchar(500) default ''::varchar, + access_token varchar(255) not null, + expire_in int8 default null, + refresh_token varchar(255) default null::varchar, + access_code varchar(255) default null::varchar, + union_id varchar(255) default null::varchar, + scope varchar(255) default null::varchar, + token_type varchar(255) default null::varchar, + id_token varchar(255) default null::varchar, + mac_algorithm varchar(255) default null::varchar, + mac_key varchar(255) default null::varchar, + code varchar(255) default null::varchar, + oauth_token varchar(255) default null::varchar, + oauth_token_secret varchar(255) default null::varchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + del_flag char default '0'::bpchar, + constraint "pk_sys_social" primary key (id) +); + +comment on table sys_social is '社会化关系表'; +comment on column sys_social.id is '主键'; +comment on column sys_social.user_id is '用户ID'; +comment on column sys_social.tenant_id is '租户id'; +comment on column sys_social.auth_id is '平台+平台唯一id'; +comment on column sys_social.source is '用户来源'; +comment on column sys_social.open_id is '平台编号唯一id'; +comment on column sys_social.user_name is '登录账号'; +comment on column sys_social.nick_name is '用户昵称'; +comment on column sys_social.email is '用户邮箱'; +comment on column sys_social.avatar is '头像地址'; +comment on column sys_social.access_token is '用户的授权令牌'; +comment on column sys_social.expire_in is '用户的授权令牌的有效期,部分平台可能没有'; +comment on column sys_social.refresh_token is '刷新令牌,部分平台可能没有'; +comment on column sys_social.access_code is '平台的授权信息,部分平台可能没有'; +comment on column sys_social.union_id is '用户的 unionid'; +comment on column sys_social.scope is '授予的权限,部分平台可能没有'; +comment on column sys_social.token_type is '个别平台的授权信息,部分平台可能没有'; +comment on column sys_social.id_token is 'id token,部分平台可能没有'; +comment on column sys_social.mac_algorithm is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.mac_key is '小米平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.code is '用户的授权code,部分平台可能没有'; +comment on column sys_social.oauth_token is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.oauth_token_secret is 'Twitter平台用户的附带属性,部分平台可能没有'; +comment on column sys_social.create_dept is '创建部门'; +comment on column sys_social.create_by is '创建者'; +comment on column sys_social.create_time is '创建时间'; +comment on column sys_social.update_by is '更新者'; +comment on column sys_social.update_time is '更新时间'; +comment on column sys_social.del_flag is '删除标志(0代表存在 2代表删除)'; + + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +drop table if exists sys_client; +create table sys_client ( + id int8, + client_id varchar(64) default ''::varchar, + client_key varchar(32) default ''::varchar, + client_secret varchar(255) default ''::varchar, + grant_type varchar(255) default ''::varchar, + device_type varchar(32) default ''::varchar, + active_timeout int4 default 1800, + timeout int4 default 604800, + status char(1) default '0'::bpchar, + del_flag char(1) default '0'::bpchar, + create_dept int8, + create_by int8, + create_time timestamp, + update_by int8, + update_time timestamp, + constraint sys_client_pk primary key (id) +); + +comment on table sys_client is '系统授权表'; +comment on column sys_client.id is '主键'; +comment on column sys_client.client_id is '客户端id'; +comment on column sys_client.client_key is '客户端key'; +comment on column sys_client.client_secret is '客户端秘钥'; +comment on column sys_client.grant_type is '授权类型'; +comment on column sys_client.device_type is '设备类型'; +comment on column sys_client.active_timeout is 'token活跃超时时间'; +comment on column sys_client.timeout is 'token固定超时'; +comment on column sys_client.status is '状态(0正常 1停用)'; +comment on column sys_client.del_flag is '删除标志(0代表存在 2代表删除)'; +comment on column sys_client.create_dept is '创建部门'; +comment on column sys_client.create_by is '创建者'; +comment on column sys_client.create_time is '创建时间'; +comment on column sys_client.update_by is '更新者'; +comment on column sys_client.update_time is '更新时间'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, now(), 1, now()); + +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', '0', 103, 1, now(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', '0', 103, 1, now(), null, null, '客户端设备类型'); + +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', '0', 103, 1, now(), null, null, '小程序'); + +-- 二级菜单 +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', '1', '0', 'C', '0', '0', 'system:client:list', 'international', 103, 1, now(), null, null, '客户端管理菜单'); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:query', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:remove', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', '1', '0', 'F', '0', '0', 'system:client:export', '#', 103, 1, now(), null, null, ''); + +-- 角色菜单权限 +insert into sys_role_menu values ('2', '1061'); +insert into sys_role_menu values ('2', '1062'); +insert into sys_role_menu values ('2', '1063'); +insert into sys_role_menu values ('2', '1064'); +insert into sys_role_menu values ('2', '1065'); + + +update sys_dept set leader = null; +ALTER TABLE sys_dept ALTER COLUMN leader TYPE int8; diff --git a/script/sql/update/postgres/update_5.1.0-5.1.1.sql b/script/sql/update/postgres/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..29f5507 --- /dev/null +++ b/script/sql/update/postgres/update_5.1.0-5.1.1.sql @@ -0,0 +1,5 @@ +ALTER TABLE sys_logininfor ADD client_key varchar(32) default ''::varchar; +COMMENT ON COLUMN sys_logininfor.client_key IS '客户端'; + +ALTER TABLE sys_logininfor ADD device_type varchar(32) default ''::varchar; +COMMENT ON COLUMN sys_logininfor.device_type IS '设备类型'; diff --git a/script/sql/update/postgres/update_5.1.1-5.1.2.sql b/script/sql/update/postgres/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..62eb836 --- /dev/null +++ b/script/sql/update/postgres/update_5.1.1-5.1.2.sql @@ -0,0 +1,5 @@ +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, now(), null, null, ''); +insert into sys_menu values('1621', '配置添加', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:add', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1622', '配置编辑', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:edit', '#', 103, 1, now(), null, null, ''); +insert into sys_menu values('1623', '配置删除', '118', '6', '#', '', '', '1', '0', 'F', '0', '0', 'system:ossConfig:remove', '#', 103, 1, now(), null, null, ''); diff --git a/script/sql/update/postgres/update_5.1.2-5.2.0.sql b/script/sql/update/postgres/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..5089a09 --- /dev/null +++ b/script/sql/update/postgres/update_5.1.2-5.2.0.sql @@ -0,0 +1,9 @@ +ALTER TABLE sys_dept ADD COLUMN dept_category varchar(100) default null::varchar; +COMMENT ON COLUMN sys_dept.dept_category IS '客户端'; +ALTER TABLE sys_post ADD COLUMN dept_id int8 NOT NULL; +COMMENT ON COLUMN sys_post.dept_id IS '部门id'; +ALTER TABLE sys_post ADD COLUMN post_category varchar(100) default null::varchar; +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.0-5.1.sql b/script/sql/update/sqlserver/update_5.0-5.1.sql new file mode 100644 index 0000000..bde3813 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.0-5.1.sql @@ -0,0 +1,409 @@ +ALTER TABLE gen_table ADD data_name nvarchar(200) DEFAULT '' NULL +GO + +EXEC sp_addextendedproperty + 'MS_Description', N'数据源名称', + 'SCHEMA', N'dbo', + 'TABLE', N'gen_table', + 'COLUMN', N'data_name' +GO + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120 +GO + +create table sys_social +( + id bigint NOT NULL, + user_id bigint NOT NULL, + tenant_id nvarchar(20) NULL, + auth_id nvarchar(255) NOT NULL, + source nvarchar(255) NOT NULL, + open_id nvarchar(255) NULL, + user_name nvarchar(30) NOT NULL, + nick_name nvarchar(30) DEFAULT ('') NULL, + email nvarchar(255) DEFAULT ('') NULL, + avatar nvarchar(500) DEFAULT ('') NULL, + access_token nvarchar(255) NOT NULL, + expire_in bigint NULL, + refresh_token nvarchar(255) NULL, + access_code nvarchar(255) NULL, + union_id nvarchar(255) NULL, + scope nvarchar(255) NULL, + token_type nvarchar(255) NULL, + id_token nvarchar(255) NULL, + mac_algorithm nvarchar(255) NULL, + mac_key nvarchar(255) NULL, + code nvarchar(255) NULL, + oauth_token nvarchar(255) NULL, + oauth_token_secret nvarchar(255) NULL, + create_dept bigint, + create_by bigint, + create_time datetime2(7), + update_by bigint, + update_time datetime2(7), + del_flag nchar DEFAULT ('0') NULL, + CONSTRAINT PK__sys_social__B21E8F2427725F8A PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户ID' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'租户id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'tenant_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台+平台唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'auth_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户来源' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'source' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台编号唯一id' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'open_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'登录账号' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'user_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户昵称' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'nick_name' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户邮箱' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'email' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'头像地址' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'avatar' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权令牌的有效期,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'expire_in' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'刷新令牌,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'refresh_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'access_code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的 unionid' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'union_id' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'授予的权限,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'scope' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'个别平台的授权信息,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'token_type' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'id token,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'id_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_algorithm' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'小米平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'mac_key' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'用户的授权code,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'code' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'Twitter平台用户的附带属性,部分平台可能没有' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'oauth_token_secret' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'删除标志(0代表存在 2代表删除)' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建部门' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_dept' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'创建时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'create_time' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新者' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_by' +GO +EXEC sys.sp_addextendedproperty + 'MS_Description', N'更新时间' , + 'SCHEMA', N'dbo', + 'TABLE', N'sys_social', + 'COLUMN', N'update_time' +GO + + +CREATE TABLE sys_client +( + id bigint NOT NULL, + client_id nvarchar(64) DEFAULT '' NULL, + client_key nvarchar(32) DEFAULT '' NULL, + client_secret nvarchar(255) DEFAULT '' NULL, + grant_type nvarchar(255) DEFAULT '' NULL, + device_type nvarchar(32) DEFAULT '' NULL, + active_timeout int DEFAULT ((1800)) NULL, + timeout int DEFAULT ((604800)) NULL, + status nchar(1) DEFAULT ('0') NULL, + del_flag nchar(1) DEFAULT ('0') NULL, + create_dept bigint NULL, + create_by bigint NULL, + create_time datetime2(7) NULL, + update_by bigint NULL, + update_time datetime2(7) NULL + CONSTRAINT PK__sys_client___BFBDE87009ED2882 PRIMARY KEY CLUSTERED (id) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) + ON [PRIMARY] +) +ON [PRIMARY] +GO + +EXEC sp_addextendedproperty +'MS_Description', N'主键', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'id' +GO +EXEC sys.sp_addextendedproperty +'MS_Description', N'客户端id' , +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'client_id' +GO +EXEC sp_addextendedproperty +'MS_Description', N'客户端key', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'client_key' +GO +EXEC sp_addextendedproperty +'MS_Description', N'客户端秘钥', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'client_secret' +GO +EXEC sp_addextendedproperty +'MS_Description', N'授权类型', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'grant_type' +GO +EXEC sp_addextendedproperty +'MS_Description', N'设备类型', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'device_type' +GO +EXEC sp_addextendedproperty +'MS_Description', N'token活跃超时时间', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'active_timeout' +GO +EXEC sp_addextendedproperty +'MS_Description', N'token固定超时', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'timeout' +GO +EXEC sp_addextendedproperty +'MS_Description', N'状态(0正常 1停用)', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'status' +GO +EXEC sp_addextendedproperty +'MS_Description', N'删除标志(0代表存在 2代表删除)', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'del_flag' +GO +EXEC sys.sp_addextendedproperty +'MS_Description', N'创建部门' , +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'create_dept' +GO +EXEC sp_addextendedproperty +'MS_Description', N'创建者', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'create_by' +GO +EXEC sp_addextendedproperty +'MS_Description', N'创建时间', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'create_time' +GO +EXEC sp_addextendedproperty +'MS_Description', N'更新者', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'update_by' +GO +EXEC sp_addextendedproperty +'MS_Description', N'更新时间', +'SCHEMA', N'dbo', +'TABLE', N'sys_client', +'COLUMN', N'update_time' +GO +EXEC sp_addextendedproperty +'MS_Description', N'系统授权表', +'SCHEMA', N'dbo', +'TABLE', N'sys_client' +GO + +INSERT INTO sys_client VALUES (N'1', N'e5cd7e4891bf95d1d19206ce24a7b32e', N'pc', N'pc123', N'password,social', N'pc', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO +INSERT INTO sys_client VALUES (N'2', N'428a8310cd442757ae699df5d894f051', N'app', N'app123', N'password,sms,social', N'android', 1800, 604800, N'0', N'0', 103, 1, getdate(), 1, getdate()) +GO + +INSERT sys_dict_type VALUES (11, N'000000', N'授权类型', N'sys_grant_type', N'0', 103, 1, getdate(), NULL, NULL, N'认证授权类型') +GO +INSERT sys_dict_type VALUES (12, N'000000', N'设备类型', N'sys_device_type', N'0', 103, 1, getdate(), NULL, NULL, N'客户端设备类型') +GO + +INSERT sys_dict_data VALUES (30, N'000000', 0, N'密码认证', N'password', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'密码认证'); +GO +INSERT sys_dict_data VALUES (31, N'000000', 0, N'短信认证', N'sms', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'短信认证') +GO +INSERT sys_dict_data VALUES (32, N'000000', 0, N'邮件认证', N'email', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'邮件认证') +GO +INSERT sys_dict_data VALUES (33, N'000000', 0, N'小程序认证', N'xcx', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'小程序认证') +GO +INSERT sys_dict_data VALUES (34, N'000000', 0, N'三方登录认证', N'`social`', N'sys_grant_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'三方登录认证') +GO +INSERT sys_dict_data VALUES (35, N'000000', 0, N'PC', N'`pc`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'PC') +GO +INSERT sys_dict_data VALUES (36, N'000000', 0, N'安卓', N'`android`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'安卓') +GO +INSERT sys_dict_data VALUES (37, N'000000', 0, N'iOS', N'`ios`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'iOS') +GO +INSERT sys_dict_data VALUES (38, N'000000', 0, N'小程序', N'`xcx`', N'sys_device_type', N'', N'default', N'N', N'0', 103, 1, getdate(), NULL, NULL, N'小程序') +GO + +-- 二级菜单 +INSERT sys_menu VALUES (123, N'客户端管理', 1, 11, N'client', N'system/client/index', N'', 1, 0, N'C', N'0', N'0', N'system:client:list', N'international', 103, 1, getdate(), NULL, NULL, N'客户端管理菜单') +GO +-- 客户端管理按钮 +INSERT sys_menu VALUES (1061, N'客户端管理查询', 123, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:query', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1062, N'客户端管理新增', 123, 2, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1063, N'客户端管理修改', 123, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1064, N'客户端管理删除', 123, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1065, N'客户端管理导出', 123, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:client:export', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO + + +-- 角色菜单权限 +INSERT sys_role_menu VALUES (2, 1061) +GO +INSERT sys_role_menu VALUES (2, 1062) +GO +INSERT sys_role_menu VALUES (2, 1063) +GO +INSERT sys_role_menu VALUES (2, 1064) +GO +INSERT sys_role_menu VALUES (2, 1065) +GO + + +UPDATE sys_dept SET leader = null +GO +ALTER TABLE sys_dept ALTER COLUMN leader bigint NULL +GO diff --git a/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql b/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..9133772 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.1.1-5.1.2.sql @@ -0,0 +1,10 @@ +DELETE FROM sys_menu WHERE menu_id IN (1604, 1605); +GO +INSERT sys_menu VALUES (1620, N'配置列表', 118, 5, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:list', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1621, N'配置添加', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:add', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1622, N'配置编辑', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:edit', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO +INSERT sys_menu VALUES (1623, N'配置删除', 118, 6, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'system:ossConfig:remove', N'#', 103, 1, getdate(), NULL, NULL, N''); +GO diff --git a/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql b/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..18daca4 --- /dev/null +++ b/script/sql/update/sqlserver/update_5.1.2-5.2.0.sql @@ -0,0 +1,29 @@ +ALTER TABLE sys_dept ADD dept_category nvarchar(100) DEFAULT NULL +EXEC sp_addextendedproperty + 'MS_Description', N'部门类别编码', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_dept', + 'COLUMN', N'dept_category' +GO +ALTER TABLE sys_post ADD dept_id bigint NOT NULL +GO +ALTER TABLE sys_post ADD post_category nvarchar(100) DEFAULT NULL +GO +EXEC sp_addextendedproperty + 'MS_Description', N'部门id', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'dept_id' +GO +EXEC sp_addextendedproperty + 'MS_Description', N'岗位类别编码', + 'SCHEMA', N'dbo', + 'TABLE', N'sys_post', + 'COLUMN', N'post_category' +GO +UPDATE sys_post SET dept_id = 100 +GO +UPDATE sys_post SET dept_id = 103 where post_id = 1 +GO +UPDATE sys_menu SET menu_name = N'SnailJob控制台', path = N'snailjob', component = N'monitor/snailjob/index', perms = N'monitor:snailjob:list', remark = N'SnailJob控制台菜单' WHERE menu_id = 120 +GO diff --git a/script/sql/update/update_5.0-5.1.sql b/script/sql/update/update_5.0-5.1.sql new file mode 100644 index 0000000..871bda3 --- /dev/null +++ b/script/sql/update/update_5.0-5.1.sql @@ -0,0 +1,101 @@ +ALTER TABLE gen_table ADD COLUMN data_name varchar(200) NULL DEFAULT '' COMMENT '数据源名称' AFTER table_id; + +UPDATE sys_menu SET path = 'powerjob', component = 'monitor/powerjob/index', perms = 'monitor:powerjob:list', remark = 'powerjob控制台菜单' WHERE menu_id = 120; + +-- ---------------------------- +-- 第三方平台授权表 +-- ---------------------------- +drop table if exists sys_social; +create table sys_social +( + id bigint not null comment '主键', + user_id bigint not null comment '用户ID', + tenant_id varchar(20) default null comment '租户id', + auth_id varchar(255) not null comment '平台+平台唯一id', + source varchar(255) not null comment '用户来源', + open_id varchar(255) default null comment '平台编号唯一id', + user_name varchar(30) not null comment '登录账号', + nick_name varchar(30) default '' comment '用户昵称', + email varchar(255) default '' comment '用户邮箱', + avatar varchar(500) default '' comment '头像地址', + access_token varchar(255) not null comment '用户的授权令牌', + expire_in int default null comment '用户的授权令牌的有效期,部分平台可能没有', + refresh_token varchar(255) default null comment '刷新令牌,部分平台可能没有', + access_code varchar(255) default null comment '平台的授权信息,部分平台可能没有', + union_id varchar(255) default null comment '用户的 unionid', + scope varchar(255) default null comment '授予的权限,部分平台可能没有', + token_type varchar(255) default null comment '个别平台的授权信息,部分平台可能没有', + id_token varchar(255) default null comment 'id token,部分平台可能没有', + mac_algorithm varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + mac_key varchar(255) default null comment '小米平台用户的附带属性,部分平台可能没有', + code varchar(255) default null comment '用户的授权code,部分平台可能没有', + oauth_token varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + oauth_token_secret varchar(255) default null comment 'Twitter平台用户的附带属性,部分平台可能没有', + create_dept bigint(20) comment '创建部门', + create_by bigint(20) comment '创建者', + create_time datetime comment '创建时间', + update_by bigint(20) comment '更新者', + update_time datetime comment '更新时间', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + PRIMARY KEY (id) +) engine=innodb comment = '社会化关系表'; + + +-- ---------------------------- +-- 系统授权表 +-- ---------------------------- +drop table if exists sys_client; +create table sys_client ( + id bigint(20) not null comment 'id', + client_id varchar(64) default null comment '客户端id', + client_key varchar(32) default null comment '客户端key', + client_secret varchar(255) default null comment '客户端秘钥', + grant_type varchar(255) default null comment '授权类型', + device_type varchar(32) default null comment '设备类型', + active_timeout int(11) default 1800 comment 'token活跃超时时间', + timeout int(11) default 604800 comment 'token固定超时', + status char(1) default '0' comment '状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_dept bigint(20) default null comment '创建部门', + create_by bigint(20) default null comment '创建者', + create_time datetime default null comment '创建时间', + update_by bigint(20) default null comment '更新者', + update_time datetime default null comment '更新时间', + primary key (id) +) engine=innodb comment='系统授权表'; + +insert into sys_client values (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); +insert into sys_client values (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, 0, 0, 103, 1, sysdate(), 1, sysdate()); + +insert into sys_dict_type values(11, '000000', '授权类型', 'sys_grant_type', 103, 1, sysdate(), null, null, '认证授权类型'); +insert into sys_dict_type values(12, '000000', '设备类型', 'sys_device_type', 103, 1, sysdate(), null, null, '客户端设备类型'); + +insert into sys_dict_data values(30, '000000', 0, '密码认证', 'password', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '密码认证'); +insert into sys_dict_data values(31, '000000', 0, '短信认证', 'sms', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '短信认证'); +insert into sys_dict_data values(32, '000000', 0, '邮件认证', 'email', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '邮件认证'); +insert into sys_dict_data values(33, '000000', 0, '小程序认证', 'xcx', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '小程序认证'); +insert into sys_dict_data values(34, '000000', 0, '三方登录认证', 'social', 'sys_grant_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '三方登录认证'); +insert into sys_dict_data values(35, '000000', 0, 'PC', 'pc', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'PC'); +insert into sys_dict_data values(36, '000000', 0, '安卓', 'android', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '安卓'); +insert into sys_dict_data values(37, '000000', 0, 'iOS', 'ios', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, 'iOS'); +insert into sys_dict_data values(38, '000000', 0, '小程序', 'xcx', 'sys_device_type', '', 'default', 'N', 103, 1, sysdate(), null, null, '小程序'); + +-- 二级菜单 +insert into sys_menu values('123', '客户端管理', '1', '11', 'client', 'system/client/index', '', 1, 0, 'C', '0', '0', 'system:client:list', 'international', 103, 1, sysdate(), null, null, '客户端管理菜单'); +-- 客户端管理按钮 +insert into sys_menu values('1061', '客户端管理查询', '123', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:query', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1062', '客户端管理新增', '123', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:add', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1063', '客户端管理修改', '123', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:edit', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1064', '客户端管理删除', '123', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:remove', '#', 103, 1, sysdate(), null, null, ''); +insert into sys_menu values('1065', '客户端管理导出', '123', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:client:export', '#', 103, 1, sysdate(), null, null, ''); + +-- 角色菜单权限 +insert into sys_role_menu values ('2', '1061'); +insert into sys_role_menu values ('2', '1062'); +insert into sys_role_menu values ('2', '1063'); +insert into sys_role_menu values ('2', '1064'); +insert into sys_role_menu values ('2', '1065'); + + +update sys_dept set leader = null; +alter table sys_dept modify column leader bigint null default null comment '负责人' after order_num; diff --git a/script/sql/update/update_5.1.0-5.1.1.sql b/script/sql/update/update_5.1.0-5.1.1.sql new file mode 100644 index 0000000..1dea49b --- /dev/null +++ b/script/sql/update/update_5.1.0-5.1.1.sql @@ -0,0 +1,3 @@ +ALTER TABLE sys_logininfor + ADD COLUMN client_key VARCHAR(32) NULL DEFAULT NULL COMMENT '客户端' AFTER `user_name`, + ADD COLUMN device_type VARCHAR(32) NULL DEFAULT NULL COMMENT '设备类型' AFTER `client_key`; diff --git a/script/sql/update/update_5.1.1-5.1.2.sql b/script/sql/update/update_5.1.1-5.1.2.sql new file mode 100644 index 0000000..314743f --- /dev/null +++ b/script/sql/update/update_5.1.1-5.1.2.sql @@ -0,0 +1,5 @@ +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/update_5.1.2-5.2.0.sql b/script/sql/update/update_5.1.2-5.2.0.sql new file mode 100644 index 0000000..33384e7 --- /dev/null +++ b/script/sql/update/update_5.1.2-5.2.0.sql @@ -0,0 +1,5 @@ +ALTER TABLE sys_dept ADD dept_category VARCHAR(100) DEFAULT NULL COMMENT '部门类别编码'; +ALTER TABLE sys_post ADD dept_id BIGINT(20) NOT NULL COMMENT '部门id', ADD post_category VARCHAR(100) DEFAULT NULL COMMENT '岗位类别编码'; +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/stockSynchronize/stock_sync_log_2025-12-01.txt b/stockSynchronize/stock_sync_log_2025-12-01.txt new file mode 100644 index 0000000..c8318c0 --- /dev/null +++ b/stockSynchronize/stock_sync_log_2025-12-01.txt @@ -0,0 +1,9 @@ +=== Method Parameter Log === +Time: 2025-12-01 13:50:49 +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":1995369976939737089,"taskType":"STOCK_SYNCHRONIZE","shopIds":"1990614835765604353","shopNames":"志诚纸品店","fileName":"手动库存同步任务","dataNum":0,"taskStatus":"0"} + Parameter 3: 1916358871501082626 +============================= + diff --git a/stockSynchronize/stock_sync_log_2026-01-16.txt b/stockSynchronize/stock_sync_log_2026-01-16.txt new file mode 100644 index 0000000..d405e33 --- /dev/null +++ b/stockSynchronize/stock_sync_log_2026-01-16.txt @@ -0,0 +1,36 @@ +=== Method Parameter Log === +Time: 2026-01-16 17:22:36 +Method: stockSynchronize +Parameters: + Parameter 1: {"taskType":"STOCK_SYNCHRONIZE","priceAdjustments":[{"userId":"1916358871501082626","proportion":100,"addNum":0}],"imageSelect":"1","deleteNum":0,"shopIds":"2006241414755627010","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"} + Parameter 2: {"params":{},"id":2012093114066948098,"taskType":"STOCK_SYNCHRONIZE","shopIds":"2006241414755627010","shopNames":"品博","fileName":"excel表格更新:","dataNum":0,"taskStatus":"0"} + Parameter 3: 1916358871501082626 +============================= + +=== Method Parameter Log === +Time: 2026-01-16 17:33:44 +Method: stockSynchronize +Parameters: + Parameter 1: {"taskType":"STOCK_SYNCHRONIZE","priceAdjustments":[{"userId":"1967478719210483714","proportion":100,"addNum":0}],"imageSelect":"1","deleteNum":0,"shopIds":"1980898939631497217","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"} + Parameter 2: {"params":{},"id":2012095919288766465,"taskType":"STOCK_SYNCHRONIZE","shopIds":"1980898939631497217","shopNames":"纸墨旧时光","fileName":"excel表格更新:","dataNum":0,"taskStatus":"0"} + Parameter 3: 1967478719210483714 +============================= + +=== Method Parameter Log === +Time: 2026-01-16 17:33:44 +Method: stockSynchronize +Parameters: + Parameter 1: {"taskType":"STOCK_SYNCHRONIZE","priceAdjustments":[{"userId":"1967478719210483714","proportion":100,"addNum":0}],"imageSelect":"1","deleteNum":0,"shopIds":"1989217712390176769","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"} + Parameter 2: {"params":{},"id":2012095919599144961,"taskType":"STOCK_SYNCHRONIZE","shopIds":"1989217712390176769","shopNames":"旧墨书香阁","fileName":"excel表格更新:","dataNum":0,"taskStatus":"0"} + Parameter 3: 1967478719210483714 +============================= + +=== Method Parameter Log === +Time: 2026-01-16 17:33:45 +Method: stockSynchronize +Parameters: + Parameter 1: {"taskType":"STOCK_SYNCHRONIZE","priceAdjustments":[{"userId":"1967478719210483714","proportion":100,"addNum":0}],"imageSelect":"1","deleteNum":0,"shopIds":"2010715847876579329","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"} + Parameter 2: {"params":{},"id":2012095920010186754,"taskType":"STOCK_SYNCHRONIZE","shopIds":"2010715847876579329","shopNames":"直供书局的书店","fileName":"excel表格更新:","dataNum":0,"taskStatus":"0"} + Parameter 3: 1967478719210483714 +============================= + diff --git a/stockSynchronize/stock_sync_log_2026-05-01.txt b/stockSynchronize/stock_sync_log_2026-05-01.txt new file mode 100644 index 0000000..3a55a96 --- /dev/null +++ b/stockSynchronize/stock_sync_log_2026-05-01.txt @@ -0,0 +1,9 @@ +=== Method Parameter Log === +Time: 2026-05-01 14:26:08 +Method: stockSynchronize +Parameters: + Parameter 1: {"taskType":"STOCK_SYNCHRONIZE","priceAdjustments":[{"userId":"2017934641338511361","proportion":100,"addNum":0}],"imageSelect":"1","deleteNum":0,"shopIds":"2031567694568841217","listStatus":"0","synchronizationType":"1","bookCategory":"0","way":"0"} + Parameter 2: {"params":{},"id":2050099427111608321,"taskType":"STOCK_SYNCHRONIZE","shopIds":"2031567694568841217","shopNames":"双枚艳图书专营店","fileName":"excel表格更新:","dataNum":0,"taskStatus":"0"} + Parameter 3: 2017934641338511361 +============================= +